{-# LANGUAGE RankNTypes #-} import Log import Driver.Log import Event import Transition.Managed import GTK import Control.Concurrent import Control.Monad.Fix import System.FilePath ((), takeDirectory) import System.Directory import System.Environment import Random () import qualified Data.ByteString.Lazy as B import Data.ChangeMap import qualified Data.Map as MM import Data.ChangeSet import Core.Square import Preferences import State (ScoreEntry) import Step import Random import Data.Data import Data.Binary import Data.Binary.Get import Data.Binary.Put import Data.Binary.Generic import Data.Binary.Generic.Extensions -------------------------------------- main :: IO () main = getArgs >>= mainWithArgs mainWithArgs :: [String] -> IO () mainWithArgs args = do -- init logging logState <- case args of ["-"] -> return stdOutLog [fn] -> fileLog fn _ -> return noLog -- find preferences file dir <- getAppUserDataDirectory "minesweeper" let prefFile = dir "preferences" -- init program state userName <- getEnv "USER" seed <- newRandomSeed b <- doesFileExist prefFile st <- if b then fmap (runGet myGet) $ B.readFile prefFile else return $ initState userName seed -- init driver state dst <- initDriverState st -- init GUI state gui <- mfix $ \gui -> guiState (handleEvent logState gui dst) (writeState prefFile dst) -- wake up the program let initActions = [Init] mapM_ (forkIO . handleEvent logState gui dst) initActions -- start GUI startGUI gui handleEvent :: LogState -> GUIState -> DriverState State Event -> Event -> IO () handleEvent logState gui dst e = applyTransition logState dst (handleResponses gui) transition e writeState :: FilePath -> DriverState State a -> IO () writeState prefFile dst = do st <- takeState dst createDirectoryIfMissing True $ takeDirectory prefFile B.writeFile prefFile $ runPut $ myPut $ stopState st -- encodeFile prefFile $ stopState st --------------------------- myPut :: Data a => a -> Put myPut = putExtDef (putGenericByCallback myPut) myGet :: Data a => Get a myGet = getExtDef (getGenericByCallback myGet) getExtDef :: Typeable a => Get a -> Get a getExtDef = extGet (get :: Get (MM.Map Preferences [ScoreEntry])) . extGet (get :: Get (Set Square)) . extGet (get :: Get (Map Square (Maybe Int))) . extGet (get :: Get (Map Square Int)) . extGet (get :: Get (RandomSeed)) . extGet (get :: Get (SquareConstraints)) . getExtDefault putExtDef :: Typeable a => (a -> Put) -> a -> Put putExtDef = extPut (put :: MM.Map Preferences [ScoreEntry] -> Put) . extPut (put :: Set Square -> Put) . extPut (put :: Map Square (Maybe Int) -> Put) . extPut (put :: Map Square Int -> Put) . extPut (put :: RandomSeed -> Put) . extPut (put :: SquareConstraints -> Put) . putExtDefault