module Ros.Internal.PathUtil where
import Data.Char (toUpper)
import Data.List (tails)
import System.Directory (doesFileExist)
import System.FilePath
import Paths_roshask

-- |Ensure that the first character in a String is capitalized.
cap :: String -> String
cap [] = []
cap (x:xs) = toUpper x : xs

-- |Determine if a path is a directory containing a ROS package.
isPkg :: FilePath -> IO Bool
isPkg = doesFileExist . (</> "manifest.xml")

-- |Determine if a path is a directory containing a ROS stack.
isStack :: FilePath -> IO Bool
isStack = doesFileExist . (</> "stack.xml")

-- |Identify the name of the package defining a msg.
pathToPkgName :: FilePath -> String
pathToPkgName p | hasExtension p = cap . last . init . splitPath $ p
                | otherwise = cap . last . splitPath $ p

-- |Identify the name of the stack in which a msg is defined. If the
-- package definining the message does not live in a stack, the result
-- is 'Nothing'.
stackName :: FilePath -> IO (Maybe String)
stackName = go . tails . reverse . splitPath
  where go :: [[FilePath]] -> IO (Maybe String)
        go [] = return Nothing
        go [[]] = return Nothing
        go (d:ds) = do b <- isStack . joinPath . reverse $ d
                       if b then return (Just (head d)) else go ds

-- |Given a path to a msg definition file, compute a destination
-- directory for generated Haskell code. A typical path will be under,
-- @~/.cabal/share/roshask/@.
codeGenDir :: FilePath -> IO FilePath
codeGenDir f = do s <- stackName f
                  r <- getDataDir
                  let base = case s of
                               Nothing -> r 
                               Just s' -> r </> s'
                  return $ base </> pkg </> "Ros" </> pkg
  where pkg = pathToPkgName f