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

import qualified CabalGild.Unstable.Type.Flag as Flag
import qualified CabalGild.Unstable.Type.Input as Input
import qualified CabalGild.Unstable.Type.Leniency as Leniency
import qualified CabalGild.Unstable.Type.Mode as Mode
import qualified CabalGild.Unstable.Type.Optional as Optional
import qualified CabalGild.Unstable.Type.Output as Output
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 -> Optional Leniency
crlf :: Optional.Optional Leniency.Leniency,
    Config -> Optional Bool
help :: Optional.Optional Bool,
    Config -> Optional Input
input :: Optional.Optional Input.Input,
    Config -> Optional Mode
mode :: Optional.Optional Mode.Mode,
    Config -> Optional Output
output :: Optional.Optional Output.Output,
    Config -> Optional FilePath
stdin :: Optional.Optional FilePath,
    Config -> Optional Bool
version :: Optional.Optional 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
    { crlf :: Optional Leniency
crlf = Optional Leniency
forall a. Optional a
Optional.Default,
      help :: Optional Bool
help = Optional Bool
forall a. Optional a
Optional.Default,
      input :: Optional Input
input = Optional Input
forall a. Optional a
Optional.Default,
      mode :: Optional Mode
mode = Optional Mode
forall a. Optional a
Optional.Default,
      output :: Optional Output
output = Optional Output
forall a. Optional a
Optional.Default,
      stdin :: Optional FilePath
stdin = Optional FilePath
forall a. Optional a
Optional.Default,
      version :: Optional Bool
version = Optional Bool
forall a. Optional a
Optional.Default
    }

-- | 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.CRLF FilePath
s -> do
    Leniency
l <- FilePath -> m Leniency
forall (m :: * -> *). MonadThrow m => FilePath -> m Leniency
Leniency.fromString FilePath
s
    Config -> m Config
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Config
config {crlf = Optional.Specific l}
  Flag.Help Bool
b -> Config -> m Config
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Config
config {help = Optional.Specific b}
  Flag.Input FilePath
s -> Config -> m Config
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Config
config {input = Optional.Specific $ Input.fromString s}
  Flag.IO FilePath
s ->
    Config -> m Config
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
      Config
config
        { input = Optional.Specific $ Input.fromString s,
          output = Optional.Specific $ Output.fromString 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 = Optional.Specific m}
  Flag.Output FilePath
s -> Config -> m Config
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Config
config {output = Optional.Specific $ Output.fromString 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 = Optional.Specific 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 = Optional.Specific 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