module Simulation.Aivika.Experiment.InfoView
(InfoView(..),
defaultInfoView) where
import Control.Monad
import Control.Monad.Trans
import Control.Concurrent.MVar
import Data.IORef
import Data.Maybe
import Data.Monoid
import Simulation.Aivika
import Simulation.Aivika.Experiment.Types
import Simulation.Aivika.Experiment.WebPageRenderer
import Simulation.Aivika.Experiment.ExperimentWriter
import Simulation.Aivika.Experiment.HtmlWriter
import Simulation.Aivika.Experiment.MRef
data InfoView =
InfoView { infoTitle :: String,
infoDescription :: String,
infoTransform :: ResultTransform,
infoSeries :: ResultTransform,
infoLocalisation :: ResultLocalisation
}
defaultInfoView :: InfoView
defaultInfoView =
InfoView { infoTitle = "Information",
infoDescription = "It shows the information about simulation entities:",
infoTransform = id,
infoSeries = id,
infoLocalisation = englishResultLocalisation }
instance ExperimentView InfoView (WebPageRenderer a) where
outputView v =
let reporter exp renderer dir =
do st <- newInfo v exp dir
let context =
WebPageContext $
WebPageWriter { reporterWriteTOCHtml = infoTOCHtml st,
reporterWriteHtml = infoHtml st }
return ExperimentReporter { reporterInitialise = return (),
reporterFinalise = return (),
reporterSimulate = simulateInfo st,
reporterContext = context }
in ExperimentGenerator { generateReporter = reporter }
data InfoViewState =
InfoViewState { infoView :: InfoView,
infoExperiment :: Experiment,
infoResults :: MRef (Maybe InfoResults) }
data InfoResults =
InfoResults { infoNames :: [String],
infoValues :: [String] }
newInfo :: InfoView -> Experiment -> FilePath -> ExperimentWriter InfoViewState
newInfo view exp dir =
do r <- liftIO $ newMRef Nothing
return InfoViewState { infoView = view,
infoExperiment = exp,
infoResults = r }
newInfoResults :: [ResultSource] -> ResultLocalisation -> Experiment -> IO InfoResults
newInfoResults sources loc exp =
do let xs =
flip map sources $ \source ->
case source of
ResultItemSource (ResultItem x) ->
[(resultItemName x, loc $ resultItemId x)]
ResultObjectSource x ->
[(resultObjectName x, loc $ resultObjectId x)]
ResultVectorSource x ->
[(resultVectorName x, loc $ resultVectorId x)]
ResultSeparatorSource x ->
[]
(names, values) = unzip $ concat xs
return InfoResults { infoNames = names,
infoValues = values }
requireInfoResults :: InfoViewState -> [ResultSource] -> IO InfoResults
requireInfoResults st sources =
let view = infoView st
loc = infoLocalisation view
exp = infoExperiment st
in maybeWriteMRef (infoResults st)
(newInfoResults sources loc exp) $ \results ->
do let xs =
flip map sources $ \source ->
case source of
ResultItemSource (ResultItem x) ->
[resultItemName x]
ResultObjectSource x ->
[resultObjectName x]
ResultVectorSource x ->
[resultVectorName x]
ResultSeparatorSource x ->
[]
let names = concat xs
if (names /= infoNames results)
then error "Series with different names are returned for different runs: requireInfoResults"
else return results
simulateInfo :: InfoViewState -> ExperimentData -> Event DisposableEvent
simulateInfo st expdata =
do let view = infoView st
rs = infoSeries view $
infoTransform view $
experimentResults expdata
sources = resultSourceList rs
liftIO $ requireInfoResults st sources
return mempty
infoHtml :: InfoViewState -> Int -> HtmlWriter ()
infoHtml st index =
do header st index
results <- liftIO $ readMRef (infoResults st)
case results of
Nothing -> return ()
Just results ->
do let names = infoNames results
values = infoValues results
writeHtmlList $
forM_ (zip names values) $ \(name, value) ->
writeHtmlListItem $
do writeHtmlText name
writeHtmlText " - "
writeHtmlText value
header :: InfoViewState -> Int -> HtmlWriter ()
header st index =
do writeHtmlHeader3WithId ("id" ++ show index) $
writeHtmlText (infoTitle $ infoView st)
let description = infoDescription $ infoView st
unless (null description) $
writeHtmlParagraph $
writeHtmlText description
infoTOCHtml :: InfoViewState -> Int -> HtmlWriter ()
infoTOCHtml st index =
writeHtmlListItem $
writeHtmlLink ("#id" ++ show index) $
writeHtmlText (infoTitle $ infoView st)