module Mischief.ECS.Relationships.Order where

import Data.Foldable
import Data.Maybe
import Data.Set (Set)
import Data.Set qualified as Set
import Mischief.ECS.Components
import Mischief.ECS.Entities
import Mischief.ECS.Log
import Mischief.ECS.Tables
import Mischief.ECS.Utils
import Mischief.ECS.World
import Mischief.ECS.World.Insert
import Mischief.ECS.World.Query
import Mischief.ECS.World.Query.QueryFilter
import Mischief.ECS.World.Query.Queryable
import Mischief.ECS.World.Remove
import Mischief.ECS.World.Spawn
import Mischief.ECS.World.Utils

data Before = Before deriving (Typeable Before
Set DefaultComponentType
Hooks Before
IsExclusive (RelExclusivity Before)
(Typeable Before, IsExclusive (RelExclusivity Before)) =>
Set DefaultComponentType -> Hooks Before -> Component Before
forall c.
(Typeable c, IsExclusive (RelExclusivity c)) =>
Set DefaultComponentType -> Hooks c -> Component c
$crequired :: Set DefaultComponentType
required :: Set DefaultComponentType
$chooks :: Hooks Before
hooks :: Hooks Before
Component)

data Visited = Visited deriving (Typeable Visited
Set DefaultComponentType
Hooks Visited
IsExclusive (RelExclusivity Visited)
(Typeable Visited, IsExclusive (RelExclusivity Visited)) =>
Set DefaultComponentType -> Hooks Visited -> Component Visited
forall c.
(Typeable c, IsExclusive (RelExclusivity c)) =>
Set DefaultComponentType -> Hooks c -> Component c
$crequired :: Set DefaultComponentType
required :: Set DefaultComponentType
$chooks :: Hooks Visited
hooks :: Hooks Visited
Component)

orderEntities :: [Entity] -> System [Entity]
orderEntities :: [Entity] -> System [Entity]
orderEntities [Entity]
entities = do
  res <- Set Entity -> System [Entity]
orderEntitiesStep ([Entity] -> Set Entity
forall a. Ord a => [a] -> Set a
Set.fromList [Entity]
entities)
  for_ entities $ remove (C @Visited)
  -- err $ text res
  return res

orderEntitiesStep :: Set Entity -> System [Entity]
orderEntitiesStep :: Set Entity -> System [Entity]
orderEntitiesStep Set Entity
entities =
  if Set Entity -> Bool
forall a. Set a -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null Set Entity
entities
    then
      [Entity] -> System [Entity]
forall a. a -> System a
forall (m :: * -> *) a. Monad m => a -> m a
return []
    else do
      next <- forall (m :: * -> *) w a.
(HasCallStack, MonadSystem w m) =>
Text -> Maybe a -> m a
Text -> Maybe Entity -> System Entity
forall (m :: * -> *) w a. MonadSystem w m => Text -> Maybe a -> m a
expect Text
"Attempted to Order Cyclic Graph!" (Maybe Entity -> System Entity)
-> System (Maybe Entity) -> System Entity
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< (Entity -> System Bool) -> Set Entity -> System (Maybe Entity)
forall (m :: * -> *) a (t :: * -> *).
(Monad m, Foldable t) =>
(a -> m Bool) -> t a -> m (Maybe a)
findM Entity -> System Bool
isAvailable Set Entity
entities
      insert Visited next
      (next :) <$> orderEntitiesStep (Set.delete next entities)

isAvailable :: Entity -> System Bool
isAvailable :: Entity -> System Bool
isAvailable Entity
entity = do
  before <- E -> With (R Before Entity) -> System [Entity]
forall qd (m :: * -> *) w out qf.
(Queryable qd out, MonadSystem w m, Collectable qf QueryFilter) =>
qd -> qf -> m [out]
query' E
E (R Before Entity -> With (R Before Entity)
forall c. c -> With c
With (forall {k} (a :: k) b. b -> R a b
forall a b. b -> R a b
R @Before Entity
entity))
  isNothing <$> findM ((not . unwrap <$>) . get (Has @Visited)) before