content: {-# LANGUAGE NamedFieldPuns    #-}
  {-# LANGUAGE OverloadedStrings #-}
  
  module Hi.Option
      (
        buildOption
      ) where
  
  import           Hi.CommandLineOption (CommandLineOption)
  import qualified Hi.CommandLineOption as CommandLineOption
  import           Hi.Config            (parseConfig)
  import qualified Hi.Git               as Git
  import           Hi.Types
  
  import           Control.Applicative
  import           Control.Monad
  import           Data.Char            (toUpper)
  import           Data.Maybe           (catMaybes, fromMaybe)
  import           Data.Time.Calendar   (toGregorian)
  import           Data.Time.Clock      (getCurrentTime, utctDay)
  
  buildOption :: CommandLineOption -> IO Option
  buildOption copt = do
      let moduleName = modularize $ CommandLineOption.packageName copt
      year <- getCurrentYear
      author <- guessAuthor
      email <- guessEmail
      let mGitInit = if CommandLineOption.initializeGitRepository copt
                       then Just "git init && git add . && git commit -m \"Initial commit\""
                       else Nothing
          afterCommands = catMaybes [ mGitInit
                                    , CommandLineOption.afterCommand copt
                                    ]
          packageName   = CommandLineOption.packageName copt
      return Option { moduleName     = fromMaybe moduleName $ CommandLineOption.moduleName copt
                    , packageName    = packageName
                    , directoryName  = fromMaybe packageName $ CommandLineOption.directoryName copt
                    , author         = author
                    , email          = email
                    , templateSource = FromRepo $ CommandLineOption.repository copt
                    , year           = year
                    , afterCommands  = afterCommands
                    }
    where
      lookupConfig :: String -> IO (Maybe String)
      lookupConfig k = case CommandLineOption.configFilePath copt of
                         Just path -> lookup k . parseConfig <$> readFile path
                         Nothing   -> return Nothing
      choice :: [IO (Maybe String)] -> IO (Maybe String)
      choice xs = foldr1 mplus <$> sequence xs
      guessAuthor :: IO String
      guessAuthor = do
        mc <- choice [ return $ CommandLineOption.author copt
                     , lookupConfig "author"
                     , Git.config "user.name"
                     ]
        case mc of
          Just x -> return x
          Nothing -> fail "No user specified"
      guessEmail :: IO String
      guessEmail  = do
        mc <- choice [ return $ CommandLineOption.email copt
                     , lookupConfig "email"
                     , Git.config "user.email"
                     ]
        case mc of
          Just x -> return x
          Nothing -> fail "No email specified"
      getCurrentYear :: IO String
      getCurrentYear  = do
          (y,_,_) <- (toGregorian . utctDay) <$> getCurrentTime
          return $ show y
  
  -- | Capitalize words and connect them with periods
  --
  -- >>> modularize "package"
  -- "Package"
  --
  -- >>> modularize "package-name"
  -- "Package.Name"
  --
  -- >>> modularize "another-package-name"
  -- "Another.Package.Name"
  --
  modularize :: String -> String
  modularize []     = []
  modularize [x]    = [toUpper x]
  modularize (x:xs) = toUpper x : rest xs
    where
      rest []       = []
      rest ('-':ys) = '.' : modularize ys
      rest (y:ys)   = y:rest ys
  