module UHC.Light.Compiler.Base.FileSearchLocation
( mkDirFileLoc
, StringPath, FileLocPath
, FileLocKind (..)
, FileLoc (..), emptyFileLoc, fileLocPkgDb
, mkPkgFileLoc
, filelocIsPkg
, FileSearchLoc
, PkgKey, PkgKey1, PkgKey2
, showPkgKey
, PackageSearchFilter (..)
, pkgSearchFilter
, PackageCfgKeyVals, PackageInfo (..), PackageMp, Module2PackageMp, PackageDatabase (..), emptyPackageMp, emptyPackageDatabase
, mkInternalPkgFileBase )
where
import UHC.Light.Compiler.Base.Common
import qualified Data.Set as Set
import qualified Data.Map as Map
import Data.Maybe
import Data.Version
import Data.List
import UU.Parsing
import UHC.Util.ParseUtils
import UHC.Util.ScanUtils
import UHC.Light.Compiler.Base.HsName
import UHC.Light.Compiler.Base.Target
import qualified UHC.Light.Compiler.ConfigInstall as Cfg
import UHC.Util.Hashable
import GHC.Generics




{-# LINE 44 "src/ehc/Base/FileSearchLocation.chs" #-}
data FileLocKind
  = FileLocKind_Dir									-- plain directory
  | FileLocKind_Pkg	PkgKey							-- specific package
  					String							-- with the dir inside package it was found
  | FileLocKind_PkgDb								-- yet unknown package in the package database
  deriving (Eq,Ord,Generic)

instance Hashable FileLocKind

instance Show FileLocKind where
  show  FileLocKind_Dir		    = "directory"
  show (FileLocKind_Pkg p d)	= "package: " ++ showPkgKey p ++ "(in: " ++ d ++ ")"
  show  FileLocKind_PkgDb    	= "package database"

{-# LINE 74 "src/ehc/Base/FileSearchLocation.chs" #-}
data FileLoc
  = FileLoc
      {	filelocKind		:: FileLocKind
      , filelocDir		:: String
      }
  deriving (Eq,Ord,Generic)

instance Hashable FileLoc

instance Show FileLoc where
  show (FileLoc k d) = d ++ " (" ++ show k ++ ")"

emptyFileLoc :: FileLoc
emptyFileLoc = FileLoc FileLocKind_Dir ""

fileLocPkgDb :: FileLoc
fileLocPkgDb = FileLoc FileLocKind_PkgDb ""

{-# LINE 94 "src/ehc/Base/FileSearchLocation.chs" #-}
mkDirFileLoc
  = FileLoc FileLocKind_Dir

{-# LINE 103 "src/ehc/Base/FileSearchLocation.chs" #-}
mkPkgFileLoc :: PkgKey -> String -> FileLoc
mkPkgFileLoc p d = FileLoc (FileLocKind_Pkg p d) d

{-# LINE 108 "src/ehc/Base/FileSearchLocation.chs" #-}
filelocIsPkg :: FileLoc -> Bool
filelocIsPkg (FileLoc (FileLocKind_Pkg _ _) _) = True
filelocIsPkg (FileLoc  FileLocKind_PkgDb    _) = True
filelocIsPkg _                                 = False

{-# LINE 115 "src/ehc/Base/FileSearchLocation.chs" #-}
type StringPath  = [String]
type FileLocPath = [FileLoc]

{-# LINE 124 "src/ehc/Base/FileSearchLocation.chs" #-}
type FileSearchLoc = FileLoc

{-# LINE 132 "src/ehc/Base/FileSearchLocation.chs" #-}
type PkgKey1 = PkgName
type PkgKey2 = Maybe Version
type PkgKey  = (PkgKey1,PkgKey2)

instance HSNM PkgKey where
  mkHNm (n,Just v) =   mkHNmBase (n ++ "-" ++ (concat $ intersperse "." $ map show $ versionBranch v))
  mkHNm (n,_     ) =   mkHNm      n

{-# LINE 146 "src/ehc/Base/FileSearchLocation.chs" #-}
showPkgKey :: PkgKey -> String
showPkgKey = show . mkHNm

{-# LINE 155 "src/ehc/Base/FileSearchLocation.chs" #-}
-- | Description of hiding/exposing pkgs, determining the used packages for looking up modules.
data PackageSearchFilter
  -- Note: the below order is important, it is used for sorting just before having its effect on searchable packages.
  -- The current order means that in its filtering hiding is done first, thereby starting out with all available pkgs, then hide (all), then expose selectively
  = PackageSearchFilter_HideAll
  | PackageSearchFilter_HidePkg			[PkgKey]
  | PackageSearchFilter_ExposePkg		[PkgKey]
  deriving (Show, Eq, Ord)

{-# LINE 166 "src/ehc/Base/FileSearchLocation.chs" #-}
pkgSearchFilter :: (x -> Maybe PkgKey) -> ([PkgKey] -> PackageSearchFilter) -> [x] -> [PackageSearchFilter]
pkgSearchFilter mkKey mk ss
  = if null ps then [] else [mk ps]
  where ps = catMaybes $ map mkKey ss

{-# LINE 177 "src/ehc/Base/FileSearchLocation.chs" #-}
type PackageCfgKeyVals = Map.Map String String

-- | Per package info
data PackageInfo
  = PackageInfo
      { pkginfoLoc					:: !FileLoc						-- ^ directory location
      , pkginfoOrder				:: !Int							-- ^ for multiple packages the relative order
      -- , pkginfoKeyVals				:: PackageCfgKeyVals			-- key/value pairs of pkg config info
      , pkginfoExposedModules		:: !HsNameS						-- ^ exposed modules
      , pkginfoBuildDepends			:: !(Set.Set PkgKey)			-- ^ pkgs dependend on
      , pkginfoIsExposed		    :: !Bool						-- ^ pkg is exposed?
      }
      deriving Show

-- | content of a package (keys are name, then version)
type PackageMp = Map.Map PkgKey1 (Map.Map PkgKey2 [PackageInfo])

emptyPackageMp :: PackageMp
emptyPackageMp = Map.empty

-- | reverse map from module name to package key
type Module2PackageMp = Map.Map HsName [PkgKey]

-- | A package database contains an actual package map, plus a function
-- that maps modules to associated package maps. The latter is computed
-- by "freezing" the package database using "pkgDbFreeze".
data PackageDatabase
  = PackageDatabase
      { pkgDbPkgMp		:: PackageMp
      , pkgDbMod2PkgMp	:: Module2PackageMp
      }
      deriving Show

emptyPackageDatabase :: PackageDatabase
emptyPackageDatabase = PackageDatabase emptyPackageMp Map.empty

{-# LINE 219 "src/ehc/Base/FileSearchLocation.chs" #-}

mkInternalPkgFileBase :: PkgKey -> String {- compiler name/version -} -> Target -> TargetFlavor -> FilePath
mkInternalPkgFileBase pkgKey compversion tgt tgtv =
  Cfg.mkInternalPkgFileBase (showPkgKey pkgKey) compversion (show tgt) (show tgtv)