# LANGUAGE DeriveGeneric #
# LANGUAGE FlexibleContexts #
# LANGUAGE RecordWildCards #
{-# LANGUAGE StrictData #-}
# LANGUAGE NoImplicitPrelude #

-- |
-- Module      : Headroom.Config.Global
-- Description : Global configutation
  Copyright    : ( c ) 2019 - 2022  
-- License     : BSD-3-Clause
-- Maintainer  : 
-- Stability   : experimental
-- Portability : POSIX
--
-- /Global configuration/ is configuration shared between all /Headroom/ instances
-- and it's located in user's home directory.
module Headroom.Config.Global
    ( GlobalConfig (..)
    , UpdaterConfig (..)
    , initGlobalConfigIfNeeded
    , loadGlobalConfig
    , parseGlobalConfig
    , globalConfigPath
    )
where

import Data.Aeson
    ( FromJSON (..)
    , genericParseJSON
    )
import qualified Data.Yaml as Y
import Headroom.Data.Has
    ( Has (..)
    , HasRIO
    )
import Headroom.Data.Serialization (aesonOptions)
import Headroom.Embedded (defaultGlobalConfig)
import Headroom.IO.FileSystem (FileSystem (..))
import Headroom.Meta
    ( globalConfigDirName
    , globalConfigFileName
    )
import RIO
import qualified RIO.ByteString as B
import RIO.FilePath ((</>))

---------------------------------  DATA TYPES  ---------------------------------

-- | Data type representing updater configuration.
data UpdaterConfig = UpdaterConfig
    { ucCheckForUpdates :: Bool
    -- ^ whether to check for updates
    , ucUpdateIntervalDays :: Integer
    -- ^ how ofter check for updates
    }
    deriving (Eq, Generic, Show)

instance FromJSON UpdaterConfig where
    parseJSON = genericParseJSON aesonOptions

-- | Data type representing global configuration options.
data GlobalConfig = GlobalConfig
    { gcUpdates :: UpdaterConfig
    -- ^ config for updater
    }
    deriving (Eq, Generic, Show)

instance FromJSON GlobalConfig where
    parseJSON = genericParseJSON aesonOptions

------------------------------  PUBLIC FUNCTIONS  ------------------------------

-- | Checks if global configuration /YAML/ file is already present and if not,
-- it creates one with default values.
initGlobalConfigIfNeeded :: (HasRIO FileSystem env) => RIO env ()
initGlobalConfigIfNeeded = do
    FileSystem{..} <- viewL
    userDir <- fsGetUserDirectory
    configPath <- globalConfigPath
    whenM (not <$> fsDoesFileExist configPath) $ do
        fsCreateDirectory $ userDir </> globalConfigDirName
        fsWriteFile configPath defaultGlobalConfig

-- | Loads global configuration from /YAML/ file.
loadGlobalConfig :: (HasRIO FileSystem env) => RIO env GlobalConfig
loadGlobalConfig = do
    configPath <- globalConfigPath
    content <- liftIO . B.readFile $ configPath
    Y.decodeThrow content

-- | Parses global configuration /YAML/ file.
parseGlobalConfig :: (MonadThrow m) => ByteString -> m GlobalConfig
parseGlobalConfig = Y.decodeThrow

-- | Path to global configuration /YAML/ file in user's directory.
globalConfigPath :: HasRIO FileSystem env => RIO env FilePath
globalConfigPath = do
    FileSystem{..} <- viewL
    userDir <- fsGetUserDirectory
    pure $ userDir </> globalConfigDirName </> globalConfigFileName

# LANGUAGE StrictData #
 |
 Module      : Headroom.Config.Global
 Description : Global configutation
 License     : BSD-3-Clause
 Maintainer  : 
 Stability   : experimental
 Portability : POSIX

 /Global configuration/ is configuration shared between all /Headroom/ instances
 and it's located in user's home directory.
-------------------------------  DATA TYPES  ---------------------------------
 | Data type representing updater configuration.
 ^ whether to check for updates
 ^ how ofter check for updates
 | Data type representing global configuration options.
 ^ config for updater
----------------------------  PUBLIC FUNCTIONS  ------------------------------
 | Checks if global configuration /YAML/ file is already present and if not,
 it creates one with default values.
 | Loads global configuration from /YAML/ file.
 | Parses global configuration /YAML/ file.
 | Path to global configuration /YAML/ file in user's directory.
# LANGUAGE DeriveGeneric #
# LANGUAGE FlexibleContexts #
# LANGUAGE RecordWildCards #
# LANGUAGE NoImplicitPrelude #

  Copyright    : ( c ) 2019 - 2022  
module Headroom.Config.Global
    ( GlobalConfig (..)
    , UpdaterConfig (..)
    , initGlobalConfigIfNeeded
    , loadGlobalConfig
    , parseGlobalConfig
    , globalConfigPath
    )
where

import Data.Aeson
    ( FromJSON (..)
    , genericParseJSON
    )
import qualified Data.Yaml as Y
import Headroom.Data.Has
    ( Has (..)
    , HasRIO
    )
import Headroom.Data.Serialization (aesonOptions)
import Headroom.Embedded (defaultGlobalConfig)
import Headroom.IO.FileSystem (FileSystem (..))
import Headroom.Meta
    ( globalConfigDirName
    , globalConfigFileName
    )
import RIO
import qualified RIO.ByteString as B
import RIO.FilePath ((</>))


data UpdaterConfig = UpdaterConfig
    { ucCheckForUpdates :: Bool
    , ucUpdateIntervalDays :: Integer
    }
    deriving (Eq, Generic, Show)

instance FromJSON UpdaterConfig where
    parseJSON = genericParseJSON aesonOptions

data GlobalConfig = GlobalConfig
    { gcUpdates :: UpdaterConfig
    }
    deriving (Eq, Generic, Show)

instance FromJSON GlobalConfig where
    parseJSON = genericParseJSON aesonOptions


initGlobalConfigIfNeeded :: (HasRIO FileSystem env) => RIO env ()
initGlobalConfigIfNeeded = do
    FileSystem{..} <- viewL
    userDir <- fsGetUserDirectory
    configPath <- globalConfigPath
    whenM (not <$> fsDoesFileExist configPath) $ do
        fsCreateDirectory $ userDir </> globalConfigDirName
        fsWriteFile configPath defaultGlobalConfig

loadGlobalConfig :: (HasRIO FileSystem env) => RIO env GlobalConfig
loadGlobalConfig = do
    configPath <- globalConfigPath
    content <- liftIO . B.readFile $ configPath
    Y.decodeThrow content

parseGlobalConfig :: (MonadThrow m) => ByteString -> m GlobalConfig
parseGlobalConfig = Y.decodeThrow

globalConfigPath :: HasRIO FileSystem env => RIO env FilePath
globalConfigPath = do
    FileSystem{..} <- viewL
    userDir <- fsGetUserDirectory
    pure $ userDir </> globalConfigDirName </> globalConfigFileName
