{-| This module exports the 'Plan' Applicative.

>>> :{
    let example :: Plan String [Int] IO () ()
        example = 
            step "(a)" (step "(a.a)" (foretell [1] *>
                                      plan (threadDelay 1e6)) *>
                        step "(a.a)" (foretell [2] *>
                                      plan (threadDelay 1e6))) *>
            step "(b)" (step "(b.a)" (foretell [3] *>
                                      plan (threadDelay 1e6)) *>
                        step "(b.b)" (foretell [4] *>
                                      plan (threadDelay 1e6)))
    in 
    bifoldMap id (foldMap Prelude.show) (getSteps example)
:}
"(a)(a.a)1(a.a)2(b)(b.a)3(b.b)4"

Some possible use cases:

- Inspect the steps of an existing 'Plan' from @ghci@ using 'getSteps',
  'toForest' and 'Data.Tree.drawForest', as a form of documentation.

- If your script requires files that must be already present in the file
  system, use 'foretell' to annotate each 'Plan' action that requires a file,
  then get the global list of files using 'getSteps' and 'foldMap', and check
  that they all exist before running the 'Plan' with 'runPlan'.

- Get progress updates for your script by declaring (possibly nested) steps
  with 'step', running the 'Plan' with 'runPlan', and providing a notification
  callback with 'onTick', probably using 'tickToForest' and
  'Data.Tree.drawForest' to render the updates.

- Run a 'Plan' with 'runPlan', use 'instants' an 'toForest' on the resulting
  'Timeline' to get the durations of each step, then use 'zipSteps' on the same 
  'Plan' and
  run it again. Now whenever a step finishes we can know if it took more or
  less than in the previous execution.

-}
module Control.Plan (
                    -- * Constructing plans
                     Plan
                    ,plan
                    ,planIO
                    ,planK
                    ,planKIO
                    -- ** Declaring steps and annotations
                    ,step
                    ,skippable
                    ,foretell
                    -- * Analyzing plans
                    ,getSteps
                    ,Steps
                    ,mandatoriness
                    ,Mandatoriness(..)
                    ,foldSteps
                    -- * Adapting plans
                    -- $adapting
                    ,bimapSteps
                    ,zoomSteps
                    ,zipSteps
                    ,hoistPlan
                    -- * Running plans
                    ,unliftPlan
                    ,runPlan
                    ,onTick
                    ,tickToForest
                    ,Tick(..)
                    ,Context(..)
                    ,Progress(..)
                    ,Timeline
                    ,instants
                    ,foldTimeline
                    -- ** Running arrow plans
                    ,unliftPlanK
                    ,runPlanK
                    -- * The Lasagna typeclass
                    ,Lasagna(..)
                    -- * Re-exports
                    ,Data.Bifunctor.bimap
                    ,Data.Bifoldable.bifoldMap
                    ,Data.Bitraversable.bitraverse
                    ,Control.Comonad.extract
                    -- $extract
                    ,Streaming.hoist
                    ,Streaming.Prelude.effects
                    -- $effects
                    ) where

import Data.Bifunctor
import Data.Bifoldable
import Data.Bitraversable
import Control.Comonad
import Streaming
import Streaming.Prelude

import Control.Plan.Core

{- $setup

>>> :set -XNumDecimals
>>> import Control.Applicative
>>> import Control.Plan
>>> import Control.Concurrent(threadDelay)

-}

{- $adapting

   Sometimes, we might need to mix 'Plan's for which step tags and annotations
   are of different types. These functions help with that.

-}

{- $extract
   Besides its usefulness with 'Timeline', 'extract' lets you get the head of a
   'NonEmpty' or the second element of a tuple.
-}

{- $effects
   'effects' lets you ignore all the update notifications while running a plan,
   when you are only interested in the final 'Timeline' and the result.
-}