module DDC.Driver.Build.Locate
        (locateModuleFromPaths)
where
import DDC.Core.Module
import qualified DDC.Core.Pretty        as P
import Control.Monad
import Control.Monad.Trans.Except
import Control.Monad.IO.Class
import Data.Maybe
import System.FilePath
import qualified System.Directory       as Directory


-- | Locate the source file for a module, starting from the given list of base paths.
--   If the module cannot be found, or is found from multiple paths then throw
--   an error in the monad.
--
locateModuleFromPaths
        :: [FilePath]           -- ^ Base paths.
        -> ModuleName           -- ^ Module name.
        -> String               -- ^ Source file extension
        -> ExceptT String IO FilePath

locateModuleFromPaths pathsBase name ext
 = do
        mPaths  <- liftIO 
                $  liftM catMaybes
                $  mapM  (\d -> locateModuleFromPath d name ext) pathsBase

        case mPaths of
         []        -> throwE $ unlines 
                   $  [ "Cannot locate source for module '" 
                                ++ (P.renderIndent $ P.ppr name)  
                                ++ "' from base directories:" ]
                   ++ ["    " ++ dir | dir <- pathsBase]

         [path]    -> return path

         paths     -> throwE $ unlines
                   $  [ "Source for module '" 
                                ++ (P.renderIndent $ P.ppr name )
                                ++ "' found at multiple paths:" ]
                   ++ ["    " ++ dir | dir <- paths]


-- | Given the path of a .build spec, and a module name, yield the path where
--   the source of the module should be.
locateModuleFromPath 
        :: FilePath             -- ^ Base path.
        -> ModuleName           -- ^ Module name.
        -> String               -- ^ Source file extension.
        -> IO (Maybe FilePath)

locateModuleFromPath pathBase (ModuleName parts) ext
 = let  
        go []           = ext
        go [p]          = p <.> ext
        go (p : ps)     = p </> go ps

   in do
        let pathFile    = pathBase </> go parts
        exists          <- Directory.doesFileExist pathFile
        if exists 
         then return $ Just pathFile
         else return Nothing