render :: DynFlags -> [Flag] -> QualOption -> [Interface] -> [InstalledInterface] -> Map Module FilePath -> IO ()
render dflags flags qual ifaces installedIfaces extSrcMap = do

  let
    title                = fromMaybe "" (optTitle flags)
    unicode              = Flag_UseUnicode `elem` flags
    pretty               = Flag_PrettyHtml `elem` flags
    opt_wiki_urls        = wikiUrls          flags
    opt_contents_url     = optContentsUrl    flags
    opt_index_url        = optIndexUrl       flags
    odir                 = outputDir         flags
    opt_latex_style      = optLaTeXStyle     flags
    opt_source_css       = optSourceCssFile  flags
    opt_mathjax          = optMathjax        flags

    visibleIfaces    = [ i | i <- ifaces, OptHide `notElem` ifaceOptions i ]

    -- /All/ visible interfaces including external package modules.
    allIfaces        = map toInstalledIface ifaces ++ installedIfaces
    allVisibleIfaces = [ i | i <- allIfaces, OptHide `notElem` instOptions i ]

    pkgMod           = ifaceMod (head ifaces)
    pkgKey           = moduleUnitId pkgMod
    pkgStr           = Just (unitIdString pkgKey)
    pkgNameVer       = modulePackageInfo dflags flags pkgMod

    (srcBase, srcModule, srcEntity, srcLEntity) = sourceUrls flags

    srcModule'
      | Flag_HyperlinkedSource `elem` flags = Just hypSrcModuleUrlFormat
      | otherwise = srcModule

    srcMap = mkSrcMap $ Map.union
      (Map.map SrcExternal extSrcMap)
      (Map.fromList [ (ifaceMod iface, SrcLocal) | iface <- ifaces ])

    pkgSrcMap = Map.mapKeys moduleUnitId extSrcMap
    pkgSrcMap'
      | Flag_HyperlinkedSource `elem` flags =
          Map.insert pkgKey hypSrcModuleNameUrlFormat pkgSrcMap
      | Just srcNameUrl <- srcEntity = Map.insert pkgKey srcNameUrl pkgSrcMap
      | otherwise = pkgSrcMap

    -- TODO: Get these from the interface files as with srcMap
    pkgSrcLMap'
      | Flag_HyperlinkedSource `elem` flags =
          Map.singleton pkgKey hypSrcModuleLineUrlFormat
      | Just path <- srcLEntity = Map.singleton pkgKey path
      | otherwise = Map.empty

    sourceUrls' = (srcBase, srcModule', pkgSrcMap', pkgSrcLMap')

  libDir   <- getHaddockLibDir flags
  prologue <- getPrologue dflags flags
  themes   <- getThemes libDir flags >>= either bye return

  when (Flag_GenIndex `elem` flags) $ do
    ppHtmlIndex odir title pkgStr
                themes opt_contents_url sourceUrls' opt_wiki_urls
                allVisibleIfaces pretty
    copyHtmlBits odir libDir themes

  when (Flag_GenContents `elem` flags) $ do
    ppHtmlContents dflags odir title pkgStr
                   themes opt_mathjax opt_index_url sourceUrls' opt_wiki_urls
                   allVisibleIfaces True prologue pretty
                   (makeContentsQual qual)
    copyHtmlBits odir libDir themes

  when (Flag_Html `elem` flags) $ do
    ppHtml dflags title pkgStr visibleIfaces odir
                prologue
                themes opt_mathjax sourceUrls' opt_wiki_urls
                opt_contents_url opt_index_url unicode qual
                pretty
    copyHtmlBits odir libDir themes

  -- TODO: we throw away Meta for both Hoogle and LaTeX right now,
  -- might want to fix that if/when these two get some work on them
  when (Flag_Hoogle `elem` flags) $ do
    case pkgNameVer of
      Nothing -> putStrLn . unlines $
          [ "haddock: Unable to find a package providing module "
            ++ moduleNameString (moduleName pkgMod) ++ ", skipping Hoogle."
          , ""
          , "         Perhaps try specifying the desired package explicitly"
            ++ " using the --package-name"
          , "         and --package-version arguments."
          ]
      Just (PackageName pkgNameFS, pkgVer) ->
          let pkgNameStr | unpackFS pkgNameFS == "main" && title /= [] = title
                         | otherwise = unpackFS pkgNameFS
          in ppHoogle dflags pkgNameStr pkgVer title (fmap _doc prologue)
               visibleIfaces odir

  when (Flag_LaTeX `elem` flags) $ do
    ppLaTeX title pkgStr visibleIfaces odir (fmap _doc prologue) opt_latex_style
                  libDir

  when (Flag_HyperlinkedSource `elem` flags) $ do
    ppHyperlinkedSource odir libDir opt_source_css pretty srcMap ifaces

-- | From GHC 7.10, this function has a potential to crash with a
-- nasty message such as @expectJust getPackageDetails@ because
-- package name and versions can no longer reliably be extracted in
-- all cases: if the package is not installed yet then this info is no
-- longer available. The @--package-name@ and @--package-version@
-- Haddock flags allow the user to specify this information and it is
-- returned here if present: if it is not present, the error will
-- occur. Nasty but that's how it is for now. Potential TODO.
render :: DynFlags -> [Flag] -> QualOption -> [Interface] -> [InstalledInterface] -> Map Module FilePath -> IO ()
render dflags flags qual ifaces installedIfaces extSrcMap = do

  let
    title                = fromMaybe "" (optTitle flags)
    unicode              = Flag_UseUnicode `elem` flags
    pretty               = Flag_PrettyHtml `elem` flags
    opt_wiki_urls        = wikiUrls          flags
    opt_contents_url     = optContentsUrl    flags
    opt_index_url        = optIndexUrl       flags
    odir                 = outputDir         flags
    opt_latex_style      = optLaTeXStyle     flags
    opt_source_css       = optSourceCssFile  flags
    opt_mathjax          = optMathjax        flags

    visibleIfaces    = [ i | i <- ifaces, OptHide `notElem` ifaceOptions i ]

    -- /All/ visible interfaces including external package modules.
    allIfaces        = map toInstalledIface ifaces ++ installedIfaces
    allVisibleIfaces = [ i | i <- allIfaces, OptHide `notElem` instOptions i ]

    pkgMod           = ifaceMod (head ifaces)
    pkgKey           = moduleUnitId pkgMod
    pkgStr           = Just (unitIdString pkgKey)
    pkgNameVer       = modulePackageInfo dflags flags pkgMod

    (srcBase, srcModule, srcEntity, srcLEntity) = sourceUrls flags

    srcModule'
      | Flag_HyperlinkedSource `elem` flags = Just hypSrcModuleUrlFormat
      | otherwise = srcModule

    srcMap = mkSrcMap $ Map.union
      (Map.map SrcExternal extSrcMap)
      (Map.fromList [ (ifaceMod iface, SrcLocal) | iface <- ifaces ])

    pkgSrcMap = Map.mapKeys moduleUnitId extSrcMap
    pkgSrcMap'
      | Flag_HyperlinkedSource `elem` flags =
          Map.insert pkgKey hypSrcModuleNameUrlFormat pkgSrcMap
      | Just srcNameUrl <- srcEntity = Map.insert pkgKey srcNameUrl pkgSrcMap
      | otherwise = pkgSrcMap

    -- TODO: Get these from the interface files as with srcMap
    pkgSrcLMap'
      | Flag_HyperlinkedSource `elem` flags =
          Map.singleton pkgKey hypSrcModuleLineUrlFormat
      | Just path <- srcLEntity = Map.singleton pkgKey path
      | otherwise = Map.empty

    sourceUrls' = (srcBase, srcModule', pkgSrcMap', pkgSrcLMap')

  libDir   <- getHaddockLibDir flags
  prologue <- getPrologue dflags flags
  themes   <- getThemes libDir flags >>= either bye return

  when (Flag_GenIndex `elem` flags) $ do
    ppHtmlIndex odir title pkgStr
                themes opt_contents_url sourceUrls' opt_wiki_urls
                allVisibleIfaces pretty
    copyHtmlBits odir libDir themes

  when (Flag_GenContents `elem` flags) $ do
    ppHtmlContents dflags odir title pkgStr
                   themes opt_mathjax opt_index_url sourceUrls' opt_wiki_urls
                   allVisibleIfaces True prologue pretty
                   (makeContentsQual qual)
    copyHtmlBits odir libDir themes

  when (Flag_Html `elem` flags) $ do
    ppHtml dflags title pkgStr visibleIfaces odir
                prologue
                themes opt_mathjax sourceUrls' opt_wiki_urls
                opt_contents_url opt_index_url unicode qual
                pretty
    copyHtmlBits odir libDir themes

  -- TODO: we throw away Meta for both Hoogle and LaTeX right now,
  -- might want to fix that if/when these two get some work on them
  when (Flag_Hoogle `elem` flags) $ do
    case pkgNameVer of
      Nothing -> putStrLn . unlines $
          [ "haddock: Unable to find a package providing module "
            ++ moduleNameString (moduleName pkgMod) ++ ", skipping Hoogle."
          , ""
          , "         Perhaps try specifying the desired package explicitly"
            ++ " using the --package-name"
          , "         and --package-version arguments."
          ]
      Just (PackageName pkgNameFS, pkgVer) ->
          let pkgNameStr | unpackFS pkgNameFS == "main" && title /= [] = title
                         | otherwise = unpackFS pkgNameFS
          in ppHoogle dflags pkgNameStr pkgVer title (fmap _doc prologue)
               visibleIfaces odir

  when (Flag_LaTeX `elem` flags) $ do
    ppLaTeX title pkgStr visibleIfaces odir (fmap _doc prologue) opt_latex_style
                  libDir

  when (Flag_HyperlinkedSource `elem` flags) $ do
    ppHyperlinkedSource odir libDir opt_source_css pretty srcMap ifaces

-- | From GHC 7.10, this function has a potential to crash with a
-- nasty message such as @expectJust getPackageDetails@ because
-- package name and versions can no longer reliably be extracted in
-- all cases: if the package is not installed yet then this info is no
-- longer available. The @--package-name@ and @--package-version@
-- Haddock flags allow the user to specify this information and it is
-- returned here if present: if it is not present, the error will
-- occur. Nasty but that's how it is for now. Potential TODO.
render dflags flags qual ifaces installedIfaces extSrcMap = do

  let
    title                = fromMaybe "" (optTitle flags)
    unicode              = Flag_UseUnicode `elem` flags
    pretty               = Flag_PrettyHtml `elem` flags
    opt_wiki_urls        = wikiUrls          flags
    opt_contents_url     = optContentsUrl    flags
    opt_index_url        = optIndexUrl       flags
    odir                 = outputDir         flags
    opt_latex_style      = optLaTeXStyle     flags
    opt_source_css       = optSourceCssFile  flags
    opt_mathjax          = optMathjax        flags

    visibleIfaces    = [ i | i <- ifaces, OptHide `notElem` ifaceOptions i ]

    -- /All/ visible interfaces including external package modules.
    allIfaces        = map toInstalledIface ifaces ++ installedIfaces
    allVisibleIfaces = [ i | i <- allIfaces, OptHide `notElem` instOptions i ]

    pkgMod           = ifaceMod (head ifaces)
    pkgKey           = moduleUnitId pkgMod
    pkgStr           = Just (unitIdString pkgKey)
    pkgNameVer       = modulePackageInfo dflags flags pkgMod

    (srcBase, srcModule, srcEntity, srcLEntity) = sourceUrls flags

    srcModule'
      | Flag_HyperlinkedSource `elem` flags = Just hypSrcModuleUrlFormat
      | otherwise = srcModule

    srcMap = mkSrcMap $ Map.union
      (Map.map SrcExternal extSrcMap)
      (Map.fromList [ (ifaceMod iface, SrcLocal) | iface <- ifaces ])

    pkgSrcMap = Map.mapKeys moduleUnitId extSrcMap
    pkgSrcMap'
      | Flag_HyperlinkedSource `elem` flags =
          Map.insert pkgKey hypSrcModuleNameUrlFormat pkgSrcMap
      | Just srcNameUrl <- srcEntity = Map.insert pkgKey srcNameUrl pkgSrcMap
      | otherwise = pkgSrcMap

    -- TODO: Get these from the interface files as with srcMap
    pkgSrcLMap'
      | Flag_HyperlinkedSource `elem` flags =
          Map.singleton pkgKey hypSrcModuleLineUrlFormat
      | Just path <- srcLEntity = Map.singleton pkgKey path
      | otherwise = Map.empty

    sourceUrls' = (srcBase, srcModule', pkgSrcMap', pkgSrcLMap')

  libDir   <- getHaddockLibDir flags
  prologue <- getPrologue dflags flags
  themes   <- getThemes libDir flags >>= either bye return

  when (Flag_GenIndex `elem` flags) $ do
    ppHtmlIndex odir title pkgStr
                themes opt_contents_url sourceUrls' opt_wiki_urls
                allVisibleIfaces pretty
    copyHtmlBits odir libDir themes

  when (Flag_GenContents `elem` flags) $ do
    ppHtmlContents dflags odir title pkgStr
                   themes opt_mathjax opt_index_url sourceUrls' opt_wiki_urls
                   allVisibleIfaces True prologue pretty
                   (makeContentsQual qual)
    copyHtmlBits odir libDir themes

  when (Flag_Html `elem` flags) $ do
    ppHtml dflags title pkgStr visibleIfaces odir
                prologue
                themes opt_mathjax sourceUrls' opt_wiki_urls
                opt_contents_url opt_index_url unicode qual
                pretty
    copyHtmlBits odir libDir themes

  -- TODO: we throw away Meta for both Hoogle and LaTeX right now,
  -- might want to fix that if/when these two get some work on them
  when (Flag_Hoogle `elem` flags) $ do
    case pkgNameVer of
      Nothing -> putStrLn . unlines $
          [ "haddock: Unable to find a package providing module "
            ++ moduleNameString (moduleName pkgMod) ++ ", skipping Hoogle."
          , ""
          , "         Perhaps try specifying the desired package explicitly"
            ++ " using the --package-name"
          , "         and --package-version arguments."
          ]
      Just (PackageName pkgNameFS, pkgVer) ->
          let pkgNameStr | unpackFS pkgNameFS == "main" && title /= [] = title
                         | otherwise = unpackFS pkgNameFS
          in ppHoogle dflags pkgNameStr pkgVer title (fmap _doc prologue)
               visibleIfaces odir

  when (Flag_LaTeX `elem` flags) $ do
    ppLaTeX title pkgStr visibleIfaces odir (fmap _doc prologue) opt_latex_style
                  libDir

  when (Flag_HyperlinkedSource `elem` flags) $ do
    ppHyperlinkedSource odir libDir opt_source_css pretty srcMap ifaces

-- | From GHC 7.10, this function has a potential to crash with a
-- nasty message such as @expectJust getPackageDetails@ because
-- package name and versions can no longer reliably be extracted in
-- all cases: if the package is not installed yet then this info is no
-- longer available. The @--package-name@ and @--package-version@
-- Haddock flags allow the user to specify this information and it is
-- returned here if present: if it is not present, the error will
-- occur. Nasty but that's how it is for now. Potential TODO.