{-# LANGUAGE TypeFamilies #-}

-- |
-- Module     : Simulation.Aivika.Experiment.Base.FileRenderer
-- Copyright  : Copyright (c) 2012-2017, David Sorokin <david.sorokin@gmail.com>
-- License    : BSD3
-- Maintainer : David Sorokin <david.sorokin@gmail.com>
-- Stability  : experimental
-- Tested with: GHC 8.0.1
--
-- It defines a renderer that saves the results in files when running the simulation experiment.
--

module Simulation.Aivika.Experiment.Base.FileRenderer where

import Control.Monad
import Control.Monad.Trans

import System.Directory
import System.FilePath

import Simulation.Aivika.Trans.Exception
import Simulation.Aivika.Experiment.Types
import Simulation.Aivika.Experiment.Base.ExperimentWriter

-- | It defines a simulation 'Experiment' renderer that saves the results in files. 
data FileRenderer a = FileRenderer a ExperimentFilePath
                      -- ^ A file renderer that depends on the provided parameter and
                      -- a directory path, where the simulation results are saved in.

-- | A convenient type synonym for describing a file generator.
type FileGenerator a = ExperimentGenerator (FileRenderer a)

-- | Saving the results of simulation in files when running the experiment.
instance ExperimentRendering (FileRenderer a) where

  -- | A file rendering context.
  data ExperimentContext (FileRenderer a) = FileContext
                                            -- ^ A file context constructor.

  -- | A file environment.
  type ExperimentEnvironment (FileRenderer a) = FilePath

  -- | A file rendering monad.
  type ExperimentMonad (FileRenderer a) = ExperimentWriter

  liftExperiment :: forall a.
FileRenderer a -> ExperimentMonad (FileRenderer a) a -> IO a
liftExperiment FileRenderer a
r = ExperimentMonad (FileRenderer a) a -> IO a
ExperimentWriter a -> IO a
forall a. ExperimentWriter a -> IO a
runExperimentWriter

  prepareExperiment :: Experiment
-> FileRenderer a
-> ExperimentMonad
     (FileRenderer a) (ExperimentEnvironment (FileRenderer a))
prepareExperiment Experiment
e (FileRenderer a
_ ExperimentFilePath
path0) =
    do FilePath
path <- FilePath -> ExperimentFilePath -> ExperimentWriter FilePath
resolveFilePath FilePath
"" ExperimentFilePath
path0
       IO () -> ExperimentWriter ()
forall a. IO a -> ExperimentWriter a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> ExperimentWriter ()) -> IO () -> ExperimentWriter ()
forall a b. (a -> b) -> a -> b
$ do
         Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Experiment -> Bool
experimentVerbose Experiment
e) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$
           do FilePath -> IO ()
putStr FilePath
"Updating directory " 
              FilePath -> IO ()
putStrLn FilePath
path
         Bool -> FilePath -> IO ()
createDirectoryIfMissing Bool
True FilePath
path
       FilePath -> ExperimentWriter FilePath
forall a. a -> ExperimentWriter a
forall (m :: * -> *) a. Monad m => a -> m a
return FilePath
path
  
  renderExperiment :: Experiment
-> FileRenderer a
-> [ExperimentReporter (FileRenderer a)]
-> ExperimentEnvironment (FileRenderer a)
-> ExperimentMonad (FileRenderer a) ()
renderExperiment Experiment
e FileRenderer a
r [ExperimentReporter (FileRenderer a)]
reporters ExperimentEnvironment (FileRenderer a)
path = () -> ExperimentWriter ()
forall a. a -> ExperimentWriter a
forall (m :: * -> *) a. Monad m => a -> m a
return ()

  onExperimentCompleted :: Experiment
-> FileRenderer a
-> ExperimentEnvironment (FileRenderer a)
-> ExperimentMonad (FileRenderer a) ()
onExperimentCompleted Experiment
e FileRenderer a
r ExperimentEnvironment (FileRenderer a)
path = () -> ExperimentWriter ()
forall a. a -> ExperimentWriter a
forall (m :: * -> *) a. Monad m => a -> m a
return ()

  onExperimentFailed :: forall e.
Exception e =>
Experiment
-> FileRenderer a
-> ExperimentEnvironment (FileRenderer a)
-> e
-> ExperimentMonad (FileRenderer a) ()
onExperimentFailed Experiment
e FileRenderer a
r ExperimentEnvironment (FileRenderer a)
path e
e' = e -> ExperimentWriter ()
forall e a. Exception e => e -> ExperimentWriter a
forall (m :: * -> *) e a.
(MonadException m, Exception e) =>
e -> m a
throwComp e
e'