-- | Adapted from how Shelly does finding in Shelly.Find
-- (shelly is BSD-licensed)

module System.FSNotify.Find where

import Control.Monad
import Control.Monad.IO.Class
import System.Directory (doesDirectoryExist, listDirectory, pathIsSymbolicLink)
import System.FilePath

find :: Bool -> FilePath -> IO [FilePath]
find followSymlinks = find' followSymlinks  []

find' :: Bool -> [FilePath] -> FilePath -> IO [FilePath]
find' followSymlinks startValue dir = do
  (rPaths, aPaths) <- lsRelAbs dir
  foldM visit startValue (zip rPaths aPaths)
  where
    visit acc (relativePath, absolutePath) = do
      isDir <- liftIO $ doesDirectoryExist absolutePath
      sym <- liftIO $ pathIsSymbolicLink absolutePath
      let newAcc = relativePath : acc
      if isDir && (followSymlinks || not sym)
        then find' followSymlinks newAcc relativePath
        else return newAcc

lsRelAbs :: FilePath -> IO ([FilePath], [FilePath])
lsRelAbs fp = do
  files <- liftIO $ listDirectory fp
  let absolute = map (fp </>) files
  let relativized = map (\p -> joinPath [fp, p]) files
  return (relativized, absolute)
