{-# LANGUAGE TypeFamilies, MultiParamTypeClasses, FlexibleInstances, FlexibleContexts, FunctionalDependencies, UndecidableInstances #-}

-- |
-- Module     : Simulation.Aivika.Trans.QueueStrategy
-- Copyright  : Copyright (c) 2009-2017, David Sorokin <david.sorokin@gmail.com>
-- License    : BSD3
-- Maintainer : David Sorokin <david.sorokin@gmail.com>
-- Stability  : experimental
-- Tested with: GHC 8.0.1
--
-- This module defines the queue strategies.
--
module Simulation.Aivika.Trans.QueueStrategy where

import Control.Monad

import Data.Maybe

import Simulation.Aivika.Trans.Internal.Types

-- | Defines the basic queue strategy.
class Monad m => QueueStrategy m s where

  -- | The strategy queue.
  data StrategyQueue m s :: * -> *

  -- | Create a new queue by the specified strategy.
  newStrategyQueue :: s
                      -- ^ the strategy
                      -> Simulation m (StrategyQueue m s a)
                      -- ^ a new queue

  -- | Test whether the queue is empty.
  strategyQueueNull :: StrategyQueue m s a
                       -- ^ the queue
                       -> Event m Bool
                       -- ^ the result of the test

-- | Defines a strategy with support of the dequeuing operation.
class QueueStrategy m s => DequeueStrategy m s where

  -- | Dequeue the front element and return it.
  strategyDequeue :: StrategyQueue m s a
                     -- ^ the queue
                     -> Event m a
                     -- ^ the dequeued element

-- | It defines a strategy when we can enqueue a single element.
class DequeueStrategy m s => EnqueueStrategy m s where

  -- | Enqueue an element.
  strategyEnqueue :: StrategyQueue m s a
                     -- ^ the queue
                     -> a
                     -- ^ the element to be enqueued
                     -> Event m ()
                     -- ^ the action of enqueuing

-- | It defines a strategy when we can enqueue an element with the specified priority.
class DequeueStrategy m s => PriorityQueueStrategy m s p | s -> p where

  -- | Enqueue an element with the specified priority.
  strategyEnqueueWithPriority :: StrategyQueue m s a
                                 -- ^ the queue
                                 -> p
                                 -- ^ the priority
                                 -> a
                                 -- ^ the element to be enqueued
                                 -> Event m ()
                                 -- ^ the action of enqueuing

-- | Defines a strategy with support of the deleting operation.
class DequeueStrategy m s => DeletingQueueStrategy m s where

  -- | Remove the element and return a flag indicating whether
  -- the element was found and removed.
  strategyQueueDelete :: Eq a
                         => StrategyQueue m s a
                         -- ^ the queue
                         -> a
                         -- ^ the element
                         -> Event m Bool
                         -- ^ whether the element was found and removed
  strategyQueueDelete StrategyQueue m s a
s a
a =
    (Point m -> m Bool) -> Event m Bool
forall (m :: * -> *) a. (Point m -> m a) -> Event m a
Event ((Point m -> m Bool) -> Event m Bool)
-> (Point m -> m Bool) -> Event m Bool
forall a b. (a -> b) -> a -> b
$ \Point m
p ->
    do Maybe a
x <- Point m -> Event m (Maybe a) -> m (Maybe a)
forall (m :: * -> *) a. Point m -> Event m a -> m a
invokeEvent Point m
p (Event m (Maybe a) -> m (Maybe a))
-> Event m (Maybe a) -> m (Maybe a)
forall a b. (a -> b) -> a -> b
$ StrategyQueue m s a -> (a -> Bool) -> Event m (Maybe a)
forall a. StrategyQueue m s a -> (a -> Bool) -> Event m (Maybe a)
forall (m :: * -> *) s a.
DeletingQueueStrategy m s =>
StrategyQueue m s a -> (a -> Bool) -> Event m (Maybe a)
strategyQueueDeleteBy StrategyQueue m s a
s (a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
a)
       Bool -> m Bool
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe a -> Bool
forall a. Maybe a -> Bool
isJust Maybe a
x)

  -- | Remove an element satisfying the predicate and return the element if found.
  strategyQueueDeleteBy :: StrategyQueue m s a
                           -- ^ the queue
                           -> (a -> Bool)
                           -- ^ the predicate
                           -> Event m (Maybe a)
                           -- ^ the element if it was found and removed

  -- | Detect whether the specified element is contained in the queue.
  strategyQueueContains :: Eq a
                           => StrategyQueue m s a
                           -- ^ the queue
                           -> a
                           -- ^ the element to find
                           -> Event m Bool
                           -- ^ whether the element is contained in the queue
  strategyQueueContains StrategyQueue m s a
s a
a =
    (Point m -> m Bool) -> Event m Bool
forall (m :: * -> *) a. (Point m -> m a) -> Event m a
Event ((Point m -> m Bool) -> Event m Bool)
-> (Point m -> m Bool) -> Event m Bool
forall a b. (a -> b) -> a -> b
$ \Point m
p ->
    do Maybe a
x <- Point m -> Event m (Maybe a) -> m (Maybe a)
forall (m :: * -> *) a. Point m -> Event m a -> m a
invokeEvent Point m
p (Event m (Maybe a) -> m (Maybe a))
-> Event m (Maybe a) -> m (Maybe a)
forall a b. (a -> b) -> a -> b
$ StrategyQueue m s a -> (a -> Bool) -> Event m (Maybe a)
forall a. StrategyQueue m s a -> (a -> Bool) -> Event m (Maybe a)
forall (m :: * -> *) s a.
DeletingQueueStrategy m s =>
StrategyQueue m s a -> (a -> Bool) -> Event m (Maybe a)
strategyQueueContainsBy StrategyQueue m s a
s (a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
a)
       Bool -> m Bool
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe a -> Bool
forall a. Maybe a -> Bool
isJust Maybe a
x)

  -- | Detect whether an element satifying the specified predicate is contained in the queue.
  strategyQueueContainsBy :: StrategyQueue m s a
                             -- ^ the queue
                             -> (a -> Bool)
                             -- ^ the predicate
                             -> Event m (Maybe a)
                             -- ^ the element if it was found

-- | Strategy: First Come - First Served (FCFS).
data FCFS = FCFS deriving (FCFS -> FCFS -> Bool
(FCFS -> FCFS -> Bool) -> (FCFS -> FCFS -> Bool) -> Eq FCFS
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: FCFS -> FCFS -> Bool
== :: FCFS -> FCFS -> Bool
$c/= :: FCFS -> FCFS -> Bool
/= :: FCFS -> FCFS -> Bool
Eq, Eq FCFS
Eq FCFS =>
(FCFS -> FCFS -> Ordering)
-> (FCFS -> FCFS -> Bool)
-> (FCFS -> FCFS -> Bool)
-> (FCFS -> FCFS -> Bool)
-> (FCFS -> FCFS -> Bool)
-> (FCFS -> FCFS -> FCFS)
-> (FCFS -> FCFS -> FCFS)
-> Ord FCFS
FCFS -> FCFS -> Bool
FCFS -> FCFS -> Ordering
FCFS -> FCFS -> FCFS
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: FCFS -> FCFS -> Ordering
compare :: FCFS -> FCFS -> Ordering
$c< :: FCFS -> FCFS -> Bool
< :: FCFS -> FCFS -> Bool
$c<= :: FCFS -> FCFS -> Bool
<= :: FCFS -> FCFS -> Bool
$c> :: FCFS -> FCFS -> Bool
> :: FCFS -> FCFS -> Bool
$c>= :: FCFS -> FCFS -> Bool
>= :: FCFS -> FCFS -> Bool
$cmax :: FCFS -> FCFS -> FCFS
max :: FCFS -> FCFS -> FCFS
$cmin :: FCFS -> FCFS -> FCFS
min :: FCFS -> FCFS -> FCFS
Ord, Int -> FCFS -> ShowS
[FCFS] -> ShowS
FCFS -> String
(Int -> FCFS -> ShowS)
-> (FCFS -> String) -> ([FCFS] -> ShowS) -> Show FCFS
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> FCFS -> ShowS
showsPrec :: Int -> FCFS -> ShowS
$cshow :: FCFS -> String
show :: FCFS -> String
$cshowList :: [FCFS] -> ShowS
showList :: [FCFS] -> ShowS
Show)

-- | Strategy: Last Come - First Served (LCFS)
data LCFS = LCFS deriving (LCFS -> LCFS -> Bool
(LCFS -> LCFS -> Bool) -> (LCFS -> LCFS -> Bool) -> Eq LCFS
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: LCFS -> LCFS -> Bool
== :: LCFS -> LCFS -> Bool
$c/= :: LCFS -> LCFS -> Bool
/= :: LCFS -> LCFS -> Bool
Eq, Eq LCFS
Eq LCFS =>
(LCFS -> LCFS -> Ordering)
-> (LCFS -> LCFS -> Bool)
-> (LCFS -> LCFS -> Bool)
-> (LCFS -> LCFS -> Bool)
-> (LCFS -> LCFS -> Bool)
-> (LCFS -> LCFS -> LCFS)
-> (LCFS -> LCFS -> LCFS)
-> Ord LCFS
LCFS -> LCFS -> Bool
LCFS -> LCFS -> Ordering
LCFS -> LCFS -> LCFS
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: LCFS -> LCFS -> Ordering
compare :: LCFS -> LCFS -> Ordering
$c< :: LCFS -> LCFS -> Bool
< :: LCFS -> LCFS -> Bool
$c<= :: LCFS -> LCFS -> Bool
<= :: LCFS -> LCFS -> Bool
$c> :: LCFS -> LCFS -> Bool
> :: LCFS -> LCFS -> Bool
$c>= :: LCFS -> LCFS -> Bool
>= :: LCFS -> LCFS -> Bool
$cmax :: LCFS -> LCFS -> LCFS
max :: LCFS -> LCFS -> LCFS
$cmin :: LCFS -> LCFS -> LCFS
min :: LCFS -> LCFS -> LCFS
Ord, Int -> LCFS -> ShowS
[LCFS] -> ShowS
LCFS -> String
(Int -> LCFS -> ShowS)
-> (LCFS -> String) -> ([LCFS] -> ShowS) -> Show LCFS
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> LCFS -> ShowS
showsPrec :: Int -> LCFS -> ShowS
$cshow :: LCFS -> String
show :: LCFS -> String
$cshowList :: [LCFS] -> ShowS
showList :: [LCFS] -> ShowS
Show)

-- | Strategy: Service in Random Order (SIRO).
data SIRO = SIRO deriving (SIRO -> SIRO -> Bool
(SIRO -> SIRO -> Bool) -> (SIRO -> SIRO -> Bool) -> Eq SIRO
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: SIRO -> SIRO -> Bool
== :: SIRO -> SIRO -> Bool
$c/= :: SIRO -> SIRO -> Bool
/= :: SIRO -> SIRO -> Bool
Eq, Eq SIRO
Eq SIRO =>
(SIRO -> SIRO -> Ordering)
-> (SIRO -> SIRO -> Bool)
-> (SIRO -> SIRO -> Bool)
-> (SIRO -> SIRO -> Bool)
-> (SIRO -> SIRO -> Bool)
-> (SIRO -> SIRO -> SIRO)
-> (SIRO -> SIRO -> SIRO)
-> Ord SIRO
SIRO -> SIRO -> Bool
SIRO -> SIRO -> Ordering
SIRO -> SIRO -> SIRO
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: SIRO -> SIRO -> Ordering
compare :: SIRO -> SIRO -> Ordering
$c< :: SIRO -> SIRO -> Bool
< :: SIRO -> SIRO -> Bool
$c<= :: SIRO -> SIRO -> Bool
<= :: SIRO -> SIRO -> Bool
$c> :: SIRO -> SIRO -> Bool
> :: SIRO -> SIRO -> Bool
$c>= :: SIRO -> SIRO -> Bool
>= :: SIRO -> SIRO -> Bool
$cmax :: SIRO -> SIRO -> SIRO
max :: SIRO -> SIRO -> SIRO
$cmin :: SIRO -> SIRO -> SIRO
min :: SIRO -> SIRO -> SIRO
Ord, Int -> SIRO -> ShowS
[SIRO] -> ShowS
SIRO -> String
(Int -> SIRO -> ShowS)
-> (SIRO -> String) -> ([SIRO] -> ShowS) -> Show SIRO
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> SIRO -> ShowS
showsPrec :: Int -> SIRO -> ShowS
$cshow :: SIRO -> String
show :: SIRO -> String
$cshowList :: [SIRO] -> ShowS
showList :: [SIRO] -> ShowS
Show)

-- | Strategy: Static Priorities. It uses the priority queue.
data StaticPriorities = StaticPriorities deriving (StaticPriorities -> StaticPriorities -> Bool
(StaticPriorities -> StaticPriorities -> Bool)
-> (StaticPriorities -> StaticPriorities -> Bool)
-> Eq StaticPriorities
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: StaticPriorities -> StaticPriorities -> Bool
== :: StaticPriorities -> StaticPriorities -> Bool
$c/= :: StaticPriorities -> StaticPriorities -> Bool
/= :: StaticPriorities -> StaticPriorities -> Bool
Eq, Eq StaticPriorities
Eq StaticPriorities =>
(StaticPriorities -> StaticPriorities -> Ordering)
-> (StaticPriorities -> StaticPriorities -> Bool)
-> (StaticPriorities -> StaticPriorities -> Bool)
-> (StaticPriorities -> StaticPriorities -> Bool)
-> (StaticPriorities -> StaticPriorities -> Bool)
-> (StaticPriorities -> StaticPriorities -> StaticPriorities)
-> (StaticPriorities -> StaticPriorities -> StaticPriorities)
-> Ord StaticPriorities
StaticPriorities -> StaticPriorities -> Bool
StaticPriorities -> StaticPriorities -> Ordering
StaticPriorities -> StaticPriorities -> StaticPriorities
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: StaticPriorities -> StaticPriorities -> Ordering
compare :: StaticPriorities -> StaticPriorities -> Ordering
$c< :: StaticPriorities -> StaticPriorities -> Bool
< :: StaticPriorities -> StaticPriorities -> Bool
$c<= :: StaticPriorities -> StaticPriorities -> Bool
<= :: StaticPriorities -> StaticPriorities -> Bool
$c> :: StaticPriorities -> StaticPriorities -> Bool
> :: StaticPriorities -> StaticPriorities -> Bool
$c>= :: StaticPriorities -> StaticPriorities -> Bool
>= :: StaticPriorities -> StaticPriorities -> Bool
$cmax :: StaticPriorities -> StaticPriorities -> StaticPriorities
max :: StaticPriorities -> StaticPriorities -> StaticPriorities
$cmin :: StaticPriorities -> StaticPriorities -> StaticPriorities
min :: StaticPriorities -> StaticPriorities -> StaticPriorities
Ord, Int -> StaticPriorities -> ShowS
[StaticPriorities] -> ShowS
StaticPriorities -> String
(Int -> StaticPriorities -> ShowS)
-> (StaticPriorities -> String)
-> ([StaticPriorities] -> ShowS)
-> Show StaticPriorities
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> StaticPriorities -> ShowS
showsPrec :: Int -> StaticPriorities -> ShowS
$cshow :: StaticPriorities -> String
show :: StaticPriorities -> String
$cshowList :: [StaticPriorities] -> ShowS
showList :: [StaticPriorities] -> ShowS
Show)