module Wordify.Rules.Game.Internal (updateGame, Game(Game),
     GameStatus(InProgress, Finished),
      moveNumber,
      playerNumber,
      currentPlayer,
      passes,
      nextPlayer,
      player1,
      player2,
      optionalPlayers,
      gameStatus,
      board,
      bag,
      pass,
      dictionary,
      updateHistory,
      Move(PlaceTiles, Exchange, Pass),
      History(History),
      history) where

  import Wordify.Rules.Player
  import Wordify.Rules.Board
  import Wordify.Rules.LetterBag
  import Wordify.Rules.Dictionary
  import Control.Applicative
  import Data.Map
  import Wordify.Rules.Pos
  import Wordify.Rules.Tile
  import Data.Sequence

  data Move = PlaceTiles (Map Pos Tile) | Exchange [Tile] | Pass deriving (Eq, Show)

  data History = History LetterBag (Seq Move) deriving (Eq, Show)

  data GameStatus = InProgress | Finished deriving (Eq, Show)

  data Game = Game { player1 :: Player
                     , player2 :: Player
                     , optionalPlayers :: Maybe (Player, Maybe Player)
                     , board :: Board
                     , bag :: LetterBag
                     , dictionary :: Dictionary 
                     , currentPlayer :: Player
                     , playerNumber :: Int
                     , moveNumber :: Int
                     , passes :: Int
                     , gameStatus :: GameStatus
                     , history :: History }

  {-
    Updates the game with the new board and letter bag state, and the last player to play's state after replacing their played
    tiles with new tiles from the letter bag. 

    Yields the next game state.
  -}
  updateGame :: Game -> Player -> Board -> LetterBag -> Game
  updateGame game player newBoard newBag = 
   updatedPlayerGame {board = newBoard, bag = newBag, currentPlayer = newPlayer, playerNumber = newPlayerNum, moveNumber = succ moveNo, passes = 0}
    where
      updatedPlayerGame = updateCurrentPlayer game player
      (newPlayerNum, newPlayer) = nextPlayer game
      moveNo = moveNumber game

  updateCurrentPlayer :: Game -> Player -> Game
  updateCurrentPlayer game player =
    case playing of
      1 -> game {player1 = player}
      2 -> game {player2 = player}
      3 -> game {optionalPlayers = (\(_, player4) -> (player, player4)) <$> maybePlayers }
      _ -> game {optionalPlayers = (\(player3, _) -> (player3, (Just player))) <$> maybePlayers  }

    where
      playing = playerNumber game
      maybePlayers = optionalPlayers game

  {- Returns the next player to play. If there are optional players, loops back round to 'player 1' where appropriate. -}
  nextPlayer :: Game -> (Int, Player)
  nextPlayer game 
    | (playing == 1) = (2, playr2)
    | (playing == 2 || playing == 3) =
     maybe ( (1, playr1) ) (\(player3, player4) -> 
      if (playing == 2) then (3, player3 )
      else 
        case player4 of
          Just playr4 -> (4, playr4)
          Nothing -> (1, playr1)
        ) $ maybePlayers
    | otherwise = (1, playr1)

    where
      playing = playerNumber game
      playr2 = player2 game
      playr1 = player1 game
      maybePlayers = optionalPlayers game


  pass :: Game -> Game
  pass game =  game {moveNumber = succ moveNo, playerNumber = playerNo, currentPlayer = player, passes = succ numPasses}
    where
      (playerNo, player) = nextPlayer game
      numPasses = passes game
      moveNo = moveNumber game

  updateHistory :: Game -> Move -> Game
  updateHistory game move = game {history = History originalBag (moveList |> move) }
    where
      History originalBag moveList = history game