{-# LANGUAGE GADTs #-}

module Epidemic.Types.Simulation
  ( SimulationConfiguration(..)
  , SimulationState(..)
  , SimulationRandEvent(..)
  ) where

import Epidemic.Types.Events
import Epidemic.Types.Parameter
import Epidemic.Types.Population
import Epidemic.Types.Time (AbsoluteTime(..), TimeDelta(..), timeDelta)
import System.Random.MWC

data SimulationConfiguration r p =
  SimulationConfiguration
    { -- | The event rates
      SimulationConfiguration r p -> r
scRates :: r
      -- | The population
    , SimulationConfiguration r p -> p
scPopulation :: p
      -- | A new identifier
    , SimulationConfiguration r p -> Identifier
scNewIdentifier :: Identifier
      -- | The absolute time at which the simulation starts
    , SimulationConfiguration r p -> AbsoluteTime
scStartTime :: AbsoluteTime
      -- | The duration of the simulation until it stops
    , SimulationConfiguration r p -> TimeDelta
scSimDuration :: TimeDelta
      -- | The simulation terminates if this predicate is not satisfied
    , SimulationConfiguration r p -> Maybe (p -> Bool)
scValidPopulation :: Maybe (p -> Bool)
      -- | The simulation requires at least two sequenced samples
    , SimulationConfiguration r p -> Bool
scRequireCherry :: Bool
    }

-- | Either there is a valid simulation state which contains a sequence of
-- epidemic events of there is a terminated simulation which indicates that
-- the simulation has been rejected.
data SimulationState b
  = SimulationState (AbsoluteTime, [EpidemicEvent], b, Identifier)
  | TerminatedSimulation
  deriving (SimulationState b -> SimulationState b -> Bool
(SimulationState b -> SimulationState b -> Bool)
-> (SimulationState b -> SimulationState b -> Bool)
-> Eq (SimulationState b)
forall b. Eq b => SimulationState b -> SimulationState b -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: SimulationState b -> SimulationState b -> Bool
$c/= :: forall b. Eq b => SimulationState b -> SimulationState b -> Bool
== :: SimulationState b -> SimulationState b -> Bool
$c== :: forall b. Eq b => SimulationState b -> SimulationState b -> Bool
Eq, Int -> SimulationState b -> ShowS
[SimulationState b] -> ShowS
SimulationState b -> String
(Int -> SimulationState b -> ShowS)
-> (SimulationState b -> String)
-> ([SimulationState b] -> ShowS)
-> Show (SimulationState b)
forall b. Show b => Int -> SimulationState b -> ShowS
forall b. Show b => [SimulationState b] -> ShowS
forall b. Show b => SimulationState b -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [SimulationState b] -> ShowS
$cshowList :: forall b. Show b => [SimulationState b] -> ShowS
show :: SimulationState b -> String
$cshow :: forall b. Show b => SimulationState b -> String
showsPrec :: Int -> SimulationState b -> ShowS
$cshowsPrec :: forall b. Show b => Int -> SimulationState b -> ShowS
Show)

data SimulationRandEvent a b where
  SimulationRandEvent
    :: (ModelParameters a b, Population b)
    => (a
    -> AbsoluteTime
    -> b
    -> Identifier
    -> GenIO
    -> IO (AbsoluteTime, EpidemicEvent, b, Identifier))
    -> SimulationRandEvent a b