-- | This module defines the 'Config' data type.
module CabalGild.Type.Config where

import qualified CabalGild.Type.Flag as Flag
import qualified CabalGild.Type.Mode as Mode
import qualified Control.Monad as Monad
import qualified Control.Monad.Catch as Exception

-- | This data type represents the configuration for the command line utility.
-- Each field typically corresponds to a flag.
data Config = Config
  { Config -> Bool
help :: Bool,
    Config -> Maybe FilePath
input :: Maybe FilePath,
    Config -> Mode
mode :: Mode.Mode,
    Config -> Maybe FilePath
output :: Maybe FilePath,
    Config -> FilePath
stdin :: FilePath,
    Config -> Bool
version :: Bool
  }
  deriving (Config -> Config -> Bool
(Config -> Config -> Bool)
-> (Config -> Config -> Bool) -> Eq Config
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Config -> Config -> Bool
== :: Config -> Config -> Bool
$c/= :: Config -> Config -> Bool
/= :: Config -> Config -> Bool
Eq, Int -> Config -> ShowS
[Config] -> ShowS
Config -> FilePath
(Int -> Config -> ShowS)
-> (Config -> FilePath) -> ([Config] -> ShowS) -> Show Config
forall a.
(Int -> a -> ShowS) -> (a -> FilePath) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Config -> ShowS
showsPrec :: Int -> Config -> ShowS
$cshow :: Config -> FilePath
show :: Config -> FilePath
$cshowList :: [Config] -> ShowS
showList :: [Config] -> ShowS
Show)

-- | The default config.
initial :: Config
initial :: Config
initial =
  Config
    { help :: Bool
help = Bool
False,
      input :: Maybe FilePath
input = Maybe FilePath
forall a. Maybe a
Nothing,
      mode :: Mode
mode = Mode
Mode.Format,
      output :: Maybe FilePath
output = Maybe FilePath
forall a. Maybe a
Nothing,
      stdin :: FilePath
stdin = FilePath
".",
      version :: Bool
version = Bool
False
    }

-- | Applies a flag to the config, returning the new config.
applyFlag :: (Exception.MonadThrow m) => Config -> Flag.Flag -> m Config
applyFlag :: forall (m :: * -> *). MonadThrow m => Config -> Flag -> m Config
applyFlag Config
config Flag
flag = case Flag
flag of
  Flag.Help Bool
b -> Config -> m Config
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Config
config {help = b}
  Flag.Input FilePath
s -> case FilePath
s of
    FilePath
"-" -> Config -> m Config
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Config
config {input = Nothing}
    FilePath
_ -> Config -> m Config
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Config
config {input = Just s}
  Flag.Mode FilePath
s -> do
    Mode
m <- FilePath -> m Mode
forall (m :: * -> *). MonadThrow m => FilePath -> m Mode
Mode.fromString FilePath
s
    Config -> m Config
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Config
config {mode = m}
  Flag.Output FilePath
s -> case FilePath
s of
    FilePath
"-" -> Config -> m Config
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Config
config {output = Nothing}
    FilePath
_ -> Config -> m Config
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Config
config {output = Just s}
  Flag.Stdin FilePath
s -> Config -> m Config
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Config
config {stdin = s}
  Flag.Version Bool
b -> Config -> m Config
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Config
config {version = b}

-- | Converts a list of flags into a config by starting with 'initial' and
-- repeatedly calling 'applyFlag'.
fromFlags :: (Exception.MonadThrow m) => [Flag.Flag] -> m Config
fromFlags :: forall (m :: * -> *). MonadThrow m => [Flag] -> m Config
fromFlags = (Config -> Flag -> m Config) -> Config -> [Flag] -> m Config
forall (t :: * -> *) (m :: * -> *) b a.
(Foldable t, Monad m) =>
(b -> a -> m b) -> b -> t a -> m b
Monad.foldM Config -> Flag -> m Config
forall (m :: * -> *). MonadThrow m => Config -> Flag -> m Config
applyFlag Config
initial