packages feed

hcheckers-0.1.0.2: src/Core/Json.hs

{-# LANGUAGE OverloadedStrings #-}
module Core.Json where

import Control.Concurrent
import Data.Aeson
import Data.Aeson.Types
import qualified Data.Text as T
import Data.Default
import qualified Data.HashMap.Strict as HM
import System.Log.Heavy

import Core.Types
import Core.Logging
import Core.Supervisor
import Formats.Types

instance ToJSON PlayerDirection where

instance ToJSON PieceKind

instance FromJSON PieceKind

instance ToJSON Side

instance FromJSON Side

instance ToJSON GameResult

instance FromJSON GameResult

instance ToJSON BoardOrientation

instance ToJSON BoardTopology

instance ToJSON Label where
  toJSON (Label col row) = toJSON (col, row)

instance FromJSON Label where
  parseJSON v = do
    (col,row) <- parseJSON v
    return $ Label col row

instance ToJSON Step where
  toJSON (Step direction capture promote) =
    object ["direction" .= direction, "capture" .= capture, "promote" .= promote]

instance ToJSON StepRep where
  toJSON (StepRep field capture promote) =
    object ["field" .= field, "capture" .= capture, "promote" .= promote]

instance ToJSON MoveRep where
  toJSON (ShortMoveRep from to) = object ["from" .= from, "to" .= to]
  toJSON (FullMoveRep from steps) =
    object ["from" .= from, "steps" .= steps]

instance FromJSON MoveRep where
  parseJSON (Object v) = ShortMoveRep
    <$> v .: "from"
    <*> v .: "to"
  parseJSON invalid = typeMismatch "MoveRep" invalid

instance ToJSON HistoryRecordRep where
  toJSON r = object ["side" .= hrrSide r, "move" .= hrrMove r]

instance ToJSON Piece where
  toJSON (Piece kind side) = object ["kind" .= kind, "side" .= side]

instance FromJSON Piece where
  parseJSON (Object v) = Piece
    <$> v .: "kind"
    <*> v .: "side"
  parseJSON invalid = typeMismatch "Piece" invalid

instance ToJSON BoardRep where
  toJSON (BoardRep list) = toJSON list

instance FromJSON BoardRep where
  parseJSON v = BoardRep <$> parseJSON v

instance ToJSON ThreadId where
  toJSON id = toJSON (show id)

-- instance FromJSON ThreadId where
--   parseJSON (String text) = return $ read $ T.unpack text
--   parseJSON invalid = typeMismatch "ThreadId" invalid

instance ToJSON Player where
  toJSON (User name) = toJSON name
  toJSON (AI ai) = toJSON (aiName ai)

instance ToJSON SomeRules where
  toJSON (SomeRules rules) = toJSON (rulesName rules)

instance ToJSON GameStatus where
  toJSON New = toJSON ("New" :: T.Text)
  toJSON Running = toJSON ("Running" :: T.Text)
  toJSON (DrawRequested side) = object ["draw_requested" .= side]
  toJSON (Ended result) = toJSON result

instance ToJSON Game where
  toJSON g =
    object ["id" .= getGameId g,
            "rules" .= gRules g,
            "status" .= gStatus g,
            "first" .= gPlayer1 g,
            "second" .= gPlayer2 g
          ]

-- instance FromJSON Player

instance FromJSON NewGameRq where
  parseJSON = withObject "NewGame" $ \v -> NewGameRq
    <$> v .: "rules"
    <*> v .:? "params" .!= Null
    <*> v .:? "board"
    <*> v .:? "fen"
    <*> v .:? "pdn"
    <*> v .:? "previous_board"

instance FromJSON AttachAiRq where
  parseJSON = withObject "AttachAi" $ \v -> AttachAiRq
    <$> v .: "ai"
    <*> v .:? "params" .!= Null

instance FromJSON PdnInfoRq where
  parseJSON = withObject "PDN" $ \v -> PdnInfoRq
    <$> v .: "rules"
    <*> v .: "text"

instance ToJSON PdnInfo where
  toJSON pdn = object [
        "title" .= pdnTitle pdn
      , "rules" .= pdnRules pdn
      , "result" .= pdnResult pdn
      , "next_move" .= pdnNextMove pdn
    ]

instance ToJSON Notify where
  toJSON (MoveNotify to from move board) =
    object ["to_side" .= to, "from_side" .= from, "move" .= move, "board" .= board]
  toJSON (UndoNotify to from board) =
    object ["to_side" .= to, "from_side" .= from, "undo" .= True, "board" .= board]
  toJSON (ResultNotify to from result) =
    object ["to_side" .= to, "from_side" .= from, "result" .= result]
  toJSON (DrawRqNotify to from) =
    object ["to_side" .= to, "from_side" .= from, "draw" .= ("requested" :: T.Text)]
  toJSON (DrawRsNotify to from accepted) =
    object ["to_side" .= to, "from_side" .= from, "draw_accepted" .= accepted]
  toJSON (LogNotify to level src text) =
    object ["to_side" .= to, "source" .= src, "level" .= level, "message" .= text]

instance ToJSON RsPayload where
  toJSON (NewGameRs id side) = object ["id" .= id, "turn" .= side]
  toJSON RegisterUserRs = object ["register_user" .= ("ok" :: T.Text)]
  toJSON AttachAiRs = object ["attach_ai" .= ("ok" :: T.Text)]
  toJSON RunGameRs = object ["run_game" .= ("ok" :: T.Text)]
  toJSON (PollRs messages) = toJSON messages
  toJSON (StateRs board status side) = object ["board" .= board, "side" .= side, "status" .= status]
  toJSON (HistoryRs records) = toJSON records
  toJSON (PdnInfoRs info) = toJSON info
  toJSON (PossibleMovesRs moves) = toJSON moves
  toJSON (MoveRs board) = toJSON board
  toJSON (UndoRs board) = toJSON board
  toJSON CapitulateRs = object ["capitulate" .= ("ok" :: T.Text)]
  toJSON DrawRqRs = object ["draw_request" .= ("pending" :: T.Text)]
  toJSON (DrawAcceptRs accepted) = object ["draw_accepted" .= accepted]
  toJSON (LobbyRs games) = toJSON games
  toJSON (NotationRs size orientation list) =
      object ["size" .= size, "orientation" .= orientation, "notation" .= list]
  toJSON (TopologyRs topology) =
      object ["topology" .= topology]
  toJSON ShutdownRs = object ["shutdown" .= ("ok" :: T.Text)]

instance ToJSON Response where
  toJSON (Response payload messages) = object ["response" .= payload, "messages" .= messages]

instance FromJSON AiConfig where
  parseJSON = withObject "AiConfig" $ \v -> AiConfig
      <$> v .:? "threads" .!= (aiThreads def)
      <*> v .:? "load" .!= (aiLoadCache def)
      <*> v .:? "store" .!= (aiStoreCache def)
      <*> v .:? "use_cache_max_depth" .!= (aiUseCacheMaxDepth def)
      <*> v .:? "use_cache_max_pieces" .!= (aiUseCacheMaxPieces def)
      <*> v .:? "use_cache_max_depth_plus" .!= (aiUseCacheMaxDepthPlus def)
      <*> v .:? "use_cache_max_depth_minus" .!= (aiUseCacheMaxDepthMinus def)
      <*> v .:? "update_cache_max_depth" .!= (aiUpdateCacheMaxDepth def)
      <*> v .:? "update_cache_max_pieces" .!= (aiUpdateCacheMaxPieces def)

instance FromJSON BattleServerConfig where
  parseJSON = withObject "BattleServerConfig" $ \v -> BattleServerConfig
    <$> v .:? "enable" .!= bsEnable def
    <*> v .:? "host" .!= bsHost def
    <*> v .:? "port" .!= bsPort def

instance FromJSON GeneralConfig where
  parseJSON = withObject "GeneralConfig" $ \v -> GeneralConfig
    <$> v .:? "host" .!= (gcHost def)
    <*> v .:? "port" .!= (gcPort def)
    <*> v .:? "local" .!= (gcLocal def)
    <*> v .:? "enable_metrics" .!= (gcEnableMetrics def)
    <*> v .:? "metrics_port" .!= (gcMetricsPort def)
    <*> v .:? "log_path" .!= (gcLogFile def)
    <*> v .:? "log_level" .!= (gcLogLevel def)
    <*> v .:? "ai" .!= (gcAiConfig def)
    <*> v .:? "battle_server" .!= (gcBattleServerConfig def)

instance FromJSON Level where
  parseJSON (String "debug") = return debug_level
  parseJSON (String "verbose") = return verbose_level
  parseJSON (String "trace") = return trace_level
  parseJSON (String "info") = return info_level
  parseJSON (String "warning") = return warn_level
  parseJSON (String "error") = return error_level
  parseJSON (String "fatal") = return fatal_level
  parseJSON (String "disable") = return disable_logging
  parseJSON invalid = typeMismatch "logging level" invalid

mergeObjects :: Value -> Value -> Value
mergeObjects (Object v1) (Object v2) = Object (HM.union v1 v2)
mergeObjects _ _ = error "not object value"