content: {-# language TemplateHaskell #-}
  module Eve.Internal.AppState
    ( AppState(..)
    , App
    , Action
    , ActionM
    , AppM
  
    , exit
    , isExiting
  
    , asyncQueue
    ) where
  
  import Eve.Internal.Actions
  import Eve.Internal.States
  import Control.Lens
  import Data.Default
  import Data.Typeable
  import Control.Concurrent.Chan
  
  -- | A basic default state which underlies 'App' Contains only a map of 'States'.
  data AppState = AppState
    { _baseStates :: States
    }
  makeLenses ''AppState
  
  instance Default AppState where
    def = AppState mempty
  
  instance HasStates AppState where
    states = baseStates
  
  instance HasEvents AppState where
  
  newtype AsyncQueue base m = AsyncQueue
    { _asyncQueue' :: Maybe (Chan (AppT base m ()))
    } deriving Typeable
  makeLenses ''AsyncQueue
  
  instance Default (AsyncQueue base m) where
    def = AsyncQueue Nothing
  
  -- | Accesses a queue for dispatching async actions.
  asyncQueue :: (HasStates s, Typeable m, Typeable base) => Lens' s (Maybe (Chan (AppT base m ())))
  asyncQueue = stateLens.asyncQueue'
  
  newtype Exiting =
    Exiting Bool
  
  instance Default Exiting where
    def = Exiting False
  
  -- | Tells the application to quit. This triggers 'onExit' listeners
  -- following the current event loop.
  exit :: (Monad m, HasStates s) => ActionT s zoomed m ()
  exit = runApp $ stateLens .= Exiting True
  
  -- | Checks whether we're in the process of exiting.
  isExiting :: (Monad m, HasStates s) => ActionT s zoomed m Bool
  isExiting = runApp $ do
    Exiting b <- use stateLens
    return b
  
  
  -- | An 'App' is a base level monad which operates over your main application
  -- state. You may call 'runAction' inside an app to run 'Action's over other states.
  type App a = AppT AppState IO a
  
  -- | An 'Action' is a monad over some zoomed in state, they are run inside 'App' using
  -- 'runAction'. For example an 'Action' which operates over a String somewhere in your app state
  -- would be written as:
  --
  -- @
  -- alterString :: 'Action' String ()
  -- @
  type Action state a = ActionT AppState state IO a
  
  -- | A more general version of 'App' which lets you specify the underlying monad.
  type AppM m a = AppT AppState m a
  
  -- | A more general version of 'Action' which lets you to specify the underlying monad.
  type ActionM s m a = ActionT AppState s m a
  