{-# LANGUAGE AllowAmbiguousTypes #-}
{-# OPTIONS_GHC -Wno-redundant-constraints #-}

module Mischief.ECS.Relationships.Graph where

import Data.List
import Mischief.ECS.Components
import Mischief.ECS.Components.BundleTypes
import Mischief.ECS.Entities
import Mischief.ECS.World
import Mischief.ECS.World.Query
import Mischief.ECS.World.Query.Markers
import Mischief.ECS.World.Query.QueryFilter (QueryFilter (With))

type family RelOutgoing b where
  RelOutgoing True = Maybe
  RelOutgoing False = List

class ListToOutgoing b where
  listToOutgoing :: [Entity] -> b

instance ListToOutgoing (Maybe Entity) where
  listToOutgoing :: [Entity] -> Maybe Entity
listToOutgoing [Entity
x] = Entity -> Maybe Entity
forall a. a -> Maybe a
Just Entity
x
  listToOutgoing [Entity]
_ = Maybe Entity
forall a. Maybe a
Nothing

instance ListToOutgoing [Entity] where
  listToOutgoing :: [Entity] -> [Entity]
listToOutgoing = [Entity] -> [Entity]
forall a. a -> a
id

outgoing' :: forall c m w. (Component c, MonadSystem w m) => Entity -> m [Entity]
outgoing' :: forall c (m :: * -> *) w.
(Component c, MonadSystem w m) =>
Entity -> m [Entity]
outgoing' Entity
entity = do
  next <- Query m [Rel c] -> m (Maybe [Rel c])
forall w (m :: * -> *) out.
MonadSystem w m =>
Query m out -> m (Maybe out)
single (Query m [Rel c] -> m (Maybe [Rel c]))
-> Query m [Rel c] -> m (Maybe [Rel c])
forall a b. (a -> b) -> a -> b
$ Entity -> R' c Any -> Query m [Rel c]
forall qd out (m :: * -> *).
Queryable qd out =>
Entity -> qd -> Query m out
mkGet Entity
entity (forall {k} (a :: k) b. b -> R' a b
forall a b. b -> R' a b
R' @c Any
Any)
  return $ case next of
    Maybe [Rel c]
Nothing -> []
    Just [Rel c]
next -> (Rel c -> Entity) -> [Rel c] -> [Entity]
forall a b. (a -> b) -> [a] -> [b]
map (\Rel c
x -> Rel c
x.target) [Rel c]
next

outgoing :: forall c m w. (Component c, MonadSystem w m, ListToOutgoing (RelOutgoing (IsExclusiveRel c) Entity)) => Entity -> m (RelOutgoing (IsExclusiveRel c) Entity)
outgoing :: forall c (m :: * -> *) w.
(Component c, MonadSystem w m,
 ListToOutgoing (RelOutgoing (IsExclusiveRel c) Entity)) =>
Entity -> m (RelOutgoing (IsExclusiveRel c) Entity)
outgoing Entity
entity = [Entity] -> RelOutgoing (IsExclusiveRel c) Entity
forall b. ListToOutgoing b => [Entity] -> b
listToOutgoing ([Entity] -> RelOutgoing (IsExclusiveRel c) Entity)
-> m [Entity] -> m (RelOutgoing (IsExclusiveRel c) Entity)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall c (m :: * -> *) w.
(Component c, MonadSystem w m) =>
Entity -> m [Entity]
outgoing' @c Entity
entity

incoming :: forall c m w. (Component c, BundleTypes c, MonadSystem w m) => Entity -> m [Entity]
incoming :: forall c (m :: * -> *) w.
(Component c, BundleTypes c, MonadSystem w m) =>
Entity -> m [Entity]
incoming Entity
entity = Query m Entity -> m [Entity]
forall w (m :: * -> *) out.
MonadSystem w m =>
Query m out -> m [out]
query (Query m Entity -> m [Entity]) -> Query m Entity -> m [Entity]
forall a b. (a -> b) -> a -> b
$ E -> QueryFilter 'ArchetypeFilter -> Query m Entity
forall qd out (m :: * -> *).
Queryable qd out =>
qd -> QueryFilter 'ArchetypeFilter -> Query m out
mkQuery' E
E (R c Entity -> QueryFilter 'ArchetypeFilter
forall a (f :: FilterType).
ToFilterComponent a =>
a -> QueryFilter f
With (forall {k} (a :: k) b. b -> R a b
forall a b. b -> R a b
R @c Entity
entity))