    {-# LANGUAGE CPP #-}

    module System.Environment.XDG.BaseDir
        ( getUserDataDir
        , getUserDataFile
        , getUserConfigDir
        , getUserConfigFile
        , getUserCacheDir
        , getUserCacheFile
        , getSystemDataDirs
        , getSystemDataFiles
        , getSystemConfigDirs
        , getSystemConfigFiles
        , getAllDataDirs
        , getAllDataFiles
        , getAllConfigDirs
        , getAllConfigFiles
        ) where

    import Data.Maybe         ( fromMaybe )
    import System.FilePath    ( (</>), splitSearchPath )
    import System.Environment ( getEnvironment, getEnv )
    import Control.Exception    ( try )
    import System.Directory   ( getHomeDirectory )
    import Control.Monad      ( liftM2 )

    #if defined(mingw32_HOST_OS) || defined(__MINGW32__)

    getDefault "XDG_DATA_HOME"   = getEnv "AppData"
    getDefault "XDG_CONFIG_HOME" = userRelative $ "Local Settings"
    getDefault "XDG_CACHE_HOME"  = userRelative $ "Local Settings" </> "Cache"
    getDefault "XDG_DATA_DIRS"   = getEnv "ProgramFiles"
    getDefault "XDG_CONFIG_DIRS" = getEnv "ProgramFiles"
    getDefault _                 = return ""

    #else

    getDefault :: String -> IO String
    getDefault String
    "XDG_DATA_HOME"   = String -> IO String
    userRelative (String -> IO String) -> String -> IO String
    forall a b. (a -> b) -> a -> b
    $ String
    ".local" String -> String -> String
    </> String
    "share"
    getDefault String
    "XDG_CONFIG_HOME" = String -> IO String
    userRelative (String -> IO String) -> String -> IO String
    forall a b. (a -> b) -> a -> b
    $ String
    ".config"
    getDefault String
    "XDG_CACHE_HOME"  = String -> IO String
    userRelative (String -> IO String) -> String -> IO String
    forall a b. (a -> b) -> a -> b
    $ String
    ".cache"
    getDefault String
    "XDG_DATA_DIRS"   = String -> IO String
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (String -> IO String) -> String -> IO String
    forall a b. (a -> b) -> a -> b
    $ String
    "/usr/local/share:/usr/share"
    getDefault String
    "XDG_CONFIG_DIRS" = String -> IO String
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (String -> IO String) -> String -> IO String
    forall a b. (a -> b) -> a -> b
    $ String
    "/etc/xdg"
    getDefault String
    _                 = String -> IO String
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (String -> IO String) -> String -> IO String
    forall a b. (a -> b) -> a -> b
    $ String
    ""

    #endif

    -- | Get the directory for user-specific data files.
    getUserDataDir      :: String -> IO FilePath
    getUserDataDir :: String -> IO String
    getUserDataDir      = String -> String -> IO String
    singleDir String
    "XDG_DATA_HOME"
    -- | Get the directory for user-specific configuration files.
    getUserConfigDir    :: String -> IO FilePath
    getUserConfigDir :: String -> IO String
    getUserConfigDir    = String -> String -> IO String
    singleDir String
    "XDG_CONFIG_HOME"
    -- | Get the directory for user-specific cache files.
    getUserCacheDir     :: String -> IO FilePath
    getUserCacheDir :: String -> IO String
    getUserCacheDir     = String -> String -> IO String
    singleDir String
    "XDG_CACHE_HOME"
    -- | Get a list of the system-wide data directories.
    getSystemDataDirs   :: String -> IO [FilePath]
    getSystemDataDirs :: String -> IO [String]
    getSystemDataDirs   = String -> String -> IO [String]
    multiDirs String
    "XDG_DATA_DIRS"
    -- | Get a list of the system-wide configuration directories.
    getSystemConfigDirs :: String -> IO [FilePath]
    getSystemConfigDirs :: String -> IO [String]
    getSystemConfigDirs = String -> String -> IO [String]
    multiDirs String
    "XDG_CONFIG_DIRS"
    -- | Get a list of all data directories.
    getAllDataDirs      :: String -> IO [FilePath]
    getAllDataDirs :: String -> IO [String]
    getAllDataDirs String
    a    = (String -> [String] -> [String])
    -> IO String -> IO [String] -> IO [String]
    forall (m :: * -> *) a1 a2 r.
    Monad m =>
    (a1 -> a2 -> r) -> m a1 -> m a2 -> m r
    liftM2 (:) (String -> IO String
    getUserDataDir String
    a) (String -> IO [String]
    getSystemDataDirs String
    a)
    -- | Get a list of all configuration directories.
    getAllConfigDirs    :: String -> IO [FilePath]
    getAllConfigDirs :: String -> IO [String]
    getAllConfigDirs String
    a  = (String -> [String] -> [String])
    -> IO String -> IO [String] -> IO [String]
    forall (m :: * -> *) a1 a2 r.
    Monad m =>
    (a1 -> a2 -> r) -> m a1 -> m a2 -> m r
    liftM2 (:) (String -> IO String
    getUserConfigDir String
    a) (String -> IO [String]
    getSystemConfigDirs String
    a)
    -- | Get the path to a specific user data file.
    getUserDataFile          :: String -> String -> IO FilePath
    getUserDataFile :: String -> String -> IO String
    getUserDataFile String
    a String
    f      = (String -> String) -> IO String -> IO String
    forall a b. (a -> b) -> IO a -> IO b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap (String -> String -> String
    </> String
    f) (IO String -> IO String) -> IO String -> IO String
    forall a b. (a -> b) -> a -> b
    $ String -> IO String
    getUserDataDir String
    a
    -- | Get the path to a specific user configuration file.
    getUserConfigFile        :: String -> String -> IO FilePath
    getUserConfigFile :: String -> String -> IO String
    getUserConfigFile String
    a String
    f    = (String -> String) -> IO String -> IO String
    forall a b. (a -> b) -> IO a -> IO b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap (String -> String -> String
    </> String
    f) (IO String -> IO String) -> IO String -> IO String
    forall a b. (a -> b) -> a -> b
    $ String -> IO String
    getUserConfigDir String
    a
    -- | Get the path to a specific user cache file.
    getUserCacheFile         :: String -> String -> IO FilePath
    getUserCacheFile :: String -> String -> IO String
    getUserCacheFile String
    a String
    f     = (String -> String) -> IO String -> IO String
    forall a b. (a -> b) -> IO a -> IO b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap (String -> String -> String
    </> String
    f) (IO String -> IO String) -> IO String -> IO String
    forall a b. (a -> b) -> a -> b
    $ String -> IO String
    getUserCacheDir String
    a
    -- | Get a list of all paths for a specific system data file.
    getSystemDataFiles       :: String -> String -> IO [FilePath]
    getSystemDataFiles :: String -> String -> IO [String]
    getSystemDataFiles String
    a String
    f   = ([String] -> [String]) -> IO [String] -> IO [String]
    forall a b. (a -> b) -> IO a -> IO b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap ((String -> String) -> [String] -> [String]
    forall a b. (a -> b) -> [a] -> [b]
    map (String -> String -> String
    </> String
    f)) (IO [String] -> IO [String]) -> IO [String] -> IO [String]
    forall a b. (a -> b) -> a -> b
    $ String -> IO [String]
    getSystemDataDirs String
    a
    -- | Get a list of all paths for a specific system configuration file.
    getSystemConfigFiles     :: String -> String -> IO [FilePath]
    getSystemConfigFiles :: String -> String -> IO [String]
    getSystemConfigFiles String
    a String
    f = ([String] -> [String]) -> IO [String] -> IO [String]
    forall a b. (a -> b) -> IO a -> IO b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap ((String -> String) -> [String] -> [String]
    forall a b. (a -> b) -> [a] -> [b]
    map (String -> String -> String
    </> String
    f)) (IO [String] -> IO [String]) -> IO [String] -> IO [String]
    forall a b. (a -> b) -> a -> b
    $ String -> IO [String]
    getSystemConfigDirs String
    a
    -- | Get a list of all paths for a specific data file.
    getAllDataFiles          :: String -> String -> IO [FilePath]
    getAllDataFiles :: String -> String -> IO [String]
    getAllDataFiles String
    a String
    f      = ([String] -> [String]) -> IO [String] -> IO [String]
    forall a b. (a -> b) -> IO a -> IO b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap ((String -> String) -> [String] -> [String]
    forall a b. (a -> b) -> [a] -> [b]
    map (String -> String -> String
    </> String
    f)) (IO [String] -> IO [String]) -> IO [String] -> IO [String]
    forall a b. (a -> b) -> a -> b
    $ String -> IO [String]
    getAllDataDirs String
    a
    -- | Get a list of all paths for a specific configuration file.
    getAllConfigFiles        :: String -> String -> IO [FilePath]
    getAllConfigFiles :: String -> String -> IO [String]
    getAllConfigFiles String
    a String
    f    = ([String] -> [String]) -> IO [String] -> IO [String]
    forall a b. (a -> b) -> IO a -> IO b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap ((String -> String) -> [String] -> [String]
    forall a b. (a -> b) -> [a] -> [b]
    map (String -> String -> String
    </> String
    f)) (IO [String] -> IO [String]) -> IO [String] -> IO [String]
    forall a b. (a -> b) -> a -> b
    $ String -> IO [String]
    getAllConfigDirs String
    a

    singleDir :: String -> String -> IO FilePath
    singleDir :: String -> String -> IO String
    singleDir String
    key String
    app = String -> IO String
    envLookup String
    key IO String -> (String -> IO String) -> IO String
    forall a b. IO a -> (a -> IO b) -> IO b
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= String -> IO String
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (String -> IO String) -> (String -> String) -> String -> IO String
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (String -> String -> String
    </> String
    app)

    multiDirs :: String -> String -> IO [FilePath]
    multiDirs :: String -> String -> IO [String]
    multiDirs String
    key String
    app = String -> IO String
    envLookup String
    key IO String -> (String -> IO [String]) -> IO [String]
    forall a b. IO a -> (a -> IO b) -> IO b
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= [String] -> IO [String]
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ([String] -> IO [String])
    -> (String -> [String]) -> String -> IO [String]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (String -> String) -> [String] -> [String]
    forall a b. (a -> b) -> [a] -> [b]
    map (String -> String -> String
    </> String
    app) ([String] -> [String])
    -> (String -> [String]) -> String -> [String]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . String -> [String]
    splitSearchPath

    envLookup :: String -> IO String
    envLookup :: String -> IO String
    envLookup String
    key = do env <- IO [(String, String)]
    getEnvironment
                       case lookup key env of
                            Just String
    val -> String -> IO String
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return String
    val
                            Maybe String
    Nothing  -> String -> IO String
    getDefault String
    key

    userRelative :: FilePath -> IO FilePath
    userRelative :: String -> IO String
    userRelative String
    p = IO String
    getHomeDirectory IO String -> (String -> IO String) -> IO String
    forall a b. IO a -> (a -> IO b) -> IO b
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= String -> IO String
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (String -> IO String) -> (String -> String) -> String -> IO String
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (String -> String -> String
    </> String
    p)