module DistroInfo (Distro, splitDistroInfo, getDistroInfo) where

import qualified Data.Map as Map
import Control.Monad
import Distribution.Package
import Distribution.Version	( Version )
import Text.XHtml		( URL )
import Locations
import System.IO
import System.FilePath
import PublicFile
import Util
import Distribution.Text(simpleParse)
import System.IO.Error
import System.Directory

-- | Could be extended to a ADT with explicitly known distros, to e.g. link to
-- an icon
type Distro = String

type DistroInfo = [(Distro, Version, Maybe URL)]

type DistroMap = Map.Map PackageName (DistroInfo)

distromapDir :: FilePath
distromapDir = localFile archiveDir </> "00-distromap"

getDistroMap :: IO DistroMap
getDistroMap = do
        distros <- dirContents distromapDir
        maps <- mapM getDistoMapFor distros
        return $ foldr (Map.unionWith (++)) Map.empty maps

getDistoMapFor :: Distro -> IO DistroMap
getDistoMapFor distro =
	withFile (distrMapFile distro) ReadMode ( \ h -> do
                s <- hGetContents h
                return $! foldr parseDistroLine Map.empty (lines s)
        ) `catch`
                const (return Map.empty)
 where parseDistroLine str = case simpleParse version of
		  Just parsed_version -> Map.unionWith (++) (Map.singleton parsed_package [(distro,parsed_version,url)])
		  Nothing             -> id
	  where (package, version, url) = read str :: (String, String, Maybe String)
	     	parsed_package = PackageName package

distrMapFile :: Distro -> FilePath
distrMapFile distro = distromapDir </> distro

distroInfoFile :: PackageName -> FilePath
distroInfoFile pkg_name = localFile (unversionedPackageDir pkg_name) </> "distroinfo"

getDistroInfo :: PackageName -> IO DistroInfo
getDistroInfo pkg_name = withFile (distroInfoFile pkg_name) ReadMode ( \ h -> do
                s <- hGetContents h
                return $! read s
        ) `catch`
                const (return [])

writeDistroInfo :: PackageName -> DistroInfo -> IO ()
writeDistroInfo pname distroInfo =
	writeFile (distroInfoFile pname) (show distroInfo)
	`catch` (\e -> if isDoesNotExistError e then return () else ioError e)

removeDistroInfo :: PackageName -> IO ()
removeDistroInfo pname =
	removeFile (distroInfoFile pname)
	`catch` (\e -> if isDoesNotExistError e then return () else ioError e)

splitDistroInfo :: IO ()
splitDistroInfo = do
	dm <- getDistroMap
	forM_ (Map.toList dm) $ uncurry writeDistroInfo

	-- In case some packages have dropped from all distros
	pkgs <- availablePackages
	forM_ pkgs $ \pkg ->  if pkg `Map.notMember` dm
                              then removeDistroInfo pkg
	                      else return ()

