content: {-# OPTIONS_GHC -fno-warn-missing-signatures #-}
  module Options.Documentation where
  import qualified Data.Set as S
  import qualified Data.List as L
  import qualified Data.Map as M
  import Data.String.Util
  
  data Topic = Topic { title :: String, content :: String } 
  instance Eq Topic where
    l == r = title l == title r
  instance Ord Topic where
    compare l r = compare (title l) (title r)
  
  type Tag = String 
  
  type Documentation = M.Map Tag Topic 
  
  tags :: Documentation -> [String] 
  tags = M.keys 
  
  cabalSourcingTopic = 
    Topic "cabal sourcing" $
      listing [
        "This command pulls package selections from a cabal file",
        "  e.g. -c <project.cabal>\n",
        "Note:",
        "This command is not the same as a db provider.", 
        "Note:",
        "If the package occurs more than once in the cabal file", 
        "with different range, neither package is taken.\n", 
        "Pulled packages can be constrained, see: cabal-constraints." 
        ]
  
  outputTopic =
    Topic "output" $ listing [
       "For each package sourced by dash-haskell, a matching docset"
     , "will be written under this directory in its version, e.g:"
     , " \"output/package-1.2.3.docset\""
    ]
  
  nouserTopic =
    Topic "no-user" $ listing [
      "the no-user flag removes the user package db, e.g. :"
      , "~/.ghc/x86_64-linux-7.10.1/package.conf.d/"
      , "from db consideration"
      ]
  
  dbTopic   =
    Topic "package database directory" $ listing [
      "a db directory to directly use as the package database,",
      "this is ordered as a \'dir\' in the db stack"
      ]
  
  orderingTopic   =
    Topic "ordering" $ listing [
      "an ordering of package db's, in that this is the order in which",
      "dbs are examined for packages to use for documentation conversion",
      "\n",
      "Note: The global db must always appear, and it always first. This",
      "is due to upstream constraints in ghc right now. (05/30/205)."
      ]
  
  packageTopic =
    Topic "package" $ "a ghc package, e.g. either, or either-4.1.0"
  
  toEntry :: S.Set String -> Topic -> Documentation -> Documentation 
  toEntry s t doc = L.foldl (\m' k -> M.insert k t m') doc $ S.toList s 
  
  docs :: Documentation
  docs = 
    let fromListing m (t,l) = toEntry (S.fromList l) t m in 
      L.foldl fromListing M.empty [
        (cabalSourcingTopic    , ["c", "cabal"]),
        (outputTopic           , ["o", "outputdir", "output", "docset"]),
        (packageTopic          , ["packages", "package"]),
        (nouserTopic           , ["n", "no-user", "user"]),
        (dbTopic               , ["db", "dir"]),
        (orderingTopic         , ["d", "ordering"])
        ]
  
  -- | Given an arbitrary stream of options,
  -- convert to possible topic indexes for documentation look-up.
  toIndexes :: [String] -> [String] 
  toIndexes = S.toList . S.fromList . map toTopic  
    where
      toTopic :: String -> String
      toTopic [] = [] 
      toTopic ('-':rest) = toTopic rest 
      toTopic remainder  = remainder 
  
  toHelp :: Documentation -> [String] -> IO () 
  toHelp d [] = 
    putStrLn $ "available help topics:\n" ++ L.intercalate ", " (tags d)
  toHelp d args = 
    -- fold over each index, producing a list of docs to display 
    let topic_set = L.foldl folded S.empty $ toIndexes args in 
    if S.null topic_set then do 
      putStrLn "Sorry, no documentation available for expressions given.\n"
      toHelp docs [] 
    else do
      putStrLn "accessing help on topics,"
      putStrLn $ indenting 2 (listing . L.map headed $ S.toList topic_set)
    where 
      headed :: Topic -> String 
      headed topic =
        ' ':title topic ++ ':':'\n':'\n': indenting 2 (content topic)
  
      folded :: S.Set Topic -> String -> S.Set Topic
      folded s index = maybe s (`S.insert` s) $ M.lookup index d
  