collectLibraries :: [String] -> IO ([Library],[Library])
collectLibraries libs = ans where
    ans = do
        (bynames,byhashes) <- fetchAllLibraries
        let f (pn,vrs) = lname pn vrs `mplus` lhash pn vrs where
                lname pn vrs = do
                    xs <- Map.lookup (packString pn) bynames
                    (x:_) <- return $ filter isGood xs
                    return x
                isGood lib = versionBranch vrs `isPrefixOf` versionBranch (libVersion lib)
                lhash pn vrs = do
                    [] <- return $ versionBranch vrs
                    Map.lookup pn byhashes'
            byhashes' = Map.fromList [ (show x,y) | (x,y) <- Map.toList byhashes]
        let es' = [ (x,f $ splitVersion x) | x <- libs ]
            es = [ l | (_,Just l) <- es' ]
            bad = [ n | (n,Nothing) <- es' ]
        unless (null bad) $ do
            putErrLn "Libraries not found:"
            forM_ bad $ \b -> putErrLn ("    " ++ b)
            exitFailure

        checkForModuleConficts es
        let f lmap _ [] = return lmap
            f lmap lset ((ei,l):ls)
                | libHash l `Set.member` lset = f lmap lset ls
                | otherwise = case Map.lookup (libBaseName l) lmap of
                    Nothing -> f (Map.insert (libBaseName l) (ei,l) lmap) (Set.insert (libHash l) lset) (ls ++ newdeps)
                    Just (ei',l') | libHash l == libHash l' -> f  (Map.insert (libBaseName l) (ei || ei',l) lmap) lset ls
                    Just (_,l')  -> putErrDie $ printf  "Conflicting versions of library '%s' are required. [%s]\n" (libName l) (show (libHash l,libHash l'))
              where newdeps = [ (False,fromMaybe (error $ printf "Dependency '%s' with hash '%s' needed by '%s' was not found" (unpackPS p) (show h) (libName l)) (Map.lookup h byhashes)) | let HoHeader { hohLibDeps = ldeps } = libHoHeader l , (p,h) <- ldeps ]
        finalmap <- f Map.empty Set.empty [ (True,l) | l <- es ]
        checkForModuleConficts [ l | (_,l) <- Map.elems finalmap ]
        when verbose $ forM_ (Map.toList finalmap) $ \ (n,(e,l)) ->
            printf "-- Base: %s Exported: %s Hash: %s Name: %s\n" (unpackPS n) (show e) (show $ libHash l) (libName l)

        return ([ l | (True,l) <- Map.elems finalmap ],[ l | (False,l) <- Map.elems finalmap ])

    checkForModuleConficts ms = do
        let mbad = Map.toList $ Map.filter (\c -> case c of [_] -> False; _ -> True)  $ Map.fromListWith (++) [ (m,[l]) | l <- ms, m <- fst $ libModules l]
        forM_ mbad $ \ (m,l) -> putErrLn $ printf "Module '%s' is exported by multiple libraries: %s" (show m) (show $ map libName l)
        unless (null mbad) $ putErrDie "There were conflicting modules!"
collectLibraries :: [String] -> IO ([Library],[Library])
collectLibraries libs = ans where
    ans = do
        (bynames,byhashes) <- fetchAllLibraries
        let f (pn,vrs) = lname pn vrs `mplus` lhash pn vrs where
                lname pn vrs = do
                    xs <- Map.lookup (packString pn) bynames
                    (x:_) <- return $ filter isGood xs
                    return x
                isGood lib = versionBranch vrs `isPrefixOf` versionBranch (libVersion lib)
                lhash pn vrs = do
                    [] <- return $ versionBranch vrs
                    Map.lookup pn byhashes'
            byhashes' = Map.fromList [ (show x,y) | (x,y) <- Map.toList byhashes]
        let es' = [ (x,f $ splitVersion x) | x <- libs ]
            es = [ l | (_,Just l) <- es' ]
            bad = [ n | (n,Nothing) <- es' ]
        unless (null bad) $ do
            putErrLn "Libraries not found:"
            forM_ bad $ \b -> putErrLn ("    " ++ b)
            exitFailure

        checkForModuleConficts es
        let f lmap _ [] = return lmap
            f lmap lset ((ei,l):ls)
                | libHash l `Set.member` lset = f lmap lset ls
                | otherwise = case Map.lookup (libBaseName l) lmap of
                    Nothing -> f (Map.insert (libBaseName l) (ei,l) lmap) (Set.insert (libHash l) lset) (ls ++ newdeps)
                    Just (ei',l') | libHash l == libHash l' -> f  (Map.insert (libBaseName l) (ei || ei',l) lmap) lset ls
                    Just (_,l')  -> putErrDie $ printf  "Conflicting versions of library '%s' are required. [%s]\n" (libName l) (show (libHash l,libHash l'))
              where newdeps = [ (False,fromMaybe (error $ printf "Dependency '%s' with hash '%s' needed by '%s' was not found" (unpackPS p) (show h) (libName l)) (Map.lookup h byhashes)) | let HoHeader { hohLibDeps = ldeps } = libHoHeader l , (p,h) <- ldeps ]
        finalmap <- f Map.empty Set.empty [ (True,l) | l <- es ]
        checkForModuleConficts [ l | (_,l) <- Map.elems finalmap ]
        when verbose $ forM_ (Map.toList finalmap) $ \ (n,(e,l)) ->
            printf "-- Base: %s Exported: %s Hash: %s Name: %s\n" (unpackPS n) (show e) (show $ libHash l) (libName l)

        return ([ l | (True,l) <- Map.elems finalmap ],[ l | (False,l) <- Map.elems finalmap ])

    checkForModuleConficts ms = do
        let mbad = Map.toList $ Map.filter (\c -> case c of [_] -> False; _ -> True)  $ Map.fromListWith (++) [ (m,[l]) | l <- ms, m <- fst $ libModules l]
        forM_ mbad $ \ (m,l) -> putErrLn $ printf "Module '%s' is exported by multiple libraries: %s" (show m) (show $ map libName l)
        unless (null mbad) $ putErrDie "There were conflicting modules!"
collectLibraries libs = ans where
    ans = do
        (bynames,byhashes) <- fetchAllLibraries
        let f (pn,vrs) = lname pn vrs `mplus` lhash pn vrs where
                lname pn vrs = do
                    xs <- Map.lookup (packString pn) bynames
                    (x:_) <- return $ filter isGood xs
                    return x
                isGood lib = versionBranch vrs `isPrefixOf` versionBranch (libVersion lib)
                lhash pn vrs = do
                    [] <- return $ versionBranch vrs
                    Map.lookup pn byhashes'
            byhashes' = Map.fromList [ (show x,y) | (x,y) <- Map.toList byhashes]
        let es' = [ (x,f $ splitVersion x) | x <- libs ]
            es = [ l | (_,Just l) <- es' ]
            bad = [ n | (n,Nothing) <- es' ]
        unless (null bad) $ do
            putErrLn "Libraries not found:"
            forM_ bad $ \b -> putErrLn ("    " ++ b)
            exitFailure

        checkForModuleConficts es
        let f lmap _ [] = return lmap
            f lmap lset ((ei,l):ls)
                | libHash l `Set.member` lset = f lmap lset ls
                | otherwise = case Map.lookup (libBaseName l) lmap of
                    Nothing -> f (Map.insert (libBaseName l) (ei,l) lmap) (Set.insert (libHash l) lset) (ls ++ newdeps)
                    Just (ei',l') | libHash l == libHash l' -> f  (Map.insert (libBaseName l) (ei || ei',l) lmap) lset ls
                    Just (_,l')  -> putErrDie $ printf  "Conflicting versions of library '%s' are required. [%s]\n" (libName l) (show (libHash l,libHash l'))
              where newdeps = [ (False,fromMaybe (error $ printf "Dependency '%s' with hash '%s' needed by '%s' was not found" (unpackPS p) (show h) (libName l)) (Map.lookup h byhashes)) | let HoHeader { hohLibDeps = ldeps } = libHoHeader l , (p,h) <- ldeps ]
        finalmap <- f Map.empty Set.empty [ (True,l) | l <- es ]
        checkForModuleConficts [ l | (_,l) <- Map.elems finalmap ]
        when verbose $ forM_ (Map.toList finalmap) $ \ (n,(e,l)) ->
            printf "-- Base: %s Exported: %s Hash: %s Name: %s\n" (unpackPS n) (show e) (show $ libHash l) (libName l)

        return ([ l | (True,l) <- Map.elems finalmap ],[ l | (False,l) <- Map.elems finalmap ])

    checkForModuleConficts ms = do
        let mbad = Map.toList $ Map.filter (\c -> case c of [_] -> False; _ -> True)  $ Map.fromListWith (++) [ (m,[l]) | l <- ms, m <- fst $ libModules l]
        forM_ mbad $ \ (m,l) -> putErrLn $ printf "Module '%s' is exported by multiple libraries: %s" (show m) (show $ map libName l)
        unless (null mbad) $ putErrDie "There were conflicting modules!"