-- |
-- Module: Commander
--
-- re-exports everything defined in @Commander.Params@ and @Commander.Commands@
-- for convenience.
--
module Commander (

    -- * Example Usage
    -- $usage

    module Commander.Params,
    module Commander.Commands
) where

import Commander.Params
import Commander.Commands

-- $usage
--
-- The below header gives us the language extensions and imports we need
-- for basic usage of 'Commander':
--
-- > {-# LANGUAGE DataKinds, ScopedTypeVariables #-}
-- >
-- > module Main where
-- >
-- > import qualified Data.Map as Map
-- > import Commander.Params   (Flag(..), Value(..))
-- > import Commander.Commands (Command(..), commands, command, help, run, evalCommand)
--
-- The next step is to define the various commands that we care to match
-- against, which looks something like this:
--
-- > someCommands :: Command (IO ())
-- > someCommands = commands $ do
-- >
-- >     command "repeat" $ do
-- >
-- >         help "Repeat a string n times"
-- >
-- >         run $
-- >             \(Value str :: Value "value to repeat" String)
-- >              (Flag n :: Flag '["n"] "times to repeat" Int) ->
-- >              sequence_ $ replicate n (putStrLn str)
-- >
-- >     command "calculate" $ do
-- >
-- >         help "perform calculations"
-- >
-- >         command "add" $ do
-- >
-- >             help "add two numbers"
-- >
-- >             run $
-- >                 \(Value n1 :: Value "number 1" Int)
-- >                  (Value n2 :: Value "number 2" Int)
-- >                  (Flag verbose :: Flag '["v", "verbose"] "verbose mode" Bool) ->
-- >                  if verbose
-- >                     then putStrLn $ (show n1) ++ " + " ++ (show n2) ++ " = " ++ (show $ n1 + n2)
-- >                     else putStrLn (show $ n1 + n2)
-- >
-- >         command "multiply" $ do
-- >
-- >             help "multiply two numbers"
-- >
-- >             run $
-- >                 \(Value n1 :: Value "number 1" Int)
-- >                  (Value n2 :: Value "number 2" Int) ->
-- >                  putStrLn $ (show n1) ++ " x " ++ (show n2) ++ " = " ++ (show $ n1 * n2)
-- >
-- >     command "login" $ do
-- >
-- >         help "pretend authentication"
-- >
-- >         run $
-- >             \(Value username :: Value "Username" String)
-- >              (Flag mPassword :: Flag '["p", "password"] "Password" (Maybe String)) -> do
-- >              pass <- case mPassword of
-- >                 Just password -> return password
-- >                 Nothing -> getLine
-- >              putStrLn $ "logging in with username=" ++ username ++ " password=" ++ pass
--
-- Commands can be arbitrary nested, making it super easy to define subcommands as far
-- down as you like.
--
-- Using a couple of pre-baked parameter types from 'Commander.Params', namely 'Value' and 'Flag',
-- we define in the function signature itself additional /values/ and /flags/ that we expect,
-- each fully typed and with help text (the 'Flag' type in addition state which flags it will
-- try to match against).
--
-- If you prefer alternate behaviour to the provided types, it is easy to create your own custom
-- alternatives; it's simply a case of making your custom types instances of a few very basic
-- typeclasses.
--
-- The return types of the provided functions must match, so that we know what we're getting back
-- when we try executing a command; this is the only parameter needed by the 'Command' type.
--
-- Making use of the above, one could do the following:
--
-- > runCommand :: [String] -> [(String,String)] -> Command (IO ()) -> IO ()
-- > runCommand vals flags cmds = case evalCommand vals (Map.fromList flags) cmds of
-- >     Left err -> putStrLn ("Error: " ++ show err)
-- >     Right res -> res
-- >
-- > main :: IO ()
-- > main = do
-- >
-- >     putStrLn "\nRepeat Command:"
-- >     runCommand ["repeat", "hello there"] [("n","2")] someCommands
-- >
-- >     putStrLn "\nAdd numbers:"
-- >     runCommand ["calculate", "add", "12", "13"] [] someCommands
-- >
-- >     putStrLn "\nAdd numbers (verbosely):"
-- >     runCommand ["calculate", "add", "12", "13"] [("verbose", "")] someCommands
-- >
-- >     putStrLn "\nMultiply numbers:"
-- >     runCommand ["calculate", "multiply", "12", "13"] [] someCommands
-- >
-- >     putStrLn "\nPretend Auth (password provided):"
-- >     runCommand ["login", "james"] [("p", "lemons")] someCommands
-- >
-- >     putStrLn "\nPretend Auth (please type a random string):"
-- >     runCommand ["login", "james"] [] someCommands
--
-- Where we first define a function that makes use of 'evalCommand' to match the provided
-- flags and values against a specific command and either run it or return an error, and
-- either prints the error or runs the resulting IO action.
--
-- This library has no opinion on how a text based command is parsed into a path list and
-- 'Map' of flags, and so the user is free to select an approach that works best for them.
--