content: {-# LANGUAGE TupleSections #-}
  
  module Development.Rattle.Options(
      RattleOptions(..), RattleUI(..), rattleOptions,
      rattleOptionsExplicit, shorten, expand
      ) where
  
  import Control.Monad.Extra
  import General.Extra
  import Data.Ord
  import System.FilePath
  import System.Directory
  import Development.Rattle.UI
  import qualified Data.HashMap.Strict as Map
  import qualified Development.Shake.Command as C
  import Data.Maybe
  import Data.List.Extra
  import General.FileName
  import qualified Data.ByteString.Char8 as BSC
  import Data.Monoid
  import Prelude
  
  
  -- | Basic options for configuring rattle.
  data RattleOptions = RattleOptions
      {rattleFiles :: FilePath -- ^ Where all my shared files go
      ,rattleSpeculate :: Maybe String -- ^ Should I speculate? Under which key?
      ,rattleMachine :: String -- ^ Key to store run#
      ,rattleShare :: Bool -- ^ Should I share files from the cache
      ,rattleProcesses :: Int -- ^ Number of simulateous processes
      ,rattleCmdOptions :: [C.CmdOption] -- ^ Extra options added to every command line
      ,rattleNamedDirs :: [(String, FilePath)] -- ^ Named directories, e.g. (PWD, .)
      ,rattleUI :: Maybe RattleUI -- ^ Nothing for auto detect
      ,rattleForward :: Bool -- ^ Support forward style stuff
      } deriving Show
  
  
  -- | Default 'RattleOptions' value.
  rattleOptions :: RattleOptions
  rattleOptions = RattleOptions ".rattle" (Just "") "m1" True 0 [] [("PWD",".")] Nothing False
  
  
  rattleOptionsExplicit :: RattleOptions -> IO RattleOptions
  rattleOptionsExplicit = fixProcessorCount >=> fixNamedDirs
      where
          fixProcessorCount o
              | rattleProcesses o /= 0 = pure o
              | otherwise = do p <- getProcessorCount; pure o{rattleProcesses=p}
  
          fixNamedDirs o = do
              xs <- sequence [(a,) . addTrailingPathSeparator <$> canonicalizePath b | (a,b) <- rattleNamedDirs o]
              -- sort so all prefixes come last, so we get the most specific match
              pure o{rattleNamedDirs = sortOn (Down . snd) xs}
  
  
  shorten :: [(String, String)] -> FileName -> FileName
  shorten [] = id
  shorten named = \x -> fromMaybe x $ firstJust (f x) named2
      where
          named2 = [(BSC.pack $ "$" ++ a ++ [pathSeparator], BSC.pack $ addTrailingPathSeparator b) | (a,b) <- named]
          f x (name,dir) = do rest <- BSC.stripPrefix dir $ fileNameToByteString x; pure $ byteStringToFileName $ name <> rest
  
  expand :: [(String, String)] -> FileName -> FileName
  expand [] = id
  expand named = \x -> case BSC.uncons $ fileNameToByteString x of
      Just ('$', x)
          | (x1, x2) <- BSC.break isPathSeparator x
          , not $ BSC.null x2
          , Just v <- Map.lookup x1 named2
          -> byteStringToFileName $ v <> x2
      _ -> x
      where
          named2 = Map.fromList [(BSC.pack a, BSC.pack b) | (a,b) <- named]
  