content: {-# LANGUAGE OverloadedStrings #-}
  
  -- | Things related to HIndent configuration.
  module HIndent.Config
    ( Config(..)
    , defaultConfig
    , getConfig
    ) where
  
  import Control.Applicative
  import Data.Int
  import Data.Maybe
  import Data.Yaml
  import qualified Data.Yaml as Y
  import HIndent.LanguageExtension.Conversion
  import HIndent.LanguageExtension.Types
  import qualified HIndent.Path.Find as Path
  import Path
  import qualified Path.IO as Path
  
  -- | Configurations shared among the different styles. Styles may pay
  -- attention to or completely disregard this configuration.
  data Config = Config
    { configMaxColumns :: !Int64 -- ^ Maximum columns to fit code into ideally.
    , configIndentSpaces :: !Int64 -- ^ How many spaces to indent?
    , configTrailingNewline :: !Bool -- ^ End with a newline.
    , configSortImports :: !Bool -- ^ Sort imports in groups.
    , configLineBreaks :: [String] -- ^ Break line when meets these operators.
    , configExtensions :: [Extension]
        -- ^ Extra language extensions enabled by default.
    }
  
  instance FromJSON Config where
    parseJSON (Y.Object v) =
      Config
        <$> fmap
              (fromMaybe (configMaxColumns defaultConfig))
              (v Y..:? "line-length")
        <*> fmap
              (fromMaybe (configIndentSpaces defaultConfig))
              (v Y..:? "indent-size" <|> v Y..:? "tab-size")
        <*> fmap
              (fromMaybe (configTrailingNewline defaultConfig))
              (v Y..:? "force-trailing-newline")
        <*> fmap
              (fromMaybe (configSortImports defaultConfig))
              (v Y..:? "sort-imports")
        <*> fmap
              (fromMaybe (configLineBreaks defaultConfig))
              (v Y..:? "line-breaks")
        <*> (traverse convertExt . fromMaybe [] =<< v Y..:? "extensions")
      where
        convertExt x =
          case strToExt x of
            Just x' -> pure x'
            Nothing -> error $ "Unknown extension: " ++ show x
    parseJSON _ = fail "Expected Object for Config value"
  
  -- | Default style configuration.
  defaultConfig :: Config
  defaultConfig =
    Config
      { configMaxColumns = 80
      , configIndentSpaces = 2
      , configTrailingNewline = True
      , configSortImports = True
      , configLineBreaks = []
      , configExtensions = []
      }
  
  -- | Read config from a config file, or return 'defaultConfig'.
  getConfig :: IO Config
  getConfig = do
    cur <- Path.getCurrentDir
    homeDir <- Path.getHomeDir
    mfile <-
      Path.findFileUp
        cur
        ((== ".hindent.yaml") . toFilePath . filename)
        (Just homeDir)
    case mfile of
      Nothing -> return defaultConfig
      Just file -> do
        result <- Y.decodeFileEither (toFilePath file)
        case result of
          Left e -> error (show e)
          Right config -> return config
  