module Engine.ReactiveBanana.Utils where

import RIO

import Reactive.Banana qualified as RB
import Reactive.Banana.Frameworks qualified as RBF

{-# INLINE (<@@>) #-}
(<@@>) :: RB.Event a -> RB.Behavior (a -> b) -> RB.Event b
<@@> :: forall a b. Event a -> Behavior (a -> b) -> Event b
(<@@>) = (Behavior (a -> b) -> Event a -> Event b)
-> Event a -> Behavior (a -> b) -> Event b
forall a b c. (a -> b -> c) -> b -> a -> c
flip Behavior (a -> b) -> Event a -> Event b
forall a b. Behavior (a -> b) -> Event a -> Event b
(RB.<@>)

{-# INLINE ($>>) #-}
($>>) :: {- forall {a} {b} .  -}RB.Event a -> RB.Event b -> RB.Event ()
Event a
a $>> :: forall a b. Event a -> Event b -> Event ()
$>> Event b
b =
  (a -> ())
-> (b -> ()) -> (a -> b -> ()) -> Event a -> Event b -> Event ()
forall a c b.
(a -> c)
-> (b -> c) -> (a -> b -> c) -> Event a -> Event b -> Event c
RB.mergeWith
    (() -> a -> ()
forall a b. a -> b -> a
const ())
    (() -> b -> ()
forall a b. a -> b -> a
const ())
    (\a
_ b
_ -> ())
    Event a
a
    Event b
b

delay :: RB.Event a -> RBF.MomentIO (RB.Event a)
delay :: forall a. Event a -> MomentIO (Event a)
delay Event a
e = do
  (Event a
delayed, Handler a
fire) <- MomentIO (Event a, Handler a)
forall a. MomentIO (Event a, Handler a)
RBF.newEvent
  Event (IO ()) -> MomentIO ()
RBF.reactimate (Event (IO ()) -> MomentIO ()) -> Event (IO ()) -> MomentIO ()
forall a b. (a -> b) -> a -> b
$ Handler a -> Event a -> Event (IO ())
forall a b. (a -> b) -> Event a -> Event b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Handler a
fire Event a
e
  pure Event a
delayed

delayOnce :: RB.Event a -> RBF.MomentIO (RB.Event a)
delayOnce :: forall a. Event a -> MomentIO (Event a)
delayOnce Event a
e = Event a -> MomentIO (Event a)
forall a. Event a -> MomentIO (Event a)
delay Event a
e MomentIO (Event a)
-> (Event a -> MomentIO (Event a)) -> MomentIO (Event a)
forall a b. MomentIO a -> (a -> MomentIO b) -> MomentIO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Event a -> MomentIO (Event a)
forall (m :: * -> *) a. MonadMoment m => Event a -> m (Event a)
RB.once

lockstep :: a -> RB.Event a -> RBF.MomentIO (RB.Event a, RB.Behavior a)
lockstep :: forall a. a -> Event a -> MomentIO (Event a, Behavior a)
lockstep a
initial Event a
e = do
  Behavior a
b <- a -> Event a -> MomentIO (Behavior a)
forall (m :: * -> *) a.
MonadMoment m =>
a -> Event a -> m (Behavior a)
RB.stepper a
initial Event a
e
  Event a
e' <- Event a -> MomentIO (Event a)
forall a. Event a -> MomentIO (Event a)
delay Event a
e
  pure (Event a
e', Behavior a
b)

accumE_ :: RB.MonadMoment m => [RB.Event a] -> m (RB.Event a)
accumE_ :: forall (m :: * -> *) a. MonadMoment m => [Event a] -> m (Event a)
accumE_ = a -> Event (a -> a) -> m (Event a)
forall (m :: * -> *) a.
MonadMoment m =>
a -> Event (a -> a) -> m (Event a)
RB.accumE a
forall a. HasCallStack => a
undefined (Event (a -> a) -> m (Event a))
-> ([Event a] -> Event (a -> a)) -> [Event a] -> m (Event a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Event a] -> Event (a -> a)
forall a. [Event a] -> Event (a -> a)
unionsConst

unionsConst :: [RB.Event a] -> RB.Event (a -> a)
unionsConst :: forall a. [Event a] -> Event (a -> a)
unionsConst = [Event (a -> a)] -> Event (a -> a)
forall a. [Event (a -> a)] -> Event (a -> a)
RB.unions ([Event (a -> a)] -> Event (a -> a))
-> ([Event a] -> [Event (a -> a)]) -> [Event a] -> Event (a -> a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Event a -> Event (a -> a)) -> [Event a] -> [Event (a -> a)]
forall a b. (a -> b) -> [a] -> [b]
map ((a -> a -> a) -> Event a -> Event (a -> a)
forall a b. (a -> b) -> Event a -> Event b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap a -> a -> a
forall a b. a -> b -> a
const)

-- | Only pass events when their value changes.
--
-- The event is delayed for behavior value to match current value.
filterChange
  :: Eq a
  => a
  -> RB.Event a
  -> RBF.MomentIO (RB.Event (a, a), RB.Behavior a)
filterChange :: forall a.
Eq a =>
a -> Event a -> MomentIO (Event (a, a), Behavior a)
filterChange a
initial Event a
e = do
  Behavior a
b <- a -> Event a -> MomentIO (Behavior a)
forall (m :: * -> *) a.
MonadMoment m =>
a -> Event a -> m (Behavior a)
RB.stepper a
initial Event a
e
  let
    changeE :: Event (a, a)
changeE = Event (Maybe (a, a)) -> Event (a, a)
forall a. Event (Maybe a) -> Event a
RB.filterJust (Event (Maybe (a, a)) -> Event (a, a))
-> Event (Maybe (a, a)) -> Event (a, a)
forall a b. (a -> b) -> a -> b
$
      Event a
e Event a -> Behavior (a -> Maybe (a, a)) -> Event (Maybe (a, a))
forall a b. Event a -> Behavior (a -> b) -> Event b
<@@> do
        a
old <- Behavior a
b
        pure \a
new ->
          if a
old a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
new then
            Maybe (a, a)
forall a. Maybe a
Nothing
          else
            (a, a) -> Maybe (a, a)
forall a. a -> Maybe a
Just (a
old, a
new)
  Event (a, a)
syncE <- Event (a, a) -> MomentIO (Event (a, a))
forall a. Event a -> MomentIO (Event a)
delay Event (a, a)
changeE
  pure (Event (a, a)
syncE, Behavior a
b)