{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeOperators #-}

module Aztecs.ECS.Scheduler
  ( Scheduler (..),
    runSchedule,
    Run (..),
    Before (..),
    After (..),
  )
where

import Aztecs.ECS.Executor
import Aztecs.ECS.HSet
import Aztecs.ECS.Schedule.Internal
import Aztecs.ECS.Scheduler.Internal
import Data.Foldable

executeSchedule ::
  forall m cs s.
  ( Scheduler m s,
    Execute m (SchedulerOutput m s),
    s ~ HSet (SchedulerInput m s)
  ) =>
  s ->
  ExecutorT m ()
executeSchedule :: forall (m :: * -> *) cs s.
(Scheduler m s, Execute m (SchedulerOutput m s),
 s ~ HSet (SchedulerInput m s)) =>
s -> ExecutorT m ()
executeSchedule s
s = HSet
  (LevelsToNestedHSet
     (ScheduleLevels
        m (TopologicalSort (BuildSystemGraph (SchedulerInput m s)))))
-> ExecutorT m ()
forall (m :: * -> *) s. Execute m s => s -> ExecutorT m ()
execute (forall {k} {k1} (m :: k) (s :: k1).
Scheduler m s =>
HSet (SchedulerInput m s) -> SchedulerOutput m s
forall (m :: * -> *) s.
Scheduler m s =>
HSet (SchedulerInput m s) -> SchedulerOutput m s
buildSchedule @m @s s
HSet (SchedulerInput m s)
s)
{-# INLINE executeSchedule #-}

runSchedule ::
  forall m cs s.
  ( Applicative m,
    Execute m (SchedulerOutput m s),
    s ~ HSet (SchedulerInput m s),
    AllSystems m (SchedulerInput m s),
    ScheduleLevelsBuilder
      m
      (TopologicalSort (BuildSystemGraph (SchedulerInput m s)))
      (SchedulerInput m s)
  ) =>
  s ->
  m ()
runSchedule :: forall (m :: * -> *) cs s.
(Applicative m, Execute m (SchedulerOutput m s),
 s ~ HSet (SchedulerInput m s), AllSystems m (SchedulerInput m s),
 ScheduleLevelsBuilder
   m
   (TopologicalSort (BuildSystemGraph (SchedulerInput m s)))
   (SchedulerInput m s)) =>
s -> m ()
runSchedule s
s = ExecutorT m () -> ([m ()] -> m ()) -> m ()
forall (m :: * -> *) a. ExecutorT m a -> ([m ()] -> m ()) -> m a
runSystems (forall (m :: * -> *) cs s.
(Scheduler m s, Execute m (SchedulerOutput m s),
 s ~ HSet (SchedulerInput m s)) =>
s -> ExecutorT m ()
executeSchedule @m @cs @s s
s) (([m ()] -> m ()) -> m ()) -> ([m ()] -> m ()) -> m ()
forall a b. (a -> b) -> a -> b
$
  \[m ()]
actions -> [m ()] -> m ()
forall (t :: * -> *) (f :: * -> *) a.
(Foldable t, Applicative f) =>
t (f a) -> f ()
sequenceA_ [m ()]
actions
{-# INLINE runSchedule #-}