-- | This module defines the 'Configuration' type, which is just a
--   wrapper around all of the configuration options we accept on the
--   command line.
--
module Configuration (
  Configuration(..),
  merge_optional )
where

import System.Console.CmdArgs.Default ( Default( def ) )

import qualified OptionalConfiguration as OC (
  OptionalConfiguration(..),
  merge_maybes )

-- | The main configuration data type. This will be passed to most of
--   the important functions once it has been created.
--
data Configuration =
  Configuration {
    database :: Maybe String,
    detail  :: Bool,
    detail_query :: String,
    host :: Maybe String,
    password :: Maybe String,
    port :: Maybe Int,
    summary_query :: String,
    username :: Maybe String }
  deriving (Show)


-- | A Configuration with all of its fields set to their default
--   values.
--
instance Default Configuration where
  def = Configuration {
          database = def,
          detail = def,
          detail_query = def_detail_query,
          host = def,
          password = def,
          port = def,
          summary_query = def_summary_query,
          username = def }
    where
      def_summary_query = "SELECT domain,COUNT(username) " ++
                          "FROM mailbox " ++
                          "GROUP BY domain " ++
                          "ORDER BY domain;"

      def_detail_query = "SELECT domain,username " ++
                         "FROM mailbox " ++
                         "ORDER BY domain;"

-- | Merge a 'Configuration' with an 'OptionalConfiguration'. This is
--   more or less the Monoid instance for 'OptionalConfiguration', but
--   since the two types are different, we have to repeat ourselves.
--
merge_optional :: Configuration
               -> OC.OptionalConfiguration
               -> Configuration
merge_optional cfg opt_cfg =
  Configuration
    (OC.merge_maybes (database cfg) (OC.database opt_cfg))
    (merge (detail cfg) (OC.detail opt_cfg))
    (merge (detail_query cfg) (OC.detail_query opt_cfg))
    (OC.merge_maybes (host cfg) (OC.host opt_cfg))
    (OC.merge_maybes (password cfg) (OC.password opt_cfg))
    (OC.merge_maybes (port cfg) (OC.port opt_cfg))
    (merge (summary_query cfg) (OC.summary_query opt_cfg))
    (OC.merge_maybes (username cfg) (OC.username opt_cfg))
  where
    -- | If the thing on the right is Just something, return that
    --   something, otherwise return the thing on the left.
    merge :: a -> Maybe a -> a
    merge x Nothing  = x
    merge _ (Just y) = y
