module System.Console.Action
  (
    Action
  , run
  
  , readerT
  , simple
  , withArgument
  ) where


import qualified System.Console.Argument as Argument

import qualified Control.Monad.Trans.Reader as Reader
import           System.Exit             (exitFailure)


data Action o
  = Action { run :: [String] -> o -> IO () }

readerT :: Reader.ReaderT o IO () -> Action o
readerT f = Action (const $ Reader.runReaderT f)

-- | A simple action, taking no argument.
simple :: IO () -> Action o
simple = Action . const . const

-- | Create an action that takes an argument (non-option).
-- 
-- The type of argument is specified by the first parameter; these values can
-- be obtained from the module "System.Console.Argument".
withArgument :: Argument.Type x -> (x -> Action o) -> Action o
withArgument at f = Action g where
  g (x : xs) = either
    (const . (>> exitFailure) . putStrLn) -- Show errors and exit.
    (\ y -> run (f y) xs)                 -- Argument parsing succeeded; run the action.
    (Argument.parser at (Argument.name at) x)
  g []       = const $ putStrLn $ "Error: missing argument of type " ++ Argument.name at