module Sandbox (getSandboxArguments) where

import Control.Applicative ((<$>))
import Data.Char (isSpace)
import Data.List (isPrefixOf, tails)
import System.Directory (getCurrentDirectory, doesFileExist, doesDirectoryExist)
import System.FilePath ((</>), takeDirectory, takeFileName)
import Control.Exception (handle, SomeException)

configFile :: String
configFile = "cabal.sandbox.config"

sandboxDir :: String
sandboxDir = ".cabal-sandbox"

pkgDbKey :: String
pkgDbKey = "package-db:"

pkgDbKeyLen :: Int
pkgDbKeyLen = length pkgDbKey

getSandboxArguments :: IO [String]
getSandboxArguments = do
    mdir <- getCurrentDirectory >>= getSandboxDir
    case mdir of
        Nothing           -> return []
        Just (sdir,sconf) -> sandboxArguments sdir sconf

getSandboxDir :: FilePath -> IO (Maybe (FilePath,FilePath))
getSandboxDir dir = do
    exist <- doesSandboxExist dir
    if exist then
        return $ Just (dir </> sandboxDir, dir </> configFile)
      else do
        let dir' = takeDirectory dir
        if dir == dir' then
            return Nothing
          else
            getSandboxDir dir'

doesSandboxExist :: FilePath -> IO Bool
doesSandboxExist dir = do
    fileExist <- doesFileExist $ dir </> configFile
    dirExist <- doesDirectoryExist $ dir </> sandboxDir
    return (fileExist && dirExist)

sandboxArguments :: FilePath -> FilePath -> IO [String]
sandboxArguments sdir sconf = handle handler $ do
    pkgDb <- getPackageDbDir sconf
    let ver = extractGhcVer pkgDb
    let (pkgDbOpt,noUserPkgDbOpt)
          | ver < 706 = ("-package-conf","-no-user-package-conf")
          | otherwise = ("-package-db",  "-no-user-package-db")
        pkgDbPath = sdir </> pkgDb
        libPath   = sdir </> "lib"
        impOpt = "-i" ++ libPath
    return [noUserPkgDbOpt, pkgDbOpt, pkgDbPath, impOpt]
  where
    handler :: SomeException -> IO [String]
    handler _ = return []

getPackageDbDir :: FilePath -> IO FilePath
getPackageDbDir sconf = do
    ls <- lines <$> readFile sconf
    let [target] = filter ("package-db:" `isPrefixOf`) ls
    return $ extractValue target
  where
    extractValue = fst . break isSpace . dropWhile isSpace . drop pkgDbKeyLen

extractGhcVer :: String -> Int
extractGhcVer dir = ver
  where
    file = takeFileName dir
    findVer = drop 4 . head . filter ("ghc-" `isPrefixOf`) . tails
    (verStr1,_:left) = break (== '.') $ findVer file
    (verStr2,_)      = break (== '.') left
    ver = read verStr1 * 100 + read verStr2