module ChessDefinitions
where

import Control.Monad
import Data.Char

data Square = A1 | B1 | C1 | D1 | E1 | F1 | G1 | H1 |
              A2 | B2 | C2 | D2 | E2 | F2 | G2 | H2 |
              A3 | B3 | C3 | D3 | E3 | F3 | G3 | H3 |
              A4 | B4 | C4 | D4 | E4 | F4 | G4 | H4 |
              A5 | B5 | C5 | D5 | E5 | F5 | G5 | H5 |
              A6 | B6 | C6 | D6 | E6 | F6 | G6 | H6 |
              A7 | B7 | C7 | D7 | E7 | F7 | G7 | H7 |
              A8 | B8 | C8 | D8 | E8 | F8 | G8 | H8 deriving (Enum, Eq, Ord, Show)

data Color = White | Black deriving (Eq, Show)
data PieceType = Pawn | Knight | Bishop | Rook | Queen | King deriving (Eq, Show)
data Piece = Piece Color PieceType deriving (Eq, Show)
data CastleStatus = CS {
      wk :: Bool,
      wq :: Bool,
      bk :: Bool,
      bq :: Bool
    } deriving Show

data Move = Move Square Square (Maybe PieceType)

pieceType :: Piece -> PieceType
pieceType (Piece _ t) = t

instance Show Move
    where show (Move from to _) = show from ++ "-" ++ show to

rank :: Int -> Int
rank = (`div` 8)

file :: Int -> Int
file = (`mod` 8)

squareFile :: Square -> Int
squareFile = file . fromEnum

squareRank :: Square -> Int
squareRank = rank . fromEnum

within n x y = abs (x-y) <= n

go :: (Square -> Square) -> Int -> (Square -> Square)
go f n = (!! n) . iterate f

up,down,right,left :: Square -> Maybe Square
up s | (rank.fromEnum) s == 7 = Nothing
     | otherwise = Just . toEnum . (+8) . fromEnum $ s
down s | (rank.fromEnum) s == 0 = Nothing
       | otherwise = Just . toEnum . (subtract 8) . fromEnum $ s
right s | (file.fromEnum) s == 7 = Nothing
        | otherwise = Just . toEnum . (+1) . fromEnum $ s
left s | (file.fromEnum) s == 0 = Nothing
       | otherwise = Just . toEnum . (subtract 1) . fromEnum $ s

nextCursor :: Char -> Square -> Square
nextCursor ch sq = toEnum $ if (file target <= file sq') then (max 0 (sq' - 16 + n)) else target
    where n = digitToInt ch
          sq' = fromEnum sq
          target = sq' + n
       
makePiece :: Char -> Piece
makePiece c = Piece col typ
    where col = if (isUpper c) then White else Black
          typ = case (toUpper c) of
                  'P' -> Pawn
                  'N' -> Knight
                  'B' -> Bishop
                  'R' -> Rook
                  'Q' -> Queen
                  'K' -> King

color :: Maybe Piece -> Maybe Color
color = liftM (\(Piece c _) -> c)

buildMove :: Square -> Square -> Bool -> [Move]
buildMove from to isPawn | isPawn && (squareRank to == 7 || squareRank to == 0) = [Move from to (Just p) | p <- [Knight,Bishop,Rook,Queen]]
                         | otherwise = [Move from to Nothing]

switchColor :: Color -> Color
switchColor White = Black
switchColor Black = White

takeUntil :: (a -> Bool) -> [a] -> [a]
takeUntil _ [] = []
takeUntil p (x:xs) | not (p x) = x : takeUntil p xs
                   | otherwise = [x]
