    {-# LANGUAGE FlexibleContexts          #-}
    {-# LANGUAGE NoMonomorphismRestriction #-}

    module Yi.Paths ( getEvaluatorContextFilename
                    , getConfigFilename
                    , getConfigModules
                    , getPersistentStateFilename
                    , getConfigDir
                    , getConfigPath
                    , getCustomConfigPath
                    , getDataPath
                    ) where

    import           Control.Monad.Base             (MonadBase, liftBase)
    import           System.Directory               (createDirectoryIfMissing,
                                                     doesDirectoryExist,
                                                     getAppUserDataDirectory)
    import qualified System.Environment.XDG.BaseDir as XDG (getUserConfigDir, getUserDataDir)
    import           System.FilePath                ((</>))

    appUserDataCond ::(MonadBase IO m) => (String -> IO FilePath) -> m FilePath
    appUserDataCond :: forall (m :: * -> *).
    MonadBase IO m =>
    (String -> IO String) -> m String
    appUserDataCond String -> IO String
    dirQuery = IO String -> m String
    forall α. IO α -> m α
    forall (b :: * -> *) (m :: * -> *) α. MonadBase b m => b α -> m α
    liftBase (IO String -> m String) -> IO String -> m String
    forall a b. (a -> b) -> a -> b
    $
      do oldDir <- String -> IO String
    getAppUserDataDirectory String
    "yi"
         newDir <- dirQuery "yi"
         oldDirExists <- doesDirectoryExist oldDir
         newDirExists <- doesDirectoryExist newDir
         if newDirExists -- overrides old-style
            then return newDir
            else if oldDirExists -- old-style exists, use it
                   then return oldDir
                   else do createDirectoryIfMissing True newDir -- none exists, use new style, but create it
                           return newDir

    getConfigDir ::(MonadBase IO m) => m FilePath
    getConfigDir :: forall (m :: * -> *). MonadBase IO m => m String
    getConfigDir = (String -> IO String) -> m String
    forall (m :: * -> *).
    MonadBase IO m =>
    (String -> IO String) -> m String
    appUserDataCond String -> IO String
    XDG.getUserConfigDir

    getDataDir ::(MonadBase IO m) => m FilePath
    getDataDir :: forall (m :: * -> *). MonadBase IO m => m String
    getDataDir = (String -> IO String) -> m String
    forall (m :: * -> *).
    MonadBase IO m =>
    (String -> IO String) -> m String
    appUserDataCond String -> IO String
    XDG.getUserDataDir

    -- | Given a path relative to application data directory,
    --   this function finds a path to a given data file.
    getDataPath :: (MonadBase IO m) => FilePath -> m FilePath
    getDataPath :: forall (m :: * -> *). MonadBase IO m => String -> m String
    getDataPath String
    fp = (String -> String) -> m String -> m String
    forall a b. (a -> b) -> m a -> m b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap (String -> String -> String
    </> String
    fp) m String
    forall (m :: * -> *). MonadBase IO m => m String
    getDataDir

    -- | Given a path relative to application configuration directory,
    --   this function finds a path to a given configuration file.
    getConfigPath :: MonadBase IO m => FilePath -> m FilePath
    getConfigPath :: forall (m :: * -> *). MonadBase IO m => String -> m String
    getConfigPath = m String -> String -> m String
    forall (m :: * -> *).
    MonadBase IO m =>
    m String -> String -> m String
    getCustomConfigPath m String
    forall (m :: * -> *). MonadBase IO m => m String
    getConfigDir

    -- | Given an action that retrieves config path, and a path relative to it,
    -- this function joins the two together to create a config file path.
    getCustomConfigPath :: MonadBase IO m => m FilePath -> FilePath -> m FilePath
    getCustomConfigPath :: forall (m :: * -> *).
    MonadBase IO m =>
    m String -> String -> m String
    getCustomConfigPath m String
    cd String
    fp = (String -> String -> String
    </> String
    fp) (String -> String) -> m String -> m String
    forall a b. (a -> b) -> m a -> m b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    `fmap` m String
    cd

    -- Note: Dyre also uses XDG cache dir - that would be:
    --getCachePath = getPathHelper XDG.getUserCacheDirectory

    -- Below are all points that are used in Yi code (to keep it clean.)
    getEvaluatorContextFilename, getConfigFilename, getConfigModules,
        getPersistentStateFilename :: (MonadBase IO m) => m FilePath

    -- | Get Yi master configuration script.
    getConfigFilename :: forall (m :: * -> *). MonadBase IO m => m String
    getConfigFilename = String -> m String
    forall (m :: * -> *). MonadBase IO m => String -> m String
    getConfigPath String
    "yi.hs"

    getConfigModules :: forall (m :: * -> *). MonadBase IO m => m String
    getConfigModules = String -> m String
    forall (m :: * -> *). MonadBase IO m => String -> m String
    getConfigPath String
    "modules"

    -- | Get path to Yi history that stores state between runs.
    getPersistentStateFilename :: forall (m :: * -> *). MonadBase IO m => m String
    getPersistentStateFilename = String -> m String
    forall (m :: * -> *). MonadBase IO m => String -> m String
    getDataPath String
    "history"

    -- | Get path to environment file that defines namespace used by Yi
    --   command evaluator.
    getEvaluatorContextFilename :: forall (m :: * -> *). MonadBase IO m => m String
    getEvaluatorContextFilename = String -> m String
    forall (m :: * -> *). MonadBase IO m => String -> m String
    getConfigPath (String -> m String) -> String -> m String
    forall a b. (a -> b) -> a -> b
    $ String
    "local" String -> String -> String
    </> String
    "Env.hs"