-- | Directory utils that don't need to be in the Build monad.
module BuildBox.IO.Directory
	( lsFilesIn
	, lsDirsIn
	, traceFilesFrom)
where
import System.Directory
import Control.Monad
import Control.Monad.Trans
import Data.List
import Data.Sequence		(Seq)
import qualified Data.Sequence	as Seq


-- | Get the names of all files in a directory.
--   This filters out the fake files like '.' and '..'
lsFilesIn :: MonadIO m => String -> m [String]
lsFilesIn path
 = do 	contents <- liftIO $ getDirectoryContents path
	
	-- filter out directories
	files	<- filterM (\p -> liftM not $ liftIO $ doesDirectoryExist p) 
		$ map (\f -> path ++ "/" ++ f)
		$ dropDotPaths contents

	return	$ sort files


-- | Get the names of all the dirs in this one.
--   This filters out the fake files like '.' and '..'
lsDirsIn :: MonadIO m => String	 -> m [String]
lsDirsIn path
 = do 
 	contents <- liftIO $ getDirectoryContents path
	
	-- only keep directories
	dirs	<- filterM (liftIO . doesDirectoryExist)
		$  map (\f -> path ++ "/" ++ f)
		$  dropDotPaths contents

	return	$ sort dirs


-- | Get all the files reachable from this directory
traceFilesFrom :: FilePath -> IO (Seq FilePath)
traceFilesFrom path
 = do	isDir	<- doesDirectoryExist path
	isFile	<- doesFileExist      path

	let result
		| isDir 	
		= do	contents <- liftM dropDotPaths
			 	 $  getDirectoryContents path

			liftM (join  . Seq.fromList)
				$ mapM traceFilesFrom 
				$ map (\f -> path ++ "/" ++ f) 
				$ contents

		| isFile
		=	return	$ Seq.singleton path
		
		| otherwise
		=	return	$ Seq.empty
	
	result


-- | Drop out the fake '.' and '..' dirst from a list of paths.
dropDotPaths :: [FilePath] -> [FilePath]
dropDotPaths xx
	= filter (\f -> f /= "." && f /= "..") xx