content: -- | Provide a VCS implementation for directories not under version control
  module Git.Vogue.VCS.Null
  ( nullVCS,
  ) where
  
  import           Control.Monad          (filterM)
  import           Control.Monad.IO.Class
  import           Git.Vogue.Types
  import           System.Directory
  import           System.FilePath
  
  nullVCS :: MonadIO m => VCS m
  nullVCS = VCS
    { getFiles    = nullGetFiles
    , installHook = nullInstallHook
    , removeHook  = nullRemoveHook
    , checkHook   = nullCheckHook
    , getTopLevel = nullGetTopLevel
    }
  
  nullGetFiles :: MonadIO m => SearchMode -> m [FilePath]
  nullGetFiles mode = case mode of
    FindSpecific fs -> existantFiles fs
    _               -> liftIO getAllFiles
    where
      existantFiles = filterM (liftIO . doesFileExist)
  
  nullInstallHook :: MonadIO m => m ()
  nullInstallHook =
    liftIO $ putStrLn "Warning, hooks can't be installed with the null VCS backend"
  
  nullRemoveHook :: MonadIO m => m ()
  nullRemoveHook =
    liftIO $ putStrLn "Warning, hooks can't be removed with the null VCS backend"
  
  nullCheckHook :: Applicative m => m Bool
  nullCheckHook = pure False
  
  nullGetTopLevel :: MonadIO m => m FilePath
  nullGetTopLevel = liftIO getCurrentDirectory
  
  getAllFiles :: IO [FilePath]
  getAllFiles = do
      currentDirectory <- getCurrentDirectory
      fs <- go currentDirectory
      pure (makeRelative currentDirectory <$> fs)
    where
      go dir = do
        (dirs, files) <- getFilesAndDirectories dir
        (files ++) . concat <$> mapM go dirs
  
  getFilesAndDirectories :: FilePath -> IO ([FilePath], [FilePath])
  getFilesAndDirectories dir = do
    c <- fmap (dir </>) . filter (`notElem` ["..", "."]) <$> getDirectoryContents dir
    (,) <$> filterM doesDirectoryExist c <*> filterM doesFileExist c
  
  