module GameController where
import Game 
import Data.List (elem)

{- 

gameController.hs
by Joe Huang 

4995 Final Project

Descriptions:
The Game Controller keeps track of the current state of the game,
all the possible move a player can do, and the previous game states.
When there are any card that could be move to the foundation, it 
will be moved automatically. 

The purpose of this controller is to ensure that no invalid move 
can be applied to the game and only the given ones can be used. 

-}

data MoveStatus = Success | Fail | Win
    deriving (Show, Eq, Ord)

data GameStatus = GameStatus {curGame :: Game, curMoves :: [Move], madeMove :: [Move]}
    deriving (Eq, Ord)

instance Show GameStatus where 
    show (GameStatus game moves _) = unlines [show game,
            "All Possible Moves: " ++ show moves, " " ] --, "Previous Moves: " ++ show state] 

-- given a game number, return the initial game status
start :: Int -> GameStatus
start gameNumber =
    (checkFounMove ((GameStatus newGame newMoves []), newMoves))
    where newGame = initializeGame gameNumber
          newMoves = getAllMove newGame

-- given a game status and a move, apply the move and return the move status 
-- and the game status after the move.
makeMove :: GameStatus -> Move -> (MoveStatus, GameStatus)
makeMove (GameStatus game moves state) move =
    if (not (elem move moves)) then (Fail, (GameStatus game moves state))
    else
         if (isFinished nng) then (Win, (GameStatus nng nnm nns))
         else (Success, (GameStatus nng nnm nns))
    where newGame = applyMove game move
          (GameStatus ng nm ns) = (GameStatus newGame (getAllMove newGame) (move:state))
          (GameStatus nng nnm nns) = (checkFounMove ((GameStatus ng nm ns), nm))

-- given a game status and its moves, recurse until all possible foundation moves 
-- are applied 
checkFounMove :: (GameStatus, [Move]) -> GameStatus 
checkFounMove ((GameStatus game moves state), movesList) 
    | length movesList == 0 = (GameStatus game moves state)
    | otherwise = 
        case (head movesList) of 
            MoveCasToFoun _ _-> checkFounMove (makeFounMove (GameStatus game moves state) (head movesList))
            MoveFCToFoun _ -> checkFounMove (makeFounMove (GameStatus game moves state) (head movesList))
            _ -> checkFounMove ((GameStatus game moves state), (tail movesList))

-- given a game status, a foundation move, return the new game status 
-- and its respective moves 
makeFounMove :: GameStatus -> Move -> (GameStatus, [Move])
makeFounMove (GameStatus game moves state) move = 
    if valid == Success || valid == Win then (newGame, newMoves) 
        else error "makeFounMove: invalid move"
    where (valid, newGame) = makeMove (GameStatus game moves state) move
          (GameStatus _ newMoves _) = newGame

            