module Tak.Tree (
    GameBranch(..),
    GameNode(..),
    Eval,
    gameTree,
    treeGameState
) where

import Control.Monad.ST

import Tak.ApplyPlay
import Tak.PossiblePlays
import Tak.Types

data GameBranch a = GameBranch Play (GameNode a)
data GameNode a = GameNode GameState a [GameBranch a]

type Eval a = GameState -> a

--hashtableSize :: Integer
--hashtableSize = 10 * 1024 * 1024

gameTree :: GameState -> Eval a -> GameNode a
gameTree gameState eval = runST $ do
    --refAge <- newSTRef 0
    --hashtable <- H.newSized (fromIntegral hashtableSize)
    return $ gameTreeST gameState eval

gameTreeST
    :: GameState
    -> Eval a
    -> (GameNode a)
gameTreeST gameState eval =
    GameNode gameState (eval gameState) branches where
        branches = map branch plays
        branch p =
            let newGameState = noErr $ play p gameState in
            GameBranch p (gameTreeST newGameState eval)
            {-unsafePerformST $ do
                mBranch <- H.lookup table newGameState
                age <- readSTRef refAge
                case mBranch of
                    Nothing -> do
                        let node = gameTreeST newGameState eval refAge table
                            branch = GameBranch p node
                        H.insert table newGameState (age, branch)
                        writeSTRef refAge (age + 1)
                        if (age `mod` 100000 == 0)
                            then (flip H.mapM_) table $ \ (k, (age', v)) -> do
                                if (age' < age - hashtableSize)
                                    then H.delete table k
                                    else return ()
                            else return ()
                        return branch
                    Just (age', branch) -> do
                        H.insert table newGameState (age, branch)
                        return branch-}
        noErr (Left state) = state
        noErr (Right err) = error $ "Error creating game tree: " ++ show err
        plays = possiblePlays gameState

treeGameState :: GameNode a -> GameState
treeGameState (GameNode state _ _) = state