module Data.Dependency
    ( -- * Functions
      resolveDependencies
    , isPresent
    , buildSequence
    , asGraph
    -- * Types
    , Dependency (..)
    , PackageSet (..)
    , Version (..)
    ) where

import           Data.Dependency.Sort
import           Data.Dependency.Type
import           Data.List            (groupBy)
import qualified Data.Map             as M
import qualified Data.Set             as S

isPresent :: PackageSet -> Dependency -> Bool
isPresent (PackageSet ps) (Dependency ln _ _) = g (M.lookup ln ps)
    where g (Just x) = not (S.null x)
          g Nothing  = False

latest :: PackageSet -> Dependency -> Maybe (String, Version)
latest (PackageSet ps) (Dependency ln _ _) = do
    s <- M.lookup ln ps
    (,) ln <$> S.lookupMax s

buildSequence :: [Dependency] -> [[Dependency]]
buildSequence = reverse . groupBy independent . sortDeps
    where independent (Dependency ln _ ls) (Dependency ln' _ ls') = ln' `notElem` ls && ln `notElem` ls'

-- | Heuristics:
--
-- 1. Always use a newer version when possible
--
-- 2. Obey constraints
--
-- 3. Specify an error for circular dependencies
--
-- 4. Specify an error for overconstrained builds
--
-- 5. Specify an error if a package is not present.
--
-- This doesn't do any package resolution beyond versioning.
resolveDependencies :: [[Dependency]] -> PackageSet -> Maybe [[(String, Version)]]
resolveDependencies sd ps = sequence (traverse (latest ps) <$> sd)