module Config.Dyre.Paths where

import System.Info                    (os, arch)
import System.FilePath                ( (</>), (<.>), takeExtension )
import System.Directory               (getCurrentDirectory, doesFileExist, getModificationTime)
import System.Environment.XDG.BaseDir (getUserCacheDir, getUserConfigDir)
import System.Environment.Executable  (getExecutablePath)
import Data.Time

import Config.Dyre.Params
import Config.Dyre.Options

-- | Return the paths to, respectively, the current binary, the custom
--   binary, the config file, and the cache directory.
getPaths :: Params c -> IO (FilePath, FilePath, FilePath, FilePath, FilePath)
getPaths :: Params c -> IO (FilePath, FilePath, FilePath, FilePath, FilePath)
getPaths params :: Params c
params@Params{projectName :: forall cfgType. Params cfgType -> FilePath
projectName = FilePath
pName} = do
    FilePath
thisBinary <- IO FilePath
getExecutablePath
    Bool
debugMode  <- IO Bool
getDebug
    FilePath
cwd <- IO FilePath
getCurrentDirectory
    FilePath
cacheDir  <- case (Bool
debugMode, Params c -> Maybe (IO FilePath)
forall cfgType. Params cfgType -> Maybe (IO FilePath)
cacheDir Params c
params) of
                      (True,  _      ) -> FilePath -> IO FilePath
forall (m :: * -> *) a. Monad m => a -> m a
return (FilePath -> IO FilePath) -> FilePath -> IO FilePath
forall a b. (a -> b) -> a -> b
$ FilePath
cwd FilePath -> FilePath -> FilePath
</> "cache"
                      (False, Nothing) -> FilePath -> IO FilePath
getUserCacheDir FilePath
pName
                      (False, Just cd :: IO FilePath
cd) -> IO FilePath
cd
    FilePath
configDir <- case (Bool
debugMode, Params c -> Maybe (IO FilePath)
forall cfgType. Params cfgType -> Maybe (IO FilePath)
configDir Params c
params) of
                      (True,  _      ) -> FilePath -> IO FilePath
forall (m :: * -> *) a. Monad m => a -> m a
return FilePath
cwd
                      (False, Nothing) -> FilePath -> IO FilePath
getUserConfigDir FilePath
pName
                      (False, Just cd :: IO FilePath
cd) -> IO FilePath
cd
    let tempBinary :: FilePath
tempBinary = FilePath
cacheDir FilePath -> FilePath -> FilePath
</> FilePath
pName FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ "-" FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
os FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ "-" FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
arch
                              FilePath -> FilePath -> FilePath
<.> FilePath -> FilePath
takeExtension FilePath
thisBinary
    let configFile :: FilePath
configFile = FilePath
configDir FilePath -> FilePath -> FilePath
</> FilePath
pName FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ ".hs"
    let libsDir :: FilePath
libsDir = FilePath
configDir FilePath -> FilePath -> FilePath
</> "lib"
    (FilePath, FilePath, FilePath, FilePath, FilePath)
-> IO (FilePath, FilePath, FilePath, FilePath, FilePath)
forall (m :: * -> *) a. Monad m => a -> m a
return (FilePath
thisBinary, FilePath
tempBinary, FilePath
configFile, FilePath
cacheDir, FilePath
libsDir)

-- | Check if a file exists. If it exists, return Just the modification
--   time. If it doesn't exist, return Nothing.
maybeModTime :: FilePath -> IO (Maybe UTCTime)
maybeModTime path :: FilePath
path = do
    Bool
fileExists <- FilePath -> IO Bool
doesFileExist FilePath
path
    if Bool
fileExists
       then (UTCTime -> Maybe UTCTime) -> IO UTCTime -> IO (Maybe UTCTime)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap UTCTime -> Maybe UTCTime
forall a. a -> Maybe a
Just (IO UTCTime -> IO (Maybe UTCTime))
-> IO UTCTime -> IO (Maybe UTCTime)
forall a b. (a -> b) -> a -> b
$ FilePath -> IO UTCTime
getModificationTime FilePath
path
       else Maybe UTCTime -> IO (Maybe UTCTime)
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe UTCTime
forall a. Maybe a
Nothing
-- Removed type signature because it can't satisfy GHC 7.4 and 7.6 at once
-- maybeModTime :: FilePath -> IO (Maybe UTCTime)