content: 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
  