content: -- | This module defines 'TriggerEvent', which describes actions that may create
  -- new 'Event's that can be triggered from 'IO'.
  {-# LANGUAGE FlexibleInstances #-}
  {-# LANGUAGE FunctionalDependencies #-}
  {-# LANGUAGE UndecidableInstances #-}
  module Reflex.TriggerEvent.Class
    ( TriggerEvent (..)
    ) where
  
  import Reflex.Class
  
  import Control.Monad.Reader
  import Control.Monad.State
  import qualified Control.Monad.State.Strict as Strict
  import Control.Monad.Trans.Maybe (MaybeT)
  
  --TODO: Shouldn't have IO hard-coded
  -- | 'TriggerEvent' represents actions that can create 'Event's that can be
  -- triggered by 'IO' actions.
  class Monad m => TriggerEvent t m | m -> t where
    -- | Create a triggerable 'Event'.  Whenever the resulting function is called,
    -- the resulting 'Event' will fire at some point in the future.  Note that
    -- this may not be synchronous.
    newTriggerEvent :: m (Event t a, a -> IO ())
    -- | Like 'newTriggerEvent', but the callback itself takes another callback,
    -- to be invoked once the requested 'Event' occurrence has finished firing.
    -- This allows synchronous operation.
    newTriggerEventWithOnComplete :: m (Event t a, a -> IO () -> IO ()) --TODO: This and newTriggerEvent should be unified somehow
    -- | Like 'newTriggerEventWithOnComplete', but with setup and teardown.  This
    -- relatively complex type signature allows any external listeners to be
    -- subscribed lazily and then removed whenever the returned 'Event' is no
    -- longer being listened to.  Note that the setup/teardown may happen multiple
    -- times, and there is no guarantee that the teardown will be executed
    -- promptly, or even at all, in the case of program termination.
    newEventWithLazyTriggerWithOnComplete :: ((a -> IO () -> IO ()) -> IO (IO ())) -> m (Event t a)
  
  instance TriggerEvent t m => TriggerEvent t (ReaderT r m) where
    newTriggerEvent = lift newTriggerEvent
    newTriggerEventWithOnComplete = lift newTriggerEventWithOnComplete
    newEventWithLazyTriggerWithOnComplete = lift . newEventWithLazyTriggerWithOnComplete
  
  instance TriggerEvent t m => TriggerEvent t (StateT s m) where
    newTriggerEvent = lift newTriggerEvent
    newTriggerEventWithOnComplete = lift newTriggerEventWithOnComplete
    newEventWithLazyTriggerWithOnComplete = lift . newEventWithLazyTriggerWithOnComplete
  
  instance TriggerEvent t m => TriggerEvent t (Strict.StateT s m) where
    newTriggerEvent = lift newTriggerEvent
    newTriggerEventWithOnComplete = lift newTriggerEventWithOnComplete
    newEventWithLazyTriggerWithOnComplete = lift . newEventWithLazyTriggerWithOnComplete
  
  instance TriggerEvent t m => TriggerEvent t (MaybeT m) where
    newTriggerEvent = lift newTriggerEvent
    newTriggerEventWithOnComplete = lift newTriggerEventWithOnComplete
    newEventWithLazyTriggerWithOnComplete = lift . newEventWithLazyTriggerWithOnComplete
  