module Eve
  (
  -- | This documentation is split into parts based on complexity.
  -- For most applications you'll need only the Simple section. You'll
  -- find useful tools in the Advanced section once you've got a simple app
  -- up and running.

  -- * Simple
  -- | Eve allows you to build your applications incrementally, adding more
  -- complexity as you need it. For this reason, many of the types are more
  -- general than you'll likely need. This can be a bit confusing, but here's
  -- a few tips:
  --
  --    * Both 'Action' and 'App' unify with 'ActionT'. You may use them in place of
  --    'ActionT'. When in doubt, use 'App'.
  --    * When you see vague references to monads @m@ or @n@, you can use 'App' or 'Action' in its place.
  --    * Simple Apps assume that you use the provided 'AppState' and it is
  --      "baked in" to the 'Action' and 'App' types. Wherever you see @'HasStates' s@
  --      you can mentally replace @s@ with 'AppState'.

  -- ** Running your App
  eve_

  -- ** Working with Actions
  , App
  , Action
  , runApp
  , runAction
  , exit

  -- ** Dispatching Events
  , dispatchEvent
  , dispatchEvent_

  -- ** Event Listeners
  , addListener
  , addListener_

  , removeListener

  , Listener
  , ListenerId

  -- ** Asynchronous Helpers
  , asyncEventProvider
  , EventDispatcher

  -- ** Built-in Event Listeners
  , afterInit
  , beforeEvent
  , beforeEvent_
  , afterEvent
  , afterEvent_
  , onExit

  -- ** Working with State
  -- | All application-provided states are stored in the same
  -- Map; keyed by their 'Data.Typeable.TypeRep'. This means that if more than one state
  -- uses the same type then they'll conflict and overwrite each-other (this is less of a
  -- problem than you're probably thinking). This is easily solved by simply
  -- using a newtype around any types you haven't defined yourself.
  -- For example if your application stores a counter as an Int, wrap it in your own custom
  -- @Counter@ newtype when storing it. If you wish to store multiple copies of a given state
  -- simply store them in a list or map, then store that container as your state.
  --
  -- Because states are stored by their 'Data.Typeable.TypeRep', they must
  -- define an instance of 'Data.Typeable.Typeable', In most cases it's
  -- unnecessary, but GHC can derive this for you with @deriving Typeable@.
  --
  -- It is also required for all states to define an instance of
  -- 'Data.Default.Default', this is because accessing an extension which has not
  -- yet been stored will result in the default value.
  --
  -- If there's no default value that makes sense for your type, you can define
  -- a default of 'Data.Maybe.Nothing' and pattern-match on its value when you
  -- access it.
  --
  -- Here's an example of defining your own state:
  --
  -- > data SimpleState = SimpleState
  -- >   { _myString :: String
  -- >   }
  -- > makeLenses ''SimpleState
  -- >
  -- > instance Default SimpleState where
  -- >   def = SimpleState "default"
  , makeStateLens
  , AppState

  -- * Advanced
  -- | This section provides tools which become relevant when working on more
  -- complex apps. You can customize which states you operate over, embed events
  -- in nested states, and choose a custom base monad for the mtl stack.

  , eve
  -- ** Actions
  , AppT
  , ActionT
  , runActionOver

  -- ** States
  , HasStates(..)
  , States
  , stateLens

  -- ** Local Events

  -- | The local versions of the event functions are the same as the others ('dispatchEvent',
  -- 'addListener', 'removeListener') however they operate on a per-state basis.
  -- This means that if you define a custom state which implements 'HasEvents'
  -- then you may use these functions inside an `Action CustomState` to dispatch events
  -- to ONLY the listners within that specific instance of that state. Note that
  -- these listeners and events are distinct on the value level, not just the type level,
  -- so if you have multiple copies of CustomState in your app, they each have their
  -- own disjoint event listeners.
  , HasEvents
  , dispatchLocalEvent
  , dispatchLocalEvent_

  , addLocalListener
  , addLocalListener_

  , removeLocalListener

  -- ** Async
  , asyncActionProvider

  , dispatchEventAsync
  , dispatchActionAsync
  ) where

import Eve.Internal.Run
import Eve.Internal.Actions
import Eve.Internal.Listeners
import Eve.Internal.Async
import Eve.Internal.AppState
import Eve.Internal.States