Nomyx-0.1.0: src/Web/Game.hs
{-# LANGUAGE GADTs, OverloadedStrings, ExtendedDefaultRules#-}
module Web.Game where
import Prelude hiding (div)
import Text.Blaze.Html5 hiding (map)
import qualified Text.Blaze.Html5.Attributes as A
import Web.Routes.RouteT
import Text.Blaze.Internal
import Game
import Control.Monad
import Control.Monad.State
import Data.Monoid
import Control.Concurrent.STM
import Language.Nomyx.Expression
import Language.Nomyx.Evaluation
import Data.Maybe
import Text.Reform.Happstack
import Text.Reform
import Happstack.Server
import Data.List
import qualified Web.Help as Help
import Web.Common
import Types
import Web.Routes.Happstack()
import qualified Text.Reform.Blaze.String as RB hiding (form)
import Control.Applicative
import Utils
import Mail
import Data.Text(Text)
import qualified Text.Reform.Blaze.Common as RBC
default (Integer, Double, Data.Text.Text)
viewGame :: Game -> PlayerNumber -> (Maybe SubmitRule) -> RoutedNomyxServer Html
viewGame g pn sr = do
rf <- viewRuleForm pn sr
vi <- viewInputs pn $ events g
ok $ table $ do
td ! A.id "gameCol" $ do
table $ do
tr $ td $ h3 $ string $ "Viewing game: " ++ gameName g
tr $ td $ (string $ "Description: " ++ gameDesc g ++ "\n\n") >> br >> br
tr $ td $ viewPlayers $ players g
tr $ td $ viewVictory g
td ! A.id "gameElem" $ do
table $ do
tr $ td $ div ! A.id "rules" $ viewAllRules g
tr $ td $ div ! A.id "inputs" ! A.title (toValue Help.inputs) $ vi
tr $ td $ div ! A.id "events" ! A.title (toValue Help.events) $ viewEvents $ events g
tr $ td $ div ! A.id "variables" ! A.title (toValue Help.variables)$ viewVars $ variables g
tr $ td $ div ! A.id "newRule" $ rf
tr $ td $ div ! A.id "outputs" ! A.title (toValue Help.outputs)$ viewOutput (outputs g) pn
viewPlayers :: [PlayerInfo] -> Html
viewPlayers pis = do
h5 "Players in game:"
table $ mapM_ viewPlayer (sort pis)
viewPlayer :: PlayerInfo -> Html
viewPlayer pi = tr $ do
td $ string $ show $ playerNumber pi
td $ string $ playerName pi
viewVictory :: Game -> Html
viewVictory g = do
let vs = mapMaybe (getPlayersNameMay g) (victory g)
case vs of
[] -> br
a:[] -> h3 $ string $ "Player " ++ (show a) ++ " won the game!"
a:bs -> h3 $ string $ "Players " ++ (concat $ intersperse ", " $ bs) ++ " and " ++ a ++ " won the game!"
viewAllRules :: Game -> Html
viewAllRules g = do
h3 "Rules"
viewRules "Active rules:" (activeRules g) ! (A.title $ toValue Help.actives)
viewRules "Pending rules:" (pendingRules g) ! (A.title $ toValue Help.pendings)
viewRules "Suppressed rules:" $ rejectedRules g
viewRules :: Html -> [Rule] -> Html
viewRules _ [] = return ()
viewRules title nrs = do
table ! A.class_ "table" $ do
caption $ h4 title
thead $ do
td ! A.class_ "td" $ text "Number"
td ! A.class_ "td" $ text "Name"
td ! A.class_ "td" $ text "Description"
td ! A.class_ "td" $ text "Proposed by"
td ! A.class_ "td" $ text "Code of the rule"
td ! A.class_ "td" $ text "Assessed by"
forM_ nrs viewRule
viewRule :: Rule -> Html
viewRule nr = tr $ do
td ! A.class_ "td" $ string . show $ rNumber nr
td ! A.class_ "td" $ string $ rName nr
td ! A.class_ "td" $ string $ rDescription nr
td ! A.class_ "td" $ string $ if rProposedBy nr == 0 then "System" else "Player " ++ (show $ rProposedBy nr)
td ! A.class_ "td" $ string $ rRuleCode nr
td ! A.class_ "td" $ string $ case rAssessedBy nr of
Nothing -> "Not assessed"
Just 0 -> "System"
Just a -> "Rule " ++ (show $ a)
viewEvents :: [EventHandler] -> Html
viewEvents [] = h3 "Events" >> h5 "No Events"
viewEvents ehs = do
h3 "Events"
table ! A.class_ "table" $ do
thead $ do
td ! A.class_ "td" $ text "Event Number"
td ! A.class_ "td" $ text "By Rule"
td ! A.class_ "td" $ text "Event"
mapM_ viewEvent $ sort ehs
viewEvent :: EventHandler -> Html
viewEvent (EH eventNumber ruleNumber event _) = tr $ do
td ! A.class_ "td" $ string . show $ eventNumber
td ! A.class_ "td" $ string . show $ ruleNumber
td ! A.class_ "td" $ string . show $ event
viewInputs :: PlayerNumber -> [EventHandler] -> RoutedNomyxServer Html
viewInputs pn ehs = do
mis <- mapM (viewInput pn) $ sort ehs
let is = catMaybes mis
case length is of
0 -> ok $ h3 "Inputs" >> h5 "No Inputs"
_ -> ok $ do
h3 "Inputs"
table $ do
mconcat is
viewInput :: PlayerNumber -> EventHandler -> RoutedNomyxServer (Maybe Html)
viewInput me (EH eventNumber _ (InputChoice pn title choices def) _) | me == pn = do
link <- showURL (DoInputChoice pn eventNumber)
lf <- lift $ viewForm "user" $ inputChoiceForm title (map show choices) (show def)
return $ Just $ tr $ td $ blazeForm lf (link)
viewInput me (EH _ _ (InputString pn title) _) | me == pn = do
link <- showURL (DoInputString pn title)
lf <- lift $ viewForm "user" $ inputStringForm title
return $ Just $ tr $ td $ blazeForm lf (link)
viewInput _ _ = return Nothing
viewVars :: [Var] -> Html
viewVars [] = h3 "Variables" >> h5 "No Variables"
viewVars vs = do
h3 "Variables"
table ! A.class_ "table" $ do
thead $ do
td ! A.class_ "td" $ text "Rule number"
td ! A.class_ "td" $ text "Name"
td ! A.class_ "td" $ text "Value"
mapM_ viewVar vs
viewVar :: Var -> Html
viewVar (Var vRuleNumber vName vData) = tr $ do
td ! A.class_ "td" $ string . show $ vRuleNumber
td ! A.class_ "td" $ string . show $ vName
td ! A.class_ "td" $ string . show $ vData
newRuleForm :: (Maybe SubmitRule) -> NomyxForm SubmitRule
newRuleForm (Just sr) = newRuleForm' sr
newRuleForm Nothing = newRuleForm' (SubmitRule "" "" "")
newRuleForm' :: SubmitRule -> NomyxForm SubmitRule
newRuleForm' (SubmitRule name desc code) = pure SubmitRule <*> RB.label "Name: " ++> (RB.inputText name)
<*> RB.label " Short description: " ++> RB.inputText desc
<*> RB.label " Code: " ++> RB.textarea 80 15 code
`RBC.setAttr` A.class_ "code" `RBC.setAttr` A.placeholder "Enter here your rule" `RBC.setAttr` (A.title (toValue Help.code))
viewRuleForm :: PlayerNumber -> (Maybe SubmitRule) -> RoutedNomyxServer Html
viewRuleForm pn sr = do
link <- showURL (NewRule pn)
lf <- lift $ viewForm "user" $ newRuleForm sr
ok $ do
h3 "Propose a new rule:"
blazeForm lf (link)
newRule :: PlayerNumber -> (TVar Multi) -> RoutedNomyxServer Html
newRule pn tm = do
methodM POST
m <- liftRouteT $ lift $ readTVarIO tm
r <- liftRouteT $ eitherForm environment "user" (newRuleForm Nothing)
link <- showURL $ Noop pn
case r of
Right sr -> do
--t <- liftRouteT $ lift $ getCurrentTime
--liftRouteT $ lift $ putStrLn $ "before: " ++ (show m) ++"\n" ++ (show t) ++"\n"
--t' <- liftRouteT $ lift $ getCurrentTime
--liftRouteT $ lift $ putStrLn $ "after: " ++ (show m) ++"\n" ++ (show t') ++"\n"
webCommand tm pn $ MultiSubmitRule sr pn
m' <- liftRouteT $ lift $ readTVarIO tm
let rs = rules $ fromJust $ getPlayersGame pn m
let rs' = rules $ fromJust $ getPlayersGame pn m'
when (length rs' > length rs) $ liftRouteT $ lift $ sendMailsNewRule m' sr pn
(Left _) -> liftRouteT $ lift $ putStrLn $ "cannot retrieve form data"
seeOther link $ string "Redirecting..."
viewOutput :: [Output] -> PlayerNumber -> Html
viewOutput [] _ = h3 "Output" >> h5 "No Output"
viewOutput os pn = do
h3 "Output"
let myos = map snd $ filter (\o -> fst o == pn) os
mapM_ viewMessages [myos]
viewMessages :: [String] -> Html
viewMessages = mapM_ (\s -> string s >> br)
newInputChoice :: PlayerNumber -> EventNumber -> (TVar Multi) -> RoutedNomyxServer Html
newInputChoice pn en tm = do
multi <- liftRouteT $ lift $ atomically $ readTVar tm
let mg = fromJust $ getPlayersGame pn multi
let eventHandler = fromJust $ findEvent en (events mg)
methodM POST
let (title, choices, def) = getChoices eventHandler
r <- liftRouteT $ eitherForm environment "user" (inputChoiceForm title choices def)
link <- showURL $ Noop pn
case r of
(Right c) -> do
liftRouteT $ lift $ putStrLn $ "choice:" ++ (show c)
webCommand tm pn $ MultiInputChoiceResult en c pn
seeOther link $ string "Redirecting..."
(Left _) -> do
liftRouteT $ lift $ putStrLn $ "cannot retrieve form data"
seeOther link $ string "Redirecting..."
getChoices :: EventHandler -> (String, [String], String)
getChoices (EH _ _ (InputChoice _ title choices def) _) = (title, map show choices, show def)
getChoices _ = error "InputChoice event expected"
newInputString :: PlayerNumber -> String -> (TVar Multi) -> RoutedNomyxServer Html
newInputString pn title tm = do
methodM POST
r <- liftRouteT $ eitherForm environment "user" (inputStringForm title)
link <- showURL $ Noop pn
case r of
(Right c) -> do
liftRouteT $ lift $ putStrLn $ "entered:" ++ (show c)
webCommand tm pn $ MultiInputStringResult title c pn
seeOther link $ string "Redirecting..."
(Left _) -> do
liftRouteT $ lift $ putStrLn $ "cannot retrieve form data"
seeOther link $ string "Redirecting..."
inputChoiceForm :: String -> [String] -> String -> NomyxForm Int
inputChoiceForm title choices def = RB.label (title ++ " ") ++> inputRadio' (zip [0..] choices) ((==) $ fromJust $ elemIndex def choices)
inputStringForm :: String -> NomyxForm String
inputStringForm title = RB.label (title ++ " ") ++> RB.inputText ""