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


import qualified System.Console.Argument as Argument

import           System.Exit             (exitFailure)


-- | An @Action s@ is an @IO@ action, which may take arguments
-- (\"non-options\") from the command line, and which may use a configuration
-- of type @s@.
data Action c
  = Action
  {
    run :: [String] -> c -> IO ()
  }

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

-- | Create an action that takes an argument (non-option).
-- 
-- The type of argument is specified by the first parameter; such values can
-- be obtained from the module "System.Console.Argument".
withArgument :: Argument.Type x -> (x -> Action c) -> Action c
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 x)
  g []       = const $ putStrLn ("Error: missing argument of type " ++ Argument.name at) >> exitFailure

-- | Create an action that depends on the  program configuration (determined
-- by the configuration file and command line arguments).
usingConfiguration :: (c -> Action c) -> Action c
usingConfiguration f = Action (\ nonOptions settings -> run (f settings) nonOptions settings)