{- |
   Support library for users of the installation script in
   hsinstall. When your project has data files in a @resources@
   directory, this library can be used to locate those files
   at runtime.
-}
module HSInstall
   ( getRsrcDir )
   where

import Control.Monad ( liftM2, mplus )
import System.Directory ( doesDirectoryExist )
import System.Environment ( getExecutablePath )
import System.FilePath ( (</>), takeDirectory, takeFileName )


{- |
   Get the path to the resources, relative to where the binary was
   installed and executed from. The argument passed here is expected
   to be the @getDataDir@ generated by Cabal at compile time in the
   @Paths_YOUR_PROJECT@ module.

   Usage:

   @
      import HSInstall ( getRsrcDir )
      import Paths_YOUR_PROJECT ( getDataDir )

      resourcesDir <- getRsrcDir getDataDir
   @
-}
getRsrcDir :: IO FilePath -> IO FilePath
getRsrcDir cabalDataDir =
   maybe (fail "Unable to find resources directory")
      return =<< searchResult

   where
      searchResult :: IO (Maybe FilePath)
      searchResult = foldl (liftM2 mplus) (return Nothing) $ map (>>= mbExists)
         [ mkRsrcPathFHS cabalDataDir
         , mkRsrcPathFHSNoVer cabalDataDir
         , mkRsrcPathBundle
         ]

      mbExists :: FilePath -> IO (Maybe FilePath)
      mbExists p = do
         exists <- doesDirectoryExist p
         return $ if exists then Just p else Nothing


mkRsrcPathFHS :: IO FilePath -> IO FilePath
mkRsrcPathFHS cabalDataDir = do
   appDir <- takeFileName <$> cabalDataDir
   ( </> "share" </> appDir </> "resources" ) . takeDirectory . takeDirectory
      <$> getExecutablePath


mkRsrcPathFHSNoVer :: IO FilePath -> IO FilePath
mkRsrcPathFHSNoVer cabalDataDir = do
   appDir <- takeFileName <$> cabalDataDir
   ( </> "share" </> (removeVersion appDir) </> "resources" ) . takeDirectory . takeDirectory
      <$> getExecutablePath

   where
      removeVersion = init . reverse . dropWhile (/= '-') . reverse


mkRsrcPathBundle :: IO FilePath
mkRsrcPathBundle =
   ( </> "resources" ) . takeDirectory . takeDirectory <$> getExecutablePath