{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}

module Aztecs.ECS.Query.Reader
  ( -- * Queries
    QueryReader (..),
    ArrowQueryReader (..),
    ArrowDynamicQueryReader (..),

    -- ** Running
    all,
    all',

    -- * Filters
    QueryFilter (..),
    with,
    without,
    DynamicQueryFilter (..),
  )
where

import Aztecs.ECS.Component
import Aztecs.ECS.Query.Dynamic (DynamicQueryFilter (..))
import Aztecs.ECS.Query.Dynamic.Reader (DynamicQueryReader (..), allDyn)
import Aztecs.ECS.Query.Dynamic.Reader.Class (ArrowDynamicQueryReader (..))
import Aztecs.ECS.Query.Reader.Class (ArrowQueryReader (..))
import Aztecs.ECS.World.Components (Components)
import qualified Aztecs.ECS.World.Components as CS
import Aztecs.ECS.World.Entities (Entities (..))
import qualified Aztecs.ECS.World.Entities as E
import Control.Arrow (Arrow (..), ArrowChoice (..))
import Control.Category (Category (..))
import Data.Set (Set)
import qualified Data.Set as Set
import Prelude hiding (all, id, (.))

-- | Query to read from entities.
newtype QueryReader i o
  = QueryReader {forall i o.
QueryReader i o
-> Components
-> (Set ComponentID, Components, DynamicQueryReader i o)
runQueryReader :: Components -> (Set ComponentID, Components, DynamicQueryReader i o)}
  deriving ((forall a b. (a -> b) -> QueryReader i a -> QueryReader i b)
-> (forall a b. a -> QueryReader i b -> QueryReader i a)
-> Functor (QueryReader i)
forall a b. a -> QueryReader i b -> QueryReader i a
forall a b. (a -> b) -> QueryReader i a -> QueryReader i b
forall i a b. a -> QueryReader i b -> QueryReader i a
forall i a b. (a -> b) -> QueryReader i a -> QueryReader i b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
$cfmap :: forall i a b. (a -> b) -> QueryReader i a -> QueryReader i b
fmap :: forall a b. (a -> b) -> QueryReader i a -> QueryReader i b
$c<$ :: forall i a b. a -> QueryReader i b -> QueryReader i a
<$ :: forall a b. a -> QueryReader i b -> QueryReader i a
Functor)

instance Applicative (QueryReader i) where
  pure :: forall a. a -> QueryReader i a
pure a
a = (Components
 -> (Set ComponentID, Components, DynamicQueryReader i a))
-> QueryReader i a
forall i o.
(Components
 -> (Set ComponentID, Components, DynamicQueryReader i o))
-> QueryReader i o
QueryReader ((Components
  -> (Set ComponentID, Components, DynamicQueryReader i a))
 -> QueryReader i a)
-> (Components
    -> (Set ComponentID, Components, DynamicQueryReader i a))
-> QueryReader i a
forall a b. (a -> b) -> a -> b
$ \Components
cs -> (Set ComponentID
forall a. Monoid a => a
mempty, Components
cs, a -> DynamicQueryReader i a
forall a. a -> DynamicQueryReader i a
forall (f :: * -> *) a. Applicative f => a -> f a
pure a
a)
  (QueryReader Components
-> (Set ComponentID, Components, DynamicQueryReader i (a -> b))
f) <*> :: forall a b.
QueryReader i (a -> b) -> QueryReader i a -> QueryReader i b
<*> (QueryReader Components -> (Set ComponentID, Components, DynamicQueryReader i a)
g) = (Components
 -> (Set ComponentID, Components, DynamicQueryReader i b))
-> QueryReader i b
forall i o.
(Components
 -> (Set ComponentID, Components, DynamicQueryReader i o))
-> QueryReader i o
QueryReader ((Components
  -> (Set ComponentID, Components, DynamicQueryReader i b))
 -> QueryReader i b)
-> (Components
    -> (Set ComponentID, Components, DynamicQueryReader i b))
-> QueryReader i b
forall a b. (a -> b) -> a -> b
$ \Components
cs ->
    let (Set ComponentID
cIdsG, Components
cs', DynamicQueryReader i a
aQS) = Components -> (Set ComponentID, Components, DynamicQueryReader i a)
g Components
cs
        (Set ComponentID
cIdsF, Components
cs'', DynamicQueryReader i (a -> b)
bQS) = Components
-> (Set ComponentID, Components, DynamicQueryReader i (a -> b))
f Components
cs'
     in (Set ComponentID
cIdsG Set ComponentID -> Set ComponentID -> Set ComponentID
forall a. Semigroup a => a -> a -> a
<> Set ComponentID
cIdsF, Components
cs'', DynamicQueryReader i (a -> b)
bQS DynamicQueryReader i (a -> b)
-> DynamicQueryReader i a -> DynamicQueryReader i b
forall a b.
DynamicQueryReader i (a -> b)
-> DynamicQueryReader i a -> DynamicQueryReader i b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> DynamicQueryReader i a
aQS)

instance Category QueryReader where
  id :: forall a. QueryReader a a
id = (Components
 -> (Set ComponentID, Components, DynamicQueryReader a a))
-> QueryReader a a
forall i o.
(Components
 -> (Set ComponentID, Components, DynamicQueryReader i o))
-> QueryReader i o
QueryReader ((Components
  -> (Set ComponentID, Components, DynamicQueryReader a a))
 -> QueryReader a a)
-> (Components
    -> (Set ComponentID, Components, DynamicQueryReader a a))
-> QueryReader a a
forall a b. (a -> b) -> a -> b
$ \Components
cs -> (Set ComponentID
forall a. Monoid a => a
mempty, Components
cs, DynamicQueryReader a a
forall a. DynamicQueryReader a a
forall {k} (cat :: k -> k -> *) (a :: k). Category cat => cat a a
id)
  (QueryReader Components -> (Set ComponentID, Components, DynamicQueryReader b c)
f) . :: forall b c a. QueryReader b c -> QueryReader a b -> QueryReader a c
. (QueryReader Components -> (Set ComponentID, Components, DynamicQueryReader a b)
g) = (Components
 -> (Set ComponentID, Components, DynamicQueryReader a c))
-> QueryReader a c
forall i o.
(Components
 -> (Set ComponentID, Components, DynamicQueryReader i o))
-> QueryReader i o
QueryReader ((Components
  -> (Set ComponentID, Components, DynamicQueryReader a c))
 -> QueryReader a c)
-> (Components
    -> (Set ComponentID, Components, DynamicQueryReader a c))
-> QueryReader a c
forall a b. (a -> b) -> a -> b
$ \Components
cs ->
    let (Set ComponentID
cIdsG, Components
cs', DynamicQueryReader a b
aQS) = Components -> (Set ComponentID, Components, DynamicQueryReader a b)
g Components
cs
        (Set ComponentID
cIdsF, Components
cs'', DynamicQueryReader b c
bQS) = Components -> (Set ComponentID, Components, DynamicQueryReader b c)
f Components
cs'
     in (Set ComponentID
cIdsG Set ComponentID -> Set ComponentID -> Set ComponentID
forall a. Semigroup a => a -> a -> a
<> Set ComponentID
cIdsF, Components
cs'', DynamicQueryReader b c
bQS DynamicQueryReader b c
-> DynamicQueryReader a b -> DynamicQueryReader a c
forall b c a.
DynamicQueryReader b c
-> DynamicQueryReader a b -> DynamicQueryReader a c
forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. DynamicQueryReader a b
aQS)

instance Arrow QueryReader where
  arr :: forall b c. (b -> c) -> QueryReader b c
arr b -> c
f = (Components
 -> (Set ComponentID, Components, DynamicQueryReader b c))
-> QueryReader b c
forall i o.
(Components
 -> (Set ComponentID, Components, DynamicQueryReader i o))
-> QueryReader i o
QueryReader ((Components
  -> (Set ComponentID, Components, DynamicQueryReader b c))
 -> QueryReader b c)
-> (Components
    -> (Set ComponentID, Components, DynamicQueryReader b c))
-> QueryReader b c
forall a b. (a -> b) -> a -> b
$ \Components
cs -> (Set ComponentID
forall a. Monoid a => a
mempty, Components
cs, (b -> c) -> DynamicQueryReader b c
forall b c. (b -> c) -> DynamicQueryReader b c
forall (a :: * -> * -> *) b c. Arrow a => (b -> c) -> a b c
arr b -> c
f)
  first :: forall b c d. QueryReader b c -> QueryReader (b, d) (c, d)
first (QueryReader Components -> (Set ComponentID, Components, DynamicQueryReader b c)
f) = (Components
 -> (Set ComponentID, Components, DynamicQueryReader (b, d) (c, d)))
-> QueryReader (b, d) (c, d)
forall i o.
(Components
 -> (Set ComponentID, Components, DynamicQueryReader i o))
-> QueryReader i o
QueryReader ((Components
  -> (Set ComponentID, Components, DynamicQueryReader (b, d) (c, d)))
 -> QueryReader (b, d) (c, d))
-> (Components
    -> (Set ComponentID, Components, DynamicQueryReader (b, d) (c, d)))
-> QueryReader (b, d) (c, d)
forall a b. (a -> b) -> a -> b
$ \Components
comps -> let (Set ComponentID
cIds, Components
comps', DynamicQueryReader b c
qS) = Components -> (Set ComponentID, Components, DynamicQueryReader b c)
f Components
comps in (Set ComponentID
cIds, Components
comps', DynamicQueryReader b c -> DynamicQueryReader (b, d) (c, d)
forall b c d.
DynamicQueryReader b c -> DynamicQueryReader (b, d) (c, d)
forall (a :: * -> * -> *) b c d.
Arrow a =>
a b c -> a (b, d) (c, d)
first DynamicQueryReader b c
qS)

instance ArrowChoice QueryReader where
  left :: forall b c d.
QueryReader b c -> QueryReader (Either b d) (Either c d)
left (QueryReader Components -> (Set ComponentID, Components, DynamicQueryReader b c)
f) = (Components
 -> (Set ComponentID, Components,
     DynamicQueryReader (Either b d) (Either c d)))
-> QueryReader (Either b d) (Either c d)
forall i o.
(Components
 -> (Set ComponentID, Components, DynamicQueryReader i o))
-> QueryReader i o
QueryReader ((Components
  -> (Set ComponentID, Components,
      DynamicQueryReader (Either b d) (Either c d)))
 -> QueryReader (Either b d) (Either c d))
-> (Components
    -> (Set ComponentID, Components,
        DynamicQueryReader (Either b d) (Either c d)))
-> QueryReader (Either b d) (Either c d)
forall a b. (a -> b) -> a -> b
$ \Components
comps -> let (Set ComponentID
cIds, Components
comps', DynamicQueryReader b c
qS) = Components -> (Set ComponentID, Components, DynamicQueryReader b c)
f Components
comps in (Set ComponentID
cIds, Components
comps', DynamicQueryReader b c
-> DynamicQueryReader (Either b d) (Either c d)
forall b c d.
DynamicQueryReader b c
-> DynamicQueryReader (Either b d) (Either c d)
forall (a :: * -> * -> *) b c d.
ArrowChoice a =>
a b c -> a (Either b d) (Either c d)
left DynamicQueryReader b c
qS)

instance ArrowQueryReader QueryReader where
  fetch :: forall a. (Component a) => QueryReader () a
  fetch :: forall a. Component a => QueryReader () a
fetch = (Components
 -> (Set ComponentID, Components, DynamicQueryReader () a))
-> QueryReader () a
forall i o.
(Components
 -> (Set ComponentID, Components, DynamicQueryReader i o))
-> QueryReader i o
QueryReader ((Components
  -> (Set ComponentID, Components, DynamicQueryReader () a))
 -> QueryReader () a)
-> (Components
    -> (Set ComponentID, Components, DynamicQueryReader () a))
-> QueryReader () a
forall a b. (a -> b) -> a -> b
$ \Components
cs ->
    let (ComponentID
cId, Components
cs') = forall a. Component a => Components -> (ComponentID, Components)
CS.insert @a Components
cs in (ComponentID -> Set ComponentID
forall a. a -> Set a
Set.singleton ComponentID
cId, Components
cs', ComponentID -> DynamicQueryReader () a
forall a. Component a => ComponentID -> DynamicQueryReader () a
forall (arr :: * -> * -> *) a.
(ArrowDynamicQueryReader arr, Component a) =>
ComponentID -> arr () a
fetchDyn ComponentID
cId)
  fetchMaybe :: forall a. (Component a) => QueryReader () (Maybe a)
  fetchMaybe :: forall a. Component a => QueryReader () (Maybe a)
fetchMaybe = (Components
 -> (Set ComponentID, Components, DynamicQueryReader () (Maybe a)))
-> QueryReader () (Maybe a)
forall i o.
(Components
 -> (Set ComponentID, Components, DynamicQueryReader i o))
-> QueryReader i o
QueryReader ((Components
  -> (Set ComponentID, Components, DynamicQueryReader () (Maybe a)))
 -> QueryReader () (Maybe a))
-> (Components
    -> (Set ComponentID, Components, DynamicQueryReader () (Maybe a)))
-> QueryReader () (Maybe a)
forall a b. (a -> b) -> a -> b
$ \Components
cs ->
    let (ComponentID
cId, Components
cs') = forall a. Component a => Components -> (ComponentID, Components)
CS.insert @a Components
cs in (ComponentID -> Set ComponentID
forall a. a -> Set a
Set.singleton ComponentID
cId, Components
cs', ComponentID -> DynamicQueryReader () (Maybe a)
forall a.
Component a =>
ComponentID -> DynamicQueryReader () (Maybe a)
forall (arr :: * -> * -> *) a.
(ArrowDynamicQueryReader arr, Component a) =>
ComponentID -> arr () (Maybe a)
fetchMaybeDyn ComponentID
cId)

instance ArrowDynamicQueryReader QueryReader where
  entity :: QueryReader () EntityID
entity = (Components
 -> (Set ComponentID, Components, DynamicQueryReader () EntityID))
-> QueryReader () EntityID
forall i o.
(Components
 -> (Set ComponentID, Components, DynamicQueryReader i o))
-> QueryReader i o
QueryReader ((Components
  -> (Set ComponentID, Components, DynamicQueryReader () EntityID))
 -> QueryReader () EntityID)
-> (Components
    -> (Set ComponentID, Components, DynamicQueryReader () EntityID))
-> QueryReader () EntityID
forall a b. (a -> b) -> a -> b
$ \Components
cs -> (Set ComponentID
forall a. Monoid a => a
mempty, Components
cs, DynamicQueryReader () EntityID
forall (arr :: * -> * -> *).
ArrowDynamicQueryReader arr =>
arr () EntityID
entity)
  fetchDyn :: forall a. Component a => ComponentID -> QueryReader () a
fetchDyn ComponentID
cId = (Components
 -> (Set ComponentID, Components, DynamicQueryReader () a))
-> QueryReader () a
forall i o.
(Components
 -> (Set ComponentID, Components, DynamicQueryReader i o))
-> QueryReader i o
QueryReader ((Components
  -> (Set ComponentID, Components, DynamicQueryReader () a))
 -> QueryReader () a)
-> (Components
    -> (Set ComponentID, Components, DynamicQueryReader () a))
-> QueryReader () a
forall a b. (a -> b) -> a -> b
$ \Components
cs -> (ComponentID -> Set ComponentID
forall a. a -> Set a
Set.singleton ComponentID
cId, Components
cs, ComponentID -> DynamicQueryReader () a
forall a. Component a => ComponentID -> DynamicQueryReader () a
forall (arr :: * -> * -> *) a.
(ArrowDynamicQueryReader arr, Component a) =>
ComponentID -> arr () a
fetchDyn ComponentID
cId)
  fetchMaybeDyn :: forall a. Component a => ComponentID -> QueryReader () (Maybe a)
fetchMaybeDyn ComponentID
cId = (Components
 -> (Set ComponentID, Components, DynamicQueryReader () (Maybe a)))
-> QueryReader () (Maybe a)
forall i o.
(Components
 -> (Set ComponentID, Components, DynamicQueryReader i o))
-> QueryReader i o
QueryReader ((Components
  -> (Set ComponentID, Components, DynamicQueryReader () (Maybe a)))
 -> QueryReader () (Maybe a))
-> (Components
    -> (Set ComponentID, Components, DynamicQueryReader () (Maybe a)))
-> QueryReader () (Maybe a)
forall a b. (a -> b) -> a -> b
$ \Components
cs -> (ComponentID -> Set ComponentID
forall a. a -> Set a
Set.singleton ComponentID
cId, Components
cs, ComponentID -> DynamicQueryReader () (Maybe a)
forall a.
Component a =>
ComponentID -> DynamicQueryReader () (Maybe a)
forall (arr :: * -> * -> *) a.
(ArrowDynamicQueryReader arr, Component a) =>
ComponentID -> arr () (Maybe a)
fetchMaybeDyn ComponentID
cId)

-- | Filter for a `Query`.
newtype QueryFilter = QueryFilter {QueryFilter -> Components -> (DynamicQueryFilter, Components)
runQueryFilter :: Components -> (DynamicQueryFilter, Components)}

instance Semigroup QueryFilter where
  QueryFilter
a <> :: QueryFilter -> QueryFilter -> QueryFilter
<> QueryFilter
b =
    (Components -> (DynamicQueryFilter, Components)) -> QueryFilter
QueryFilter
      ( \Components
cs ->
          let (DynamicQueryFilter
withA', Components
cs') = QueryFilter -> Components -> (DynamicQueryFilter, Components)
runQueryFilter QueryFilter
a Components
cs
              (DynamicQueryFilter
withB', Components
cs'') = QueryFilter -> Components -> (DynamicQueryFilter, Components)
runQueryFilter QueryFilter
b Components
cs'
           in (DynamicQueryFilter
withA' DynamicQueryFilter -> DynamicQueryFilter -> DynamicQueryFilter
forall a. Semigroup a => a -> a -> a
<> DynamicQueryFilter
withB', Components
cs'')
      )

instance Monoid QueryFilter where
  mempty :: QueryFilter
mempty = (Components -> (DynamicQueryFilter, Components)) -> QueryFilter
QueryFilter (DynamicQueryFilter
forall a. Monoid a => a
mempty,)

-- | Filter for entities containing this component.
with :: forall a. (Component a) => QueryFilter
with :: forall a. Component a => QueryFilter
with = (Components -> (DynamicQueryFilter, Components)) -> QueryFilter
QueryFilter ((Components -> (DynamicQueryFilter, Components)) -> QueryFilter)
-> (Components -> (DynamicQueryFilter, Components)) -> QueryFilter
forall a b. (a -> b) -> a -> b
$ \Components
cs ->
  let (ComponentID
cId, Components
cs') = forall a. Component a => Components -> (ComponentID, Components)
CS.insert @a Components
cs in (DynamicQueryFilter
forall a. Monoid a => a
mempty {filterWith = Set.singleton cId}, Components
cs')

-- | Filter out entities containing this component.
without :: forall a. (Component a) => QueryFilter
without :: forall a. Component a => QueryFilter
without = (Components -> (DynamicQueryFilter, Components)) -> QueryFilter
QueryFilter ((Components -> (DynamicQueryFilter, Components)) -> QueryFilter)
-> (Components -> (DynamicQueryFilter, Components)) -> QueryFilter
forall a b. (a -> b) -> a -> b
$ \Components
cs ->
  let (ComponentID
cId, Components
cs') = forall a. Component a => Components -> (ComponentID, Components)
CS.insert @a Components
cs in (DynamicQueryFilter
forall a. Monoid a => a
mempty {filterWithout = Set.singleton cId}, Components
cs')

all :: i -> QueryReader i a -> Entities -> ([a], Entities)
all :: forall i a. i -> QueryReader i a -> Entities -> ([a], Entities)
all i
i QueryReader i a
q Entities
es = let ([a]
as, Components
cs) = i -> QueryReader i a -> Entities -> ([a], Components)
forall i a. i -> QueryReader i a -> Entities -> ([a], Components)
all' i
i QueryReader i a
q Entities
es in ([a]
as, Entities
es {E.components = cs})

-- | Match all entities.
all' :: i -> QueryReader i a -> Entities -> ([a], Components)
all' :: forall i a. i -> QueryReader i a -> Entities -> ([a], Components)
all' i
i QueryReader i a
q Entities
es = let (Set ComponentID
rs, Components
cs', DynamicQueryReader i a
dynQ) = QueryReader i a
-> Components
-> (Set ComponentID, Components, DynamicQueryReader i a)
forall i o.
QueryReader i o
-> Components
-> (Set ComponentID, Components, DynamicQueryReader i o)
runQueryReader QueryReader i a
q (Entities -> Components
E.components Entities
es) in (Set ComponentID -> i -> DynamicQueryReader i a -> Entities -> [a]
forall i a.
Set ComponentID -> i -> DynamicQueryReader i a -> Entities -> [a]
allDyn Set ComponentID
rs i
i DynamicQueryReader i a
dynQ Entities
es, Components
cs')