packages feed

ideas-1.0: src/Documentation/ExercisePage.hs

-----------------------------------------------------------------------------
-- Copyright 2011, Open Universiteit Nederland. This file is distributed
-- under the terms of the GNU General Public License. For more information,
-- see the file "LICENSE.txt", which is included in the distribution.
-----------------------------------------------------------------------------
-- |
-- Maintainer  :  bastiaan.heeren@ou.nl
-- Stability   :  provisional
-- Portability :  portable (depends on ghc)
--
-----------------------------------------------------------------------------
module Documentation.ExercisePage (makeExercisePage, idboxHTML) where

import Common.Library hiding (up)
import Common.Utils (Some(..), commaList)
import Control.Monad
import Data.Maybe
import Documentation.DefaultPage
import Documentation.ExampleFile
import Documentation.OpenMathDerivations
import Documentation.RulePresenter
import Service.BasicServices
import Service.Diagnose
import Service.DomainReasoner
import Service.State
import Service.StrategyInfo
import System.Directory
import System.Random
import Text.HTML

makeExercisePage :: String -> Exercise a -> DomainReasoner ()
makeExercisePage dir ex = do
   let make     = makeId ex
       makeId a = generatePageAt (length (qualifiers a)) dir . ($ getId a)
       exFile   = dir ++ "/" ++ diagnosisExampleFile (getId ex)

   exampleFileExists <- liftIO (doesFileExist exFile)

   make exercisePageFile     (exercisePage exampleFileExists ex)
   make exerciseStrategyFile (strategyPage ex)
   unless (null (examples ex)) $ do
       make exerciseDerivationsFile (derivationsPage ex)
       liftIO $ makeOpenMathDerivations dir ex
   when exampleFileExists $ do
      ef <- liftIO (readExampleFile exFile)
      make exerciseDiagnosisFile (diagnosisPage ef ex)
    `catchError` \_ -> return ()

exercisePage :: Bool -> Exercise a -> HTMLBuilder
exercisePage exampleFileExists ex = do
   idboxHTML "exercise" exid

   h2 "1. General information"

   let bolds (x:xs) = bold x:xs
       bolds []     = []

   table False $ map bolds
      [ [ text "Code",   ttText (showId ex)]
      , [ text "Status", text (show $ status ex)]
      , [ text "Strategy"
        , link (up len ++ exerciseStrategyFile exid) $
             text (showId $ strategy ex)
        ]
      , [ text "OpenMath support"
        , text $ showBool $ isJust $ hasTermView ex
        ]
      {- , [ text "Textual feedback"
        , text $ showBool $ isJust $ getScript ex
        ] -}
      , [ text "Restartable strategy"
        , text $ showBool $ canBeRestarted ex
        ]
      , [ text "Exercise generator"
        , text $ showBool $ isJust $ randomExercise ex
        ]
      , [ text "Examples"
        , text $ show $ length $ examples ex
        ]
      ]

   h2 "2. Rules"
   let rs   = rulesInStrategy (strategy ex)
       goUp = up (length (qualifiers ex))
       f r  = [ link (goUp ++ ruleFile r) $ ttText (showId r)
              , text $ showBool $ isBuggyRule r
              , text $ showBool $ hasArguments r
              , text $ showBool $ r `elem` rs
              , when (isRewriteRule r) $
                   ruleToHTML (Some ex) r
              ]
   table True
      ( [ text "Rule name", text "Buggy", text "Args"
        , text "Used", text "Rewrite rule"
        ]
      : map f (ruleset ex)
      )
   when exampleFileExists $
      para $ link (up len ++ exerciseDiagnosisFile exid) $ do
         br
         text "See diagnosis examples"
   -- preText $ show $ treesToInfo ex trees

   h2 "3. Example"
   let state = generate (mkStdGen 0) ex Medium
   derivationHTML ex (stateTerm state)
   para $ unless (null (examples ex)) $
      link (up len ++ exerciseDerivationsFile exid) (text "More examples")
 where
   exid  = getId ex
   len   = length (qualifiers ex)
   {-
   trees = [ mapFirst getId (derivationTree (strategy ex) (inContext ex a))
           | (_, a) <- examples ex
           ] -}

strategyPage :: Exercise a -> HTMLBuilder
strategyPage ex = do
   h1 title
   h2 "1. Representation in XML"
   highlightXML True (strategyToXML (strategy ex))
   h2 "2. Locations"
   let f (loc, a) =
          [text (show loc), indent (length loc) >> text (showId a)]
       indent n = text (replicate (3*n) '.')
   table True
      ( [text "Location", text "Label"]
      : map f (strategyLocations (strategy ex))
      )
 where
   title = "Strategy for " ++ showId ex

derivationsPage :: Exercise a -> HTMLBuilder
derivationsPage ex = do
   h1 "Examples"
   forM_ (zip [1::Int ..] (examples ex)) $ \(i, (_, a)) -> do
      h2 (show i ++ ".")
      derivationHTML ex a

derivationHTML :: Exercise a -> a -> HTMLBuilder
derivationHTML ex a = divClass "derivation" $ do
   when (isJust (hasTermView ex)) $
      let file = up upn ++ "derivations/" ++ showId ex ++ ".xml"
      in divClass "mathml" $ link file $ text "MathML"
   pre $ derivationM (forStep upn) (forTerm ex) der
   unless (ok der) $
      divClass "error" $ text "<<not ready>>"
 where
   upn = length (qualifiers ex)
   der = derivationPrevious (derivationDiffEnv (defaultDerivation ex a))
   ok  = maybe False (isReady ex) . fromContext . lastTerm

idboxHTML :: String -> Id -> HTMLBuilder
idboxHTML kind i = divClass "idbox" $ do
   divClass  "id-type" $ text kind
   spanClass "id-code" $ ttText (showId i)
   divClass  "id-description" $ text $
      if null (description i) then "no description" else description i

diagnosisPage :: ExampleFile -> Exercise a -> HTMLBuilder
diagnosisPage ef ex = do
   h1 ("Diagnosis examples for " ++ showId ex)
   let rs = [ (t, eb, descr) | Ready t eb descr <- items ef ]
   unless (null rs) $ table True $
      map text ["term", "ready", "description"] : map readyItem rs
   let ts = [ (t0, t1, expl) | Diagnose t0 t1 expl <- items ef ]
   zipWithM_ diagnoseItem [1::Int ..] ts
 where
   readyItem (t, eb, descr) =
      let mark = if ok then id else spanClass "error"
          (ok, result) =
             case parser ex t of
                Left _  -> (False, "error")
                Right a -> let b = isReady ex a
                           in (maybe True (==b) eb, showBool b)
      in map mark [ttText t, text result, text descr]

   diagnoseItem i (t0, t1, expl) = do
      h2 (show i ++ ".")
      preText (t0 ++ "\n  =>\n" ++ t1)
      unless (null expl) $ para $ do
         bold $ text "Description:"
         space
         text expl
         br
         bold $ text "Diagnosis:"
         space
         text (getDiagnosis t0 t1)

   getDiagnosis t0 t1 =
      case (parser ex t0, parser ex t1) of
         (Left msg, _) -> "parse error (before): " ++ msg
         (_, Left msg) -> "parse error (after): "  ++ msg
         (Right a, Right b) -> show (diagnose (emptyState ex a) b)

forStep :: Int -> ((Rule (Context a), Environment), Context a) -> HTMLBuilder
forStep n ((r, env), old) = do
      spaces 3
      text "=>"
      space
      let target = up n ++ ruleFile r
          make | null (description r) = link target
               | otherwise = titleA (description r) . link target
      make (text (unqualified r))
      let xs = fromMaybe [] (expectedArguments r old)
          g (ArgValue descr x) = labelArgument descr ++ "=" ++ showArgument descr x
      unless (null xs) $ do
         br
         spaces 6
         text (commaList (map g xs))
      unless (nullEnv env) $ do
         br
         spaces 6
         text (show env)
      br

forTerm :: Exercise a -> Context a -> HTMLBuilder
forTerm ex ca = do
   text (prettyPrinterContext ex ca)
   br