module HsDev.Inspect.Order (
	orderBy, order
	) where

import Control.Lens
import Data.Maybe
import Data.String
import qualified Data.Map as M
import qualified Data.Set as S
import qualified Language.Haskell.Exts as H

import Data.Deps
import HsDev.Inspect
import HsDev.Symbols.Types
import System.Directory.Paths

-- | Order source files so that dependencies goes first and we are able to resolve symbols and set fixities
orderBy :: (a -> Maybe Preloaded) -> [a] -> Either (DepsError Path) [a]
orderBy fn ps = do
	order' <- linearize pdeps
	return $ mapMaybe (`M.lookup` pm) order'
	where
		pdeps = mconcat $ mapMaybe (fmap getDeps . fn) ps
		pm = M.fromList [(pfile, p) | p <- ps, pfile <- fn p ^.. _Just . preloadedId . moduleLocation . moduleFile]
		files = S.fromList $ map fn ps ^.. each . _Just . preloadedId . moduleLocation . moduleFile
		getDeps :: Preloaded -> Deps Path
		getDeps p = deps mfile [ifile | ifile <- ifiles, S.member ifile files] where
			H.Module _ _ _ idecls _ = _preloadedModule p
			imods = [fromString iname | H.ModuleName _ iname <- map H.importModule idecls]
			mfile = _preloadedId p ^?! moduleLocation . moduleFile
			projRoot = _preloadedId p ^? moduleLocation . moduleProject . _Just . projectPath
			mroot = fromMaybe
				(sourceModuleRoot (view moduleName $ _preloadedId p) mfile)
				projRoot
			dirs = do
				proj <- _preloadedId p ^.. moduleLocation . moduleProject . _Just
				i <- fileTargets proj mfile
				view infoSourceDirs i
			ifiles = [normPath (joinPaths [mroot, dir, importPath imod]) | imod <- imods, dir <- if null dirs then [fromFilePath "."] else dirs]

order :: [Preloaded] -> Either (DepsError Path) [Preloaded]
order = orderBy Just