{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}

-- |
-- Module      : Aztecs.ECS.World.Bundle.Dynamic
-- Copyright   : (c) Matt Hunzinger, 2025
-- License     : BSD-style (see the LICENSE file in the distribution)
--
-- Maintainer  : matt@hunzinger.me
-- Stability   : provisional
-- Portability : non-portable (GHC extensions)
module Aztecs.ECS.World.Bundle.Dynamic (DynamicBundle (..), MonoidDynamicBundle (..)) where

import Aztecs.ECS.Access.Internal (Access)
import Aztecs.ECS.Entity
import Aztecs.ECS.World.Archetype
import Aztecs.ECS.World.Bundle.Dynamic.Class

-- | Dynamic bundle of components.
newtype DynamicBundle m = DynamicBundle
  { -- | Insert components into an archetype.
    forall (m :: * -> *).
DynamicBundle m
-> EntityID -> Archetype m -> (Archetype m, Access m ())
runDynamicBundle :: EntityID -> Archetype m -> (Archetype m, Access m ())
  }

instance (Monad m) => Semigroup (DynamicBundle m) where
  DynamicBundle EntityID -> Archetype m -> (Archetype m, Access m ())
d1 <> :: DynamicBundle m -> DynamicBundle m -> DynamicBundle m
<> DynamicBundle EntityID -> Archetype m -> (Archetype m, Access m ())
d2 = (EntityID -> Archetype m -> (Archetype m, Access m ()))
-> DynamicBundle m
forall (m :: * -> *).
(EntityID -> Archetype m -> (Archetype m, Access m ()))
-> DynamicBundle m
DynamicBundle EntityID -> Archetype m -> (Archetype m, Access m ())
go
    where
      go :: EntityID -> Archetype m -> (Archetype m, Access m ())
go EntityID
eId Archetype m
arch =
        let (Archetype m
arch', Access m ()
hook1) = EntityID -> Archetype m -> (Archetype m, Access m ())
d1 EntityID
eId Archetype m
arch
            (Archetype m
arch'', Access m ()
hook2) = EntityID -> Archetype m -> (Archetype m, Access m ())
d2 EntityID
eId Archetype m
arch'
         in (Archetype m
arch'', Access m ()
hook1 Access m () -> Access m () -> Access m ()
forall a b. Access m a -> Access m b -> Access m b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Access m ()
hook2)

instance (Monad m) => Monoid (DynamicBundle m) where
  mempty :: DynamicBundle m
mempty = (EntityID -> Archetype m -> (Archetype m, Access m ()))
-> DynamicBundle m
forall (m :: * -> *).
(EntityID -> Archetype m -> (Archetype m, Access m ()))
-> DynamicBundle m
DynamicBundle (\EntityID
_ Archetype m
arch -> (Archetype m
arch, () -> Access m ()
forall a. a -> Access m a
forall (m :: * -> *) a. Monad m => a -> m a
return ()))

instance (Monad m) => MonoidDynamicBundle m (DynamicBundle m) where
  dynBundle :: forall c. Component m c => ComponentID -> c -> DynamicBundle m
dynBundle ComponentID
cId c
a = (EntityID -> Archetype m -> (Archetype m, Access m ()))
-> DynamicBundle m
forall (m :: * -> *).
(EntityID -> Archetype m -> (Archetype m, Access m ()))
-> DynamicBundle m
DynamicBundle (\EntityID
eId Archetype m
arch -> EntityID
-> ComponentID -> c -> Archetype m -> (Archetype m, Access m ())
forall (m :: * -> *) a.
Component m a =>
EntityID
-> ComponentID -> a -> Archetype m -> (Archetype m, Access m ())
insertComponent EntityID
eId ComponentID
cId c
a Archetype m
arch)
  dynBundleUntracked :: forall c. Component m c => ComponentID -> c -> DynamicBundle m
dynBundleUntracked ComponentID
cId c
a = (EntityID -> Archetype m -> (Archetype m, Access m ()))
-> DynamicBundle m
forall (m :: * -> *).
(EntityID -> Archetype m -> (Archetype m, Access m ()))
-> DynamicBundle m
DynamicBundle (\EntityID
eId Archetype m
arch -> (EntityID -> ComponentID -> c -> Archetype m -> Archetype m
forall (m :: * -> *) a.
Component m a =>
EntityID -> ComponentID -> a -> Archetype m -> Archetype m
insertComponentUntracked EntityID
eId ComponentID
cId c
a Archetype m
arch, () -> Access m ()
forall a. a -> Access m a
forall (m :: * -> *) a. Monad m => a -> m a
return ()))