{-# LANGUAGE AllowAmbiguousTypes #-}

module Mischief.ECS.World.Query.QueryFilter where

import Data.Data
import Data.Maybe
import GHC.Base (eqWord#, isTrue#)
import Mischief.ECS.Components
import Mischief.ECS.Entities
import Mischief.ECS.World
import Mischief.ECS.World.Query.Markers

-- import Mischief.ECS.World.Query.Queryable

qfChangedF :: (Tick -> Tick -> Bool) -> (Tick -> Tick -> Bool) -> ComponentTick -> Tick -> Tick -> Bool
qfChangedF :: (Tick -> Tick -> Bool)
-> (Tick -> Tick -> Bool) -> ComponentTick -> Tick -> Tick -> Bool
qfChangedF Tick -> Tick -> Bool
f1 Tick -> Tick -> Bool
f2 (ComponentTick !Tick
tick) !Tick
lastSystemTick !Tick
currentSystemTick = Tick -> Tick -> Bool
f1 Tick
tick Tick
lastSystemTick Bool -> Bool -> Bool
&& Tick -> Tick -> Bool
f2 Tick
tick Tick
currentSystemTick

data FilterType = ArchetypeFilter | EntityFilter

data QueryFilter where
  NoFilter :: QueryFilter
  With :: (ToFilterComponent a) => a -> QueryFilter
  Without :: (ToFilterComponent a) => a -> QueryFilter
  Changed :: (ToFilterComponent a) => a -> (Tick -> Tick -> Bool) -> (Tick -> Tick -> Bool) -> QueryFilter
  And :: QueryFilter -> QueryFilter -> QueryFilter
  Or :: QueryFilter -> QueryFilter -> QueryFilter

newtype FilterComponent = FilterComponent {FilterComponent -> (TypeRep, Maybe Entity, Maybe Any)
inner :: (TypeRep, Maybe Entity, Maybe Any)}

class ToFilterComponent a where
  toFilterComponent :: a -> FilterComponent

instance (Component c) => ToFilterComponent (C c) where
  toFilterComponent :: C c -> FilterComponent
toFilterComponent C c
_ = (TypeRep, Maybe Entity, Maybe Any) -> FilterComponent
FilterComponent (Proxy c -> TypeRep
forall {k} (proxy :: k -> *) (a :: k).
Typeable a =>
proxy a -> TypeRep
typeRep (Proxy c -> TypeRep) -> Proxy c -> TypeRep
forall a b. (a -> b) -> a -> b
$ forall t. Proxy t
forall {k} (t :: k). Proxy t
Proxy @c, Maybe Entity
forall a. Maybe a
Nothing, Maybe Any
forall a. Maybe a
Nothing)

instance (Component c) => ToFilterComponent (R c Entity) where
  toFilterComponent :: R c Entity -> FilterComponent
toFilterComponent (R !Entity
entity) = (TypeRep, Maybe Entity, Maybe Any) -> FilterComponent
FilterComponent (Proxy c -> TypeRep
forall {k} (proxy :: k -> *) (a :: k).
Typeable a =>
proxy a -> TypeRep
typeRep (Proxy c -> TypeRep) -> Proxy c -> TypeRep
forall a b. (a -> b) -> a -> b
$ forall t. Proxy t
forall {k} (t :: k). Proxy t
Proxy @c, Entity -> Maybe Entity
forall a. a -> Maybe a
Just Entity
entity, Maybe Any
forall a. Maybe a
Nothing)

instance (Component c) => ToFilterComponent (R c Any) where
  toFilterComponent :: R c Any -> FilterComponent
toFilterComponent R c Any
_ = (TypeRep, Maybe Entity, Maybe Any) -> FilterComponent
FilterComponent (Proxy c -> TypeRep
forall {k} (proxy :: k -> *) (a :: k).
Typeable a =>
proxy a -> TypeRep
typeRep (Proxy c -> TypeRep) -> Proxy c -> TypeRep
forall a b. (a -> b) -> a -> b
$ forall t. Proxy t
forall {k} (t :: k). Proxy t
Proxy @c, Maybe Entity
forall a. Maybe a
Nothing, Any -> Maybe Any
forall a. a -> Maybe a
Just Any
Any)

instance Semigroup QueryFilter where
  (<>) :: QueryFilter -> QueryFilter -> QueryFilter
  <> :: QueryFilter -> QueryFilter -> QueryFilter
(<>) = QueryFilter -> QueryFilter -> QueryFilter
And

filterArchetype' :: FilterComponent -> World -> [ComponentId] -> IO Bool
filterArchetype' :: FilterComponent -> World -> [ComponentId] -> IO Bool
filterArchetype' (FilterComponent (!TypeRep
c, !Maybe Entity
entity, Maybe Any
Nothing)) !World
world ![ComponentId]
components = do
  !component <- (ComponentId -> ComponentId)
-> Maybe ComponentId -> Maybe ComponentId
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Maybe Entity -> ComponentId -> ComponentId
setCompIdTarget Maybe Entity
entity) (Maybe ComponentId -> Maybe ComponentId)
-> IO (Maybe ComponentId) -> IO (Maybe ComponentId)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> TypeRep -> Components -> IO (Maybe ComponentId)
getComponentId TypeRep
c World
world.components
  pure $ case component of
    Maybe ComponentId
Nothing -> Bool
False
    Just !ComponentId
component -> ComponentId
component ComponentId -> [ComponentId] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [ComponentId]
components
filterArchetype' (FilterComponent (!TypeRep
c, Maybe Entity
_, Just Any
_)) World
world [ComponentId]
components = do
  !component <- TypeRep -> Components -> IO (Maybe ComponentId)
getComponentId TypeRep
c World
world.components
  case component of
    Maybe ComponentId
Nothing -> Bool -> IO Bool
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Bool
False
    Just (ComponentId (# !Word#
id, Maybe Entity
_ #)) -> do
      Bool -> IO Bool
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Bool -> IO Bool) -> Bool -> IO Bool
forall a b. (a -> b) -> a -> b
$ (ComponentId -> Bool) -> [ComponentId] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (\(ComponentId (# !Word#
id', !Maybe Entity
a #)) -> Maybe Entity -> Bool
forall a. Maybe a -> Bool
isJust Maybe Entity
a Bool -> Bool -> Bool
&& Int# -> Bool
isTrue# (Word# -> Word# -> Int#
eqWord# Word#
id' Word#
id)) [ComponentId]
components