-- |
-- Module     : Simulation.Aivika.Trans.GPSS.Block.Preempt
-- Copyright  : Copyright (c) 2017, David Sorokin <david.sorokin@gmail.com>
-- License    : BSD3
-- Maintainer : David Sorokin <david.sorokin@gmail.com>
-- Stability  : experimental
-- Tested with: GHC 8.0.2
--
-- This module defines the GPSS block Preempt.
--
module Simulation.Aivika.Trans.GPSS.Block.Preempt
       (preemptBlock,
        PreemptBlockMode(..),
        defaultPreemptBlockMode,
        toFacilityPreemptMode,
        fromFacilityPreemptMode) where

import Simulation.Aivika.Trans
import Simulation.Aivika.Trans.GPSS.Transact
import Simulation.Aivika.Trans.GPSS.Block
import Simulation.Aivika.Trans.GPSS.Facility

-- | Specifies the Preempt block mode.
data PreemptBlockMode m a =
  PreemptBlockMode { PreemptBlockMode m a -> Bool
preemptBlockPriorityMode :: Bool,
                     -- ^ the Priority mode; otherwise, the Interrupt mode
                     PreemptBlockMode m a
-> Maybe (Maybe Double -> Block m (Transact m a) ())
preemptBlockTransfer :: Maybe (Maybe Double -> Block m (Transact m a) ()),
                     -- ^ where to transfer the preempted transact,
                     -- passing in the remaining time from the process holding 
                     -- computation such as the ADVANCE block
                     PreemptBlockMode m a -> Bool
preemptBlockRemoveMode :: Bool
                     -- ^ the Remove mode
                   }

-- | Convert 'PreemptBlockMode' to 'FacilityPreemptMode'.
toFacilityPreemptMode :: MonadDES m => PreemptBlockMode m a -> FacilityPreemptMode m a
{-# INLINABLE toFacilityPreemptMode #-}
toFacilityPreemptMode :: PreemptBlockMode m a -> FacilityPreemptMode m a
toFacilityPreemptMode PreemptBlockMode m a
m =
  FacilityPreemptMode :: forall (m :: * -> *) a.
Bool
-> Maybe (FacilityPreemptTransfer m a)
-> Bool
-> FacilityPreemptMode m a
FacilityPreemptMode { facilityPriorityMode :: Bool
facilityPriorityMode = PreemptBlockMode m a -> Bool
forall (m :: * -> *) a. PreemptBlockMode m a -> Bool
preemptBlockPriorityMode PreemptBlockMode m a
m,
                        facilityTransfer :: Maybe (FacilityPreemptTransfer m a)
facilityTransfer     = Maybe (FacilityPreemptTransfer m a)
transfer,
                        facilityRemoveMode :: Bool
facilityRemoveMode   = PreemptBlockMode m a -> Bool
forall (m :: * -> *) a. PreemptBlockMode m a -> Bool
preemptBlockRemoveMode PreemptBlockMode m a
m
                      }
  where
    transfer :: Maybe (FacilityPreemptTransfer m a)
transfer =
      case PreemptBlockMode m a
-> Maybe (Maybe Double -> Block m (Transact m a) ())
forall (m :: * -> *) a.
PreemptBlockMode m a
-> Maybe (Maybe Double -> Block m (Transact m a) ())
preemptBlockTransfer PreemptBlockMode m a
m of
        Maybe (Maybe Double -> Block m (Transact m a) ())
Nothing -> Maybe (FacilityPreemptTransfer m a)
forall a. Maybe a
Nothing
        Just Maybe Double -> Block m (Transact m a) ()
f  -> FacilityPreemptTransfer m a -> Maybe (FacilityPreemptTransfer m a)
forall a. a -> Maybe a
Just (\Transact m a
a Maybe Double
dt -> Block m (Transact m a) () -> Transact m a -> Process m ()
forall (m :: * -> *) a b. Block m a b -> a -> Process m b
blockProcess (Maybe Double -> Block m (Transact m a) ()
f Maybe Double
dt) Transact m a
a)

-- | Convert 'PreemptBlockMode' from 'FacilityPreemptMode'.
fromFacilityPreemptMode :: MonadDES m => FacilityPreemptMode m a -> PreemptBlockMode m a
{-# INLINABLE fromFacilityPreemptMode #-}
fromFacilityPreemptMode :: FacilityPreemptMode m a -> PreemptBlockMode m a
fromFacilityPreemptMode FacilityPreemptMode m a
m =
  PreemptBlockMode :: forall (m :: * -> *) a.
Bool
-> Maybe (Maybe Double -> Block m (Transact m a) ())
-> Bool
-> PreemptBlockMode m a
PreemptBlockMode { preemptBlockPriorityMode :: Bool
preemptBlockPriorityMode = FacilityPreemptMode m a -> Bool
forall (m :: * -> *) a. FacilityPreemptMode m a -> Bool
facilityPriorityMode FacilityPreemptMode m a
m,
                     preemptBlockTransfer :: Maybe (Maybe Double -> Block m (Transact m a) ())
preemptBlockTransfer     = Maybe (Maybe Double -> Block m (Transact m a) ())
transfer,
                     preemptBlockRemoveMode :: Bool
preemptBlockRemoveMode   = FacilityPreemptMode m a -> Bool
forall (m :: * -> *) a. FacilityPreemptMode m a -> Bool
facilityRemoveMode FacilityPreemptMode m a
m
                   }
  where
    transfer :: Maybe (Maybe Double -> Block m (Transact m a) ())
transfer =
      case FacilityPreemptMode m a -> Maybe (FacilityPreemptTransfer m a)
forall (m :: * -> *) a.
FacilityPreemptMode m a -> Maybe (FacilityPreemptTransfer m a)
facilityTransfer FacilityPreemptMode m a
m of
        Maybe (FacilityPreemptTransfer m a)
Nothing -> Maybe (Maybe Double -> Block m (Transact m a) ())
forall a. Maybe a
Nothing
        Just FacilityPreemptTransfer m a
f  -> (Maybe Double -> Block m (Transact m a) ())
-> Maybe (Maybe Double -> Block m (Transact m a) ())
forall a. a -> Maybe a
Just (\Maybe Double
dt -> (Transact m a -> Process m ()) -> Block m (Transact m a) ()
forall (m :: * -> *) a b. (a -> Process m b) -> Block m a b
Block ((Transact m a -> Process m ()) -> Block m (Transact m a) ())
-> (Transact m a -> Process m ()) -> Block m (Transact m a) ()
forall a b. (a -> b) -> a -> b
$ \Transact m a
a -> FacilityPreemptTransfer m a
f Transact m a
a Maybe Double
dt)

-- | The default Preempt block mode.
defaultPreemptBlockMode :: MonadDES m => PreemptBlockMode m a
{-# INLINABLE defaultPreemptBlockMode #-}
defaultPreemptBlockMode :: PreemptBlockMode m a
defaultPreemptBlockMode =
  PreemptBlockMode :: forall (m :: * -> *) a.
Bool
-> Maybe (Maybe Double -> Block m (Transact m a) ())
-> Bool
-> PreemptBlockMode m a
PreemptBlockMode { preemptBlockPriorityMode :: Bool
preemptBlockPriorityMode = Bool
False,
                     preemptBlockTransfer :: Maybe (Maybe Double -> Block m (Transact m a) ())
preemptBlockTransfer     = Maybe (Maybe Double -> Block m (Transact m a) ())
forall a. Maybe a
Nothing,
                     preemptBlockRemoveMode :: Bool
preemptBlockRemoveMode   = Bool
False
                   }

-- | This is the GPSS construct
--
-- @PREEMPT A,B,C,D,E@
preemptBlock :: MonadDES m
                => Facility m a
                -- ^ the facility
                -> PreemptBlockMode m a
                -- ^ the Preempt block mode
                -> Block m (Transact m a) (Transact m a)
{-# INLINABLE preemptBlock #-}
preemptBlock :: Facility m a
-> PreemptBlockMode m a -> Block m (Transact m a) (Transact m a)
preemptBlock Facility m a
r PreemptBlockMode m a
m =
  Block :: forall (m :: * -> *) a b. (a -> Process m b) -> Block m a b
Block { blockProcess :: Transact m a -> Process m (Transact m a)
blockProcess = \Transact m a
a -> Facility m a
-> Transact m a -> FacilityPreemptMode m a -> Process m ()
forall (m :: * -> *) a.
MonadDES m =>
Facility m a
-> Transact m a -> FacilityPreemptMode m a -> Process m ()
preemptFacility Facility m a
r Transact m a
a (PreemptBlockMode m a -> FacilityPreemptMode m a
forall (m :: * -> *) a.
MonadDES m =>
PreemptBlockMode m a -> FacilityPreemptMode m a
toFacilityPreemptMode PreemptBlockMode m a
m) Process m ()
-> Process m (Transact m a) -> Process m (Transact m a)
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Transact m a -> Process m (Transact m a)
forall (m :: * -> *) a. Monad m => a -> m a
return Transact m a
a }