-- |Experimental module for representing a single package , highly likely to change in incompatible ways.
module Linspire.Debian.PackageDeprecated where

-- Standard GHC Modules

import qualified Data.Map as Map

-- Local Modules

import Linspire.Debian.Version
import Linspire.Debian.Control
import Linspire.Debian.Relation
import Linspire.Debian.Package

-- Simple Package Representation

-- |A package with a name and list of dependencies
data Package
    = Package { pName :: String
              , pVersion :: Maybe DebianVersion
              , pDepends :: Relations
              , pPreDepends :: Relations
              , pConflicts ::Relations
              , pReplaces :: Relations
              , pProvides :: Relations
--              , pParagraph :: Paragraph
              }
      deriving Show

instance Eq Package where
    p1 == p2 = (pName p1 == pName p2) && (pVersion p1 == pVersion p2)

-- |FIXME: we do not deal with Provides\/virtual packages yet
paragraphToPackages :: Paragraph -> Package
paragraphToPackages p =
    Package { pName =
                  case lookupP "Package" p of
                    Nothing -> error $ "Paragraph does not have Package field: " ++ (show p)
                    Just (Field (_,a)) -> stripWS a
            , pVersion =
                case lookupP "Version" p of
                  Nothing -> error $ "Version not found for " ++ show p
                  Just (Field (_,a)) -> Just (parseDebianVersion (stripWS a))
            , pDepends =   tryParseRel $ lookupP "Depends" p
            , pPreDepends = tryParseRel $ lookupP "Pre-Depends" p
            , pConflicts = tryParseRel $ lookupP "Conflicts" p
            , pReplaces =  tryParseRel $ lookupP "Replaces" p
            , pProvides =  tryParseRel $ lookupP "Provides" p
--            , pParagraph = p
            }

type ProvidesMap = Map.Map String [Package]

{-
findProvides :: [Package] -> ProvidesMap
findProvides packages = foldl addProvides Map.empty packages
    where addProvides :: ProvidesMap -> Package -> ProvidesMap
          addProvides pm package =
              foldl (\m [(Rel pkgName Nothing Nothing)] -> Map.insertWith (++) pkgName [package] m) pm (pProvides package)
-}

findProvides :: [Package] -> [(PkgName, Package)]
findProvides packages = foldl addprovides [] packages
    where addprovides :: [(PkgName, Package)] -> Package -> [(PkgName, Package)]
          addprovides providesList package =
              foldl (\pl [(Rel pkgName Nothing Nothing)] ->(pkgName, package): pl) providesList (pProvides package)

-- |Architecture ?
makeVirtualPackages :: ProvidesMap -> [Package]
makeVirtualPackages pm =
    Map.foldWithKey mVP [] pm
    where mVP vpName packages virtualPackages
              = (Package { pName = vpName
                         , pVersion = Nothing
                         , pDepends = [map mkDepend packages] -- or depends on things that provide it
                         , pPreDepends = []
                         , pConflicts = []
                         , pReplaces = []
                         , pProvides = []
--                         , pParagraph = Paragraph []
                         } ) : virtualPackages
          mkDepend package =
              let name = pName package
                  rel = fmap EEQ (pVersion package)
                  in Rel name rel Nothing
{-
-- |Does not check for duplication or multiple use
addProvides :: [Package] -> PackageNameMap -> PackageNameMap
addProvides ps pnm =
    let provides = findProvides ps in
    foldl (\m (packageName, package) -> Map.insertWith (flip (++)) packageName [package] m) pnm provides
--  ++ (makeVirtualPackages (findProvides ps))


tryParseRel :: Maybe Field -> Relations
tryParseRel Nothing = []
tryParseRel (Just (Field (_, relStr))) = either (error . show) id (parseRelations relStr)
-}

controlToPackageNameMap :: Control -> (Paragraph -> Package) -> PackageNameMap Package
controlToPackageNameMap (Control p) p2p =
    let packages = (map p2p p) in
    addProvides (map (\ (Rel pkgName _ _) -> pkgName) . concat . pProvides) packages (packageNameMap pName packages)

packagesToPackageNameMap :: [Package] -> PackageNameMap Package
packagesToPackageNameMap packages =
    addProvides (map (\ (Rel pkgName _ _) -> pkgName) . concat . pProvides) packages (packageNameMap pName packages)

-- |TODO: Add architecture check
lookupPackageByRel :: PackageNameMap Package -> Relation -> [Package]
lookupPackageByRel pm (Rel pkgName mVerReq _) =
    case Map.lookup pkgName pm of
      Nothing -> []
      Just packages -> filter filterVer packages
    where filterVer p =
              case mVerReq of
                Nothing -> True
                Just _ ->
                    if (pName p) /= pkgName
                       then False -- package is a virtual package, hence we can not do a version req
                       else checkVersionReq mVerReq (pVersion p)


{-
      Nothing -> Nothing
      Just packages -> Just $ filter (\p -> checkVersionReq mVerReq (pVersion p)) packages
-}

tryParseRel :: Maybe Field -> Relations
tryParseRel Nothing = []
tryParseRel (Just (Field (_, relStr))) = either (error . show) id (parseRelations relStr)