Nomyx-Web-0.7.3: src/Nomyx/Web/Game/IOs.hs
{-# LANGUAGE DoAndIfThenElse #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ExtendedDefaultRules #-}
{-# LANGUAGE GADTs #-}
module Nomyx.Web.Game.IOs where
import Prelude hiding (div)
import Control.Monad
import Control.Monad.State
import Control.Concurrent.STM
import Control.Applicative
import Data.Monoid
import Data.Maybe
import Data.String
import Data.List
import Data.Text (Text)
import Language.Nomyx
import Text.Blaze.Html5 (Html, div, (!), table, td, tr, h3, h4, pre, toValue, br, a)
import Text.Blaze.Html5.Attributes as A (id)
import Text.Reform.Blaze.String (label, textarea, inputCheckboxes)
import qualified Text.Reform.Blaze.String as RB
import Text.Reform.Happstack (environment)
import Text.Reform ((<++), viewForm, eitherForm)
import Happstack.Server (Response, Method(..), seeOther, toResponse, methodM, ok)
import Web.Routes.RouteT (showURL, liftRouteT)
import qualified Nomyx.Web.Help as Help
import Nomyx.Web.Common as NWC
import Nomyx.Core.Types as T
import Nomyx.Core.Mail
import Nomyx.Core.Engine
import Nomyx.Core.Session as S
default (Integer, Double, Data.Text.Text)
viewIOs :: PlayerNumber -> Game -> RoutedNomyxServer Html
viewIOs pn g = do
vios <- mapM (viewIORule pn g) (sort $ _rules g)
ok $ do
titleWithHelpIcon (h3 "Inputs/Ouputs") Help.inputsOutputs
a "" ! A.id (toValue inputAnchor)
mconcat vios
viewIORule :: PlayerNumber -> Game -> RuleInfo -> RoutedNomyxServer Html
viewIORule pn g r = do
vior <- viewIORuleM pn (_rNumber r) g
ok $ when (isJust vior) $ div ! A.id "IORule" $ do
div ! A.id "IORuleTitle" $ h4 $ fromString $ "Rule #" ++ (show $ _rNumber r) ++ " \"" ++ _rName r ++ "\": "
fromJust vior
viewIORuleM :: PlayerNumber -> RuleNumber -> Game -> RoutedNomyxServer (Maybe Html)
viewIORuleM pn rn g = do
vir <- viewInputsRule pn rn (_events g) g
let vor = viewOutputsRule pn rn g
return $ if isJust vir || isJust vor then Just $ do
when (isJust vir) $ fromJust vir
when (isJust vor) $ fromJust vor
else Nothing
viewInputsRule :: PlayerNumber -> RuleNumber -> [EventInfo] -> Game -> RoutedNomyxServer (Maybe Html)
viewInputsRule pn rn ehs g = do
let filtered = filter (\e -> _ruleNumber e == rn) ehs
mis <- mapM (viewInput pn g) $ sort filtered
let is = catMaybes mis
case is of
[] -> return Nothing
i -> return $ Just $ table $ mconcat i
viewOutputsRule :: PlayerNumber -> RuleNumber -> Game -> Maybe Html
viewOutputsRule pn rn g = do
let filtered = filter (\o -> _oRuleNumber o == rn && _oStatus o == SActive) (_outputs g)
let myos = filter (isPn pn) (sort filtered)
case myos of
[] -> Nothing
os -> Just $ sequence_ $ mapMaybe (viewOutput g) os
isPn pn (Output _ _ (Just mypn) _ SActive) = mypn == pn
isPn _ (Output _ _ Nothing _ SActive) = True
isPn _ _ = False
viewInput :: PlayerNumber -> Game -> EventInfo -> RoutedNomyxServer (Maybe Html)
viewInput me g ei@(EventInfo en _ _ _ SActive _) = do
ds <- mapMaybeM (viewInput' me (_gameName g) en) (getRemainingSignals ei g)
return $ if null ds
then Nothing
else Just $ sequence_ ds
viewInput _ _ _ = return Nothing
viewInput' :: PlayerNumber -> GameName -> EventNumber -> (SignalAddress, SomeSignal) -> RoutedNomyxServer (Maybe Html)
viewInput' me gn en (fa, ev@(SomeSignal (Input pn title _))) | me == pn = do
lf <- lift $ viewForm "user" $ inputForm ev
link <- showURL (DoInput en fa (fromJust $ getFormField ev) gn)
return $ Just $ tr $ td $ do
fromString title
fromString " "
blazeForm lf link ! A.id "InputForm"
viewInput' _ _ _ _ = return Nothing
viewOutput :: Game -> Output -> Maybe Html
viewOutput g o = if (s /= "") then Just (pre $ fromString s >> br) else Nothing where
s = (evalOutput g o)
--- TODO: merge SomeSignal and FormField...
inputForm :: SomeSignal -> NomyxForm InputData
inputForm (SomeSignal (Input _ _ (Radio choices))) = RadioData <$> NWC.inputRadio' (zip [0..] (snd <$> choices)) (== 0) <++ label (" " :: String)
inputForm (SomeSignal (Input _ _ Text)) = TextData <$> RB.inputText "" <++ label (" " :: String)
inputForm (SomeSignal (Input _ _ TextArea)) = TextAreaData <$> textarea 50 5 "" <++ label (" " :: String)
inputForm (SomeSignal (Input _ _ Button)) = pure ButtonData
inputForm (SomeSignal (Input _ _ (Checkbox choices))) = CheckboxData <$> inputCheckboxes (zip [0..] (snd <$> choices)) (const False) <++ label (" " :: String)
inputForm _ = error "Not an input form"
inputForm' :: FormField -> NomyxForm InputData
inputForm' (RadioField _ _ choices) = RadioData <$> NWC.inputRadio' choices (== 0) <++ label (" " :: String)
inputForm' (TextField _ _) = TextData <$> RB.inputText "" <++ label (" " :: String)
inputForm' (TextAreaField _ _) = TextAreaData <$> textarea 50 5 "" <++ label (" " :: String)
inputForm' (ButtonField _ _) = pure ButtonData
inputForm' (CheckboxField _ _ choices) = CheckboxData <$> inputCheckboxes choices (const False) <++ label (" " :: String)
-- | a form result has been sent
newInput :: EventNumber -> SignalAddress -> FormField -> GameName -> TVar Session -> RoutedNomyxServer Response
newInput en fa ft gn ts = toResponse <$> do
pn <- fromJust <$> getPlayerNumber ts
link <- showURL MainPage
methodM POST
r <- liftRouteT $ eitherForm environment "user" (inputForm' ft)
case r of
(Right c) -> webCommand ts $ S.inputResult pn en fa ft c gn
(Left _) -> liftIO $ putStrLn "cannot retrieve form data"
seeOther (link `appendAnchor` inputAnchor) "Redirecting..."