module Distribution.Simple.Program.Find (
    
    ProgramSearchPath,
    ProgramSearchPathEntry(..),
    defaultProgramSearchPath,
    findProgramOnSearchPath,
    programSearchPathAsPATHVar,
  ) where
import Distribution.Verbosity
         ( Verbosity )
import Distribution.Simple.Utils
         ( debug, doesExecutableExist )
import Distribution.System
         ( OS(..), buildOS )
import System.Directory
         ( findExecutable )
import Distribution.Compat.Environment
         ( getEnvironment )
import System.FilePath
         ( (</>), (<.>), splitSearchPath, searchPathSeparator )
import Data.List
         ( intercalate )
type ProgramSearchPath = [ProgramSearchPathEntry]
data ProgramSearchPathEntry =
         ProgramSearchPathDir FilePath  
       | ProgramSearchPathDefault       
defaultProgramSearchPath :: ProgramSearchPath
defaultProgramSearchPath = [ProgramSearchPathDefault]
findProgramOnSearchPath :: Verbosity -> ProgramSearchPath
                        -> FilePath -> IO (Maybe FilePath)
findProgramOnSearchPath verbosity searchpath prog = do
    debug verbosity $ "Searching for " ++ prog ++ " in path."
    res <- tryPathElems searchpath
    case res of
      Nothing   -> debug verbosity ("Cannot find " ++ prog ++ " on the path")
      Just path -> debug verbosity ("Found " ++ prog ++ " at "++ path)
    return res
  where
    tryPathElems []       = return Nothing
    tryPathElems (pe:pes) = do
      res <- tryPathElem pe
      case res of
        Nothing -> tryPathElems pes
        Just _  -> return res
    tryPathElem (ProgramSearchPathDir dir) =
        findFirstExe [ dir </> prog <.> ext | ext <- extensions ]
      where
        
        
        
        extensions = case buildOS of
                       Windows -> ["", "exe"]
                       Ghcjs   -> ["", "exe"]
                       _       -> [""]
    tryPathElem ProgramSearchPathDefault = do
      
      
      
      mExe <- findExecutable prog
      case mExe of
        Just exe -> do
          exeExists <- doesExecutableExist exe
          if exeExists
            then return mExe
            else return Nothing
        _        -> return mExe
    findFirstExe []     = return Nothing
    findFirstExe (f:fs) = do
      isExe <- doesExecutableExist f
      if isExe
        then return (Just f)
        else findFirstExe fs
programSearchPathAsPATHVar :: ProgramSearchPath -> IO String
programSearchPathAsPATHVar searchpath = do
    ess <- mapM getEntries searchpath
    return (intercalate [searchPathSeparator] (concat ess))
  where
    getEntries (ProgramSearchPathDir dir) = return [dir]
    getEntries ProgramSearchPathDefault   = do
      env <- getEnvironment
      return (maybe [] splitSearchPath (lookup "PATH" env))