packages feed

nomyx-web-1.0.0: src/Nomyx/Web/Game/Templates.hs

{-# LANGUAGE DoAndIfThenElse      #-}
{-# LANGUAGE ExtendedDefaultRules #-}
{-# LANGUAGE OverloadedStrings    #-}
{-# LANGUAGE ScopedTypeVariables  #-}
--{-# LANGUAGE ApplicativeDo  #-}

module Nomyx.Web.Game.Templates where

import           Control.Applicative
import           Control.Monad
import           Control.Monad.State
import           Data.Maybe
import           Data.Function (on)
import           Data.String
import           Data.List (sortBy, groupBy)
import           Data.Ord (comparing)
import           Data.Text                   (Text, pack, unpack)
import           Data.Text.Encoding
import           Happstack.Server            (Method (..), Response, methodM,
                                              ok, seeOther, toResponse)
import           Nomyx.Language
import           Nomyx.Core.Engine
import           Nomyx.Core.Session          as S
import           Nomyx.Core.Types            as T
import           Nomyx.Core.Utils
import           Nomyx.Web.Common            as NWC
import qualified Nomyx.Web.Help              as Help
import           Nomyx.Web.Types
import           Prelude                     hiding (div)
import           Text.Blaze.Html5            as H (Html, a, div, h2, h3, h4,
                                                   img, input, label, li, pre,
                                                   toValue, ul, (!), p, br)
import           Text.Blaze.Html5.Attributes as A (class_, disabled, for, href,
                                                   id, placeholder, src, type_,
                                                   value)
import           Text.Reform                 (eitherForm, viewForm, (++>),
                                              (<++))
import           Text.Reform.Blaze.Common    (setAttr)
import           Text.Reform.Blaze.String    (inputHidden, inputSubmit, label,
                                              textarea)
import qualified Text.Reform.Blaze.String    as RB
import           Text.Reform.Happstack       (environment)
import           Web.Routes.RouteT           (liftRouteT)
import           Happstack.Server            (ContentType)
import           Safe
import           Network.HTTP.Base                  (urlEncode)
default (Integer, Double, Data.Text.Text)


-- * Library display

viewLibrary :: Library -> Maybe LastRule -> GameName -> Bool -> RoutedNomyxServer Html
viewLibrary (Library rts ms) mlr gn isGameAdmin = do
  vrs <- mapM (viewPaneRuleTemplate gn mlr isGameAdmin) rts
  ok $ do
    div ! class_ "ruleList" $ viewRuleTemplateCats rts mlr
    div ! class_ "rules" $ sequence_ vrs

-- * left menu display

viewRuleTemplateCats :: [RuleTemplate] -> Maybe LastRule -> Html
viewRuleTemplateCats rts mlr = do
  let cat = (headDef "Not category" . _rCategory)
  let rts' = groupBy ((==) `on` cat) $ sortBy (comparing cat) rts
  h2 "Library of rules"
  ul $ mapM_  viewRuleTemplateCat rts'

viewRuleTemplateCat :: [RuleTemplate] -> Html
viewRuleTemplateCat rts = li $ do
   fromString $ headDef "No category" $ _rCategory $ head rts
   ul $ mapM_  viewRuleTemplateName rts

viewRuleTemplateName :: RuleTemplate -> Html
viewRuleTemplateName rt = li $ H.a (fromString $ _rName rt) ! A.class_ "ruleName" ! (A.href $ toValue $ "?ruleName=" ++ (idEncode $ _rName rt))


-- * main tab display

viewPaneRuleTemplate :: GameName -> Maybe LastRule -> Bool -> RuleTemplate -> RoutedNomyxServer Html
viewPaneRuleTemplate gn mlr isGameAdmin rt = do
  let toEdit = case mlr of
       Nothing -> (rt, "")
       Just lr -> if ((_rName $ fst lr) == (_rName rt)) then lr else (rt, "")
  com <- templateCommands gn rt
  view <- viewRuleTemplate gn toEdit isGameAdmin
  edit <- viewRuleTemplateEdit toEdit gn
  ok $ div ! A.class_ "rule" ! A.id (toValue $ idEncode $ _rName rt) $ do
    com
    view
    edit

-- ** Template commands

templateCommands :: GameName -> RuleTemplate -> RoutedNomyxServer Html
templateCommands gn rt = do
  let delLink = showRelURL (DelRuleTemplate gn (_rName rt))
  let idrt = idEncode $ _rName rt
  ok $ div ! A.class_ "commandrule" $ do
    p $ H.a "view"   ! (A.href $ toValue $ "?ruleName=" ++ idrt)
    p $ H.a "edit"   ! (A.href $ toValue $ "?ruleName=" ++ idrt ++ "&edit")
    p $ H.a "delete" ! (A.href $ toValue delLink)


delRuleTemplate :: GameName -> RuleName -> RoutedNomyxServer Response
delRuleTemplate gn rn = do
  pn <- fromJust <$> getPlayerNumber
  webCommand $ S.delRuleTemplate rn pn
  seeOther (showRelURL $ Menu Lib gn) $ toResponse "Redirecting..."


viewRuleTemplate :: GameName -> LastRule -> Bool -> RoutedNomyxServer Html
viewRuleTemplate gn (rt@(RuleTemplate name desc code author picture _ decls), err) isGameAdmin = do
  lf  <- liftRouteT $ lift $ viewForm "user" (submitRuleTemplatForm (Just rt) isGameAdmin)
  ok $ div ! A.class_ "viewrule" $ do
    viewRuleHead name picture desc author
    viewRuleCode code
    mapM (viewDecl gn) decls
    div $ pre $ fromString err
    blazeForm lf $ showRelURL (SubmitRule gn)


submitRuleTemplatForm :: (Maybe RuleTemplate) -> Bool -> NomyxForm (String, Maybe String)
submitRuleTemplatForm mrt isGameAdmin = 
   (,) <$> inputHidden (show mrt)
       <*> if isGameAdmin then inputSubmit "Admin submit" else pure Nothing

--submitRuleTemplatForm :: (Maybe RuleTemplate) -> Bool -> NomyxForm (String, Maybe String)
--submitRuleTemplatForm mrt isGameAdmin = do
--  srt <- inputHidden (show mrt)
--  admin <- if isGameAdmin then inputSubmit "Admin submit" else pure Nothing
--  return (srt, admin)

viewDecl :: GameName -> FilePath -> Html
viewDecl gn modPath = do
   let link = showRelURLParams (Menu Modules gn) [("modulePath", Just $ pack $ idEncode modPath)]
   H.a (fromString modPath) ! (A.href $ toValue $ link)
   H.br


-- | Submit a template to a given game
submitRuleTemplatePost :: GameName -> RoutedNomyxServer Response
submitRuleTemplatePost gn = toResponse <$> do
   methodM POST
   s <- getSession
   let gi = getGameByName gn s
   admin <- isGameAdmin (fromJust gi)
   r <- liftRouteT $ lift $ eitherForm environment "user" (submitRuleTemplatForm Nothing True)
   pn <- fromJust <$> getPlayerNumber
   rt <- case r of
      Right (srt, Nothing) -> do
         let rt = fromJust $ read srt
         webCommand $ submitRule rt pn gn
         return rt
      Right (srt, Just _)  -> do
         let rt = read srt
         webCommand $ adminSubmitRule rt pn gn
         return rt
      (Left _)            -> error "cannot retrieve form data"
   seeOther (showRelURLParams (Menu Lib gn) [("ruleName", Just $ pack $ idEncode $ _rName rt)]) $ "Redirecting..."


-- * Template edit

-- Edit a template
viewRuleTemplateEdit :: LastRule -> GameName -> RoutedNomyxServer Html
viewRuleTemplateEdit lr gn = do
  lf  <- liftRouteT $ lift $ viewForm "user" (newRuleTemplateForm (Just $ fst lr) True)
  ok $ div ! A.class_ "editRule" $ do
    blazeForm lf $ showRelURL $ NewRuleTemplate gn
    pre $ fromString $ snd lr

newRuleTemplateForm :: Maybe RuleTemplate -> Bool -> NomyxForm (RuleTemplate, Maybe String)
newRuleTemplateForm sr isGameAdmin = newRuleTemplateForm' (fromMaybe (RuleTemplate "" "" "" "" Nothing [] []) sr) isGameAdmin

newRuleTemplateForm' :: RuleTemplate -> Bool -> NomyxForm (RuleTemplate, Maybe String)
newRuleTemplateForm' rt isGameAdmin =
  (,) <$> newRuleTemplateForm'' rt
      <*> inputSubmit "Check"

newRuleTemplateForm'' :: RuleTemplate -> NomyxForm RuleTemplate
newRuleTemplateForm'' (RuleTemplate name desc code aut pic cat decls) =
  RuleTemplate <$>  RB.label "Name: " ++> RB.inputText name `setAttr` class_ "ruleName" <++ RB.br
               <*> (RB.label "      Short description: " ++> (RB.inputText desc `setAttr` class_ "ruleDescr") <++ RB.br)
               <*>  RB.label "      Code: " ++> textarea 80 15 code `setAttr` class_ "ruleCode" `setAttr` placeholder "Enter here your rule"
               <*>  (inputHidden aut)
               <*>  (read <$> (inputHidden $ show pic))
               <*>  (read <$> (inputHidden $ show cat))
               <*>  (read <$> (inputHidden $ show decls))

newRuleTemplate :: GameName -> RoutedNomyxServer Response
newRuleTemplate gn = toResponse <$> do
  methodM POST
  r <- liftRouteT $ lift $ eitherForm environment "user" (newRuleTemplateForm Nothing False)
  pn <- fromJust <$> getPlayerNumber
  case r of
     Right (rt, Nothing) -> do
       webCommand $ S.newRuleTemplate pn rt
       seeOther (showRelURLParams (Menu Lib gn) [("ruleName", Just $ pack $ idEncode $ _rName rt)]) $ "Redirecting..."
     Right (rt, Just _)  -> do
       webCommand $ S.checkRule rt pn gn
       seeOther (showRelURLParams (Menu Lib gn) [("ruleName", Just $ pack $ idEncode $ _rName rt), ("edit", Nothing)]) $ "Redirecting..."
     _ -> error "cannot retrieve form data"