module Development.Cake3.Utils.Find where

import Control.Applicative
import Control.Monad.Trans
import System.Directory
import System.IO.Unsafe (unsafeInterleaveIO)

import System.FilePath.Wrapper
import Development.Cake3
import Development.Cake3.Types
import Development.Cake3.Monad


filterExts :: [String] -> [File] -> [File]
filterExts exts files = filter (\f -> or $ map (isExt f) exts) files where
  isExt f e = takeExtension f == (sureDot e)
  sureDot [] = error "filterExt: empty extantion passed"
  sureDot e@('.':cs) = e
  sureDot e@(c:cs) = '.':e

-- FIMXE: Find a way to record dependencies like
-- FIXME: Figure out how to add ./relative notation (./file instead of file)
-- Makefile : contents_of(directory)
getDirectoryContentsRecursive :: (MonadIO m) => File -> m [File]
getDirectoryContentsRecursive td@(FileT topdir) = map (td</>) `liftM` (liftIO $ recurseDirectories [""])
  where
    recurseDirectories :: [FilePath] -> IO [FilePath]
    recurseDirectories []         = return []
    recurseDirectories (dir:dirs) = unsafeInterleaveIO $ do
      (files, dirs') <- collect [] [] =<< getDirectoryContents (topdir </> dir)
      files' <- recurseDirectories (dirs' ++ dirs)
      return (files ++ files')

      where
        collect files dirs' []              = return (reverse files, reverse dirs')
        collect files dirs' (entry:entries) | ignore entry
                                            = collect files dirs' entries
        collect files dirs' (entry:entries) = do
          let dirEntry = dir </> entry
          isDirectory <- doesDirectoryExist (topdir </> dirEntry)
          if isDirectory
            then collect files (dirEntry:dirs') entries
            else collect (dirEntry:files) dirs' entries

        ignore ['.']      = True
        ignore ['.', '.'] = True
        ignore _          = False