import Text.Printf
import qualified Data.Map as Map
--import Data.Function
import Data.List
import Control.Monad

data Status
   = Accepted
   | Complete
   | Discussion
   | Old  -- from the old process, these proposals have wiki pages but no owner
   | Old_Reject  -- from the old process, these proposals have wiki pages but no owner
   deriving (Eq, Ord, Show)

data Section
   = NotApplicable
   | Introduction
   | Lexical
   | Expressions
   | DeclarationsBindings
   | Modules
   | PredefinedTypesClasses
   | FFI
   | Concurrency
   | BasicIO
   | Prelude
   | SpecificationDerivedInstances
   | CompilerPragmas
   | Syntax  -- those bits of "Syntax Reference" that aren't 
             -- repeated in other sections
   | Libraries
   deriving (Eq, Ord, Enum)

showSection :: Section -> String
showSection NotApplicable                 = "N/A"
showSection Introduction                  = "Introduction"
showSection Lexical                       = "Lexical"
showSection Expressions                   = "Expressions"
showSection DeclarationsBindings          = "Declarations and Bindings"
showSection Modules                       = "Modules"
showSection PredefinedTypesClasses        = "Predefined Types and Classes"
showSection FFI                           = "FFI"
showSection Concurrency                   = "Concurrency"
showSection BasicIO                       = "Basic I/O"
showSection Prelude                       = "Standard Prelude"
showSection SpecificationDerivedInstances = "Specification of Derived Instances"
showSection CompilerPragmas               = "Compiler Pragmas"
showSection Syntax                        = "Syntax Reference"
showSection Libraries                     = "Libraries"

data Issue = Issue {
  name    :: String, -- wiki link
  tickets :: [Int],    -- ticket number(s)
  status  :: Status, 
  section :: Section,
  notes   :: [String] -- notes
 }

cmp_stat (_,_,s1,_) (_,_,s2,_) = s1 `compare` s2
eq_stat  (_,_,s1,_) (_,_,s2,_) = s1 == s2

issues :: [Issue]
issues = [
 Issue "add [wiki:Concurrency]" [74] 
    Old Concurrency
    ["draft text: [wiki:Concurrency/DraftReportText]"]
 
 ,Issue "add ForeignFunctionInterface" [35] 
    Old FFI []
			
 ,Issue "add multi-parameter type classes (MultiParamTypeClasses)"  [49] 
    Old DeclarationsBindings ["see MultiParamTypeClassesDilemma"]

 ,Issue "add [wiki:RankNTypes] or [wiki:Rank2Types]" [60]
    Old
    DeclarationsBindings ["RankN or Rank2?"]

 ,Issue "add PolymorphicComponents" [57]
    Old
    DeclarationsBindings
    ["Draft available", "dependency on Rank2Types or RankNTypes"]

 ,Issue "add ExistentialQuantification (existential components)" [26]
    Old 
    DeclarationsBindings
    ["syntax of existentials"]

 ,Issue "add HierarchicalModules" [24]
    Old
    Modules
    ["See [http://www.haskell.org/hierarchical-modules/ addendum]"]

 ,Issue "add EmptyDataDeclarations" [25]
    Old
    DeclarationsBindings
    ["dependency on KindAnnotations"]

 ,Issue "add InfixTypeConstructors" [78]
    Old 
    DeclarationsBindings []

 ,Issue "remove FixityResolution from the context-free grammar" [30]
   Old
   Expressions []

 ,Issue "ImpreciseExceptions" [39]
   Old_Reject Libraries []

 ,Issue "DoAndIfThenElse for case-statements too?" []
   Old Syntax []

 ,Issue "allow TypeSynonymInstances" [70]
    Old
    DeclarationsBindings
    ["superseded by NewtypeDeriving?", 
     "Not very useful without FlexibleInstances and/or OverlappingInstances"]

 ,Issue "RelaxedDependencyAnalysis" [65] 
   Old 
   DeclarationsBindings []

 ,Issue "NondecreasingIndentation" [53]
   Old 
   Syntax []

 ,Issue "fix the lexical syntax for QualifiedIdentifiers" [39]
   Old
   Lexical
   ["permit qualified identifiers in definitions?",
    "interaction with CompositionAsDot"]

 ,Issue "FlexibleInstances" [32] 
   Old
   DeclarationsBindings 
   ["choice of instance conditions for termination of typechecking",
    "poor interaction with NewtypeDeriving?"]

 ,Issue "add NewPragmas" [51]
   Old
   CompilerPragmas
   ["choose specific pragmas to standardize"]

 ,Issue "make [wiki:Underscore] caseless" [72]
   Old_Reject
   Lexical
   ["treatment of underscore-only identifiers"]

 ,Issue "BangPatterns" [76] 
   Old
   Expressions
   ["top-level bang patterns",
    "interaction with ! as an operator",
    "bang-pattern polymorphism",
    "existentials and bang patterns",
    "interaction with MonomorphicPatternBindings"]

 ,Issue "ScopedTypeVariables" [67, 81] 
   Old
   DeclarationsBindings
   ["specification of syntax that binds type variables"]

 ,Issue "generalized deriving for newtype (NewtypeDeriving)" [52] 
   Old
   DeclarationsBindings
   ["specification that does not use the term \"the same representation\"",
    "overlap with TypeSynonymInstances"]

 ,Issue "improve [wiki:Defaulting] rules" [21]
   Old
   DeclarationsBindings
   ["scope of default clauses", 
    "impact on existing defaults"]

 ,Issue "KindAnnotations" [84]
   Old 
   DeclarationsBindings []

 ,Issue "MonomorphicPatternBindings" [103]
   Old_Reject
   DeclarationsBindings 
   ["treatment of pattern bindings with explicit type signatures"]

 ,Issue "SpecifyPatternBindingSemantics" []
   Old
   DeclarationsBindings
   []

 ,Issue "add [wiki:Arrows]" [13]
   Old_Reject
   Expressions []

 ,Issue "fix comment syntax grammar (LineCommentSyntax)" [42]
   Complete
   Lexical []

 ,Issue "add PatternGuards" [56]
   Complete
   Expressions []

 ,Issue "DoAndIfThenElse" [23]  
   Complete
   Syntax []

 ,Issue "more liberal kind inference" [85]
   Old
   DeclarationsBindings []

 ,Issue "standardize the System.FilePath module" [89]
   Old
   Libraries []

 ,Issue "add a binary IO interface" [15]
   Old
   Libraries []

 ,Issue "add Flexible Contexts" [31]
   Old
   DeclarationsBindings []

 ,Issue "[wiki:Natural] numbers" [79]
   Old
   PredefinedTypesClasses
   ["[http://www.haskell.org/mailman/private/haskell-prime-private/2008-March/000529.html]"]

 ,Issue "[wiki:CompositionAsDot Eliminate . as an operator]" [20]
   Old_Reject
   Lexical []

 ,Issue "replace the Read class" [61]
   Old
   Libraries []

 ,Issue "[wiki:ArrayIndexing Replace the array indexing operator] '!'" [96]
   Old
   Libraries []

 ,Issue "improve module interfaces" [95]
   Old
   Modules []

 ,Issue "add PartialTypeAnnotations" [86]
   Old_Reject
   DeclarationsBindings []

 ,Issue "allow data constructors to be exported and imported readonly" [62]
   Old_Reject
   Modules []

 ,Issue "[wiki:Prelude] re-organisation proposal" [58]
   Old
   Prelude []

 ,Issue "add [wiki:ParallelListComp Parallel List comprehensions]" [55]
   Old_Reject
   Expressions []

 ,Issue "get rid of unary '-' operator" [50]
   Old
   Expressions []

 ,Issue "clarify module system proposals" [48]
   Old
   Modules []

 ,Issue "add MagicUnderscore" [44]
   Old_Reject
   Expressions []

 ,Issue "add LambdaCase" [41]
   Old_Reject
   Expressions []

 ,Issue "add ForeignData" [34]
   Old
   FFI []

 ,Issue "add Blockable" [33]
   Old
   FFI []

 ,Issue "Require explicit quantification on all expression bound type signatures" [28]
   Old_Reject
   Expressions []

 ,Issue "add First Class Labels" [92]
   Old
   DeclarationsBindings []

 ,Issue "Move existing named field (record) system to an addendum" [99]
   Old_Reject
   NotApplicable []

 ,Issue "Replace named fields with an extensible record system" [100]
   Old_Reject
   NotApplicable []

 ,Issue "[wiki:MonomorphismRestriction/Remove Remove the monomorphism restriction]" [80]
   Old
   DeclarationsBindings []

 ,Issue "[wiki:MonomorphismRestriction/MonomorphicBindingOperator Add a monomorphic binding operator]" [80]
   Old
   DeclarationsBindings []

 ,Issue "[wiki:MonomorphismRestriction/MonomorphicBindingSyntax Add monomorphic binding syntax]" [80]
   Old
   DeclarationsBindings []

 ,Issue "[wiki:MonomorphismRestriction/Optional]" [80]
   Old_Reject
   DeclarationsBindings []

 ,Issue "[wiki:MonomorphismRestriction/MonomorphicVariableAndPatternBindings]" [80]
   Old_Reject
   DeclarationsBindings []

 ,Issue "Allow import declarations anywhere at the top level" [82]
   Old_Reject
   Modules []

 ,Issue "unified and extensible annotations" [88]
   Old
   CompilerPragmas []

 ,Issue "control export and import of class instances" [19]
   Old_Reject
   Modules []

 ,Issue "relax restriction on signatures of class methods" [17]
   Old
   DeclarationsBindings []

 ,Issue "Eliminate tabs" [68]
   Old
   Lexical []

 ,Issue "add recursive do syntax" [64]
   Old
   Expressions []

 ,Issue "add GADTs" [37]
   Old
   DeclarationsBindings []

 ,Issue "add views" [73]
   Old_Reject
   DeclarationsBindings []

 ,Issue "Allow Undecidable Instances" [71]
   Old
   DeclarationsBindings []

 ,Issue "add overlapping or incoherent instances" [54]
   Old
   DeclarationsBindings []

 ,Issue "add Linear implicit params" [43]
   Old_Reject
   DeclarationsBindings []

 ,Issue "add FunctionalDependencies" [36]
   Old
   DeclarationsBindings []

 ,Issue "add MultiWayIf" [77]
   Old_Reject
   Expressions []

 ,Issue "allow tuple sections" [69]
   Old_Reject
   Expressions []

 ,Issue "add implicit parameters" [38]
   Old_Reject
   DeclarationsBindings []

 ,Issue "add Associated Types" [14]
   Old
   DeclarationsBindings []

 ,Issue "add closed classes" [18]
   Old
   DeclarationsBindings
   ["[http://www.haskell.org/mailman/private/haskell-prime-private/2008-March/000535.html]"]

 ,Issue "Class aliases" [101]
   Old_Reject
   DeclarationsBindings []

 ,Issue "namespace cleanup: TagExportsWithNamespace ModuleSystem" []
   Old
   Modules []

 ,Issue "Remove n+k patterns" []
   Old
   Expressions
   ["see RemovalCandidates"]

 ,Issue "Remove ~ patterns" []
   Old
   Expressions
   ["see RemovalCandidates"]

 ,Issue "Remove class context on data definitions" []
   Old
   DeclarationsBindings
   ["see RemovalCandidates"]

 ,Issue "[http://www.haskell.org/mailman/private/haskell-prime-private/2008-March/000557.html require space around dot as operator]" [] 
    Old
    Lexical
    ["See also #20 QualifiedIdentifiers",
     "See also CompositionAsDot"]

 ,Issue "[wiki:ExistingRecords#Punning Re-allow record punning]" [] 
    Old 
    Expressions []

 ,Issue "[wiki:ExistingRecords#Update updating non-existant record fields]" []
    Old
    Expressions []

 ,Issue "[wiki:ExistingRecords#Label-basedpattern-matching Label-based pattern-matching]" [] 
    Old
    Expressions []

 ,Issue "[wiki:ExistingRecords#First-classsyntax First-class record syntax]" []
    Old 
    DeclarationsBindings []

 ,Issue "[wiki:ExistingRecords#Polymorphicrecordupdate Polymorphic record update]" []
    Old
    Expressions []

 ,Issue "[wiki:ExistingRecords#Openstatement Open statement]" []
    Old
    Expressions []

 ,Issue "[wiki:ExistingRecords#Abstraction Record abstraction tweak]" []
    Old
    DeclarationsBindings []

 ,Issue "[wiki:ExistingRecords#PolymorphicRecordUpdatetakeII Polymorphic record update take II]" [] 
    Old
    Expressions []

 ,Issue "Remove upper/lower case distinction" [] 
    Old
    Lexical []

 ,Issue "[wiki:RemoveStringGaps Remove string gaps]" [] 
    Old_Reject
    Lexical []

 ,Issue "[http://www.haskell.org/ghc/docs/latest/html/users_guide/type-class-extensions.html#overloaded-strings Overload string literals]" [] 
    Old
    Expressions
    []

 ,Issue "RecordPatternMatching" [] 
    Old
    Expressions
    []

 ,Issue "Disambiguate record fields" [] 
    Old
    Expressions
    ["[http://www.haskell.org/ghc/docs/latest/html/users_guide/syntax-extns.html#disambiguate-fields GHC Users Guide]"]

 ,Issue "[wiki:DerivedInstances#Standalonederivedinstances Standalone Derived Instances]" []
    Old
    DeclarationsBindings
    []

 ,Issue "LiberalTypeSynonyms" [] 
     Old
     DeclarationsBindings
     ["subsumes TypeSynonymInstances"]

 ,Issue "Simpler layout specification" []
     Old 
     Syntax
     ["[http://repetae.net/repos/getlaid/]"]

 ,Issue "[wiki:DerivingInstances]" []
     Old
     DeclarationsBindings
     []

 ,Issue "Change the syntax of QualifiedOperators" []
     Old
     Lexical
     []

 ,Issue "[wiki:ChangeDollarAssociativity Make $ left associative, like application]" []
     Old
     Prelude
     []

 ,Issue "[http://www.haskell.org/pipermail/haskell-prime/2008-April/002569.html Instance declarations can use qualified names]" []
     Old
     DeclarationsBindings
     []

 ,Issue "Allow GADT syntax for data types" []
     Old
     DeclarationsBindings
     []

 ,Issue "[wiki:ImportShadowing Local declarations shadow imports]" []
     Old
     Modules
     []
 ]


main = do
  putStrLn "[[PageOutline]]"
  putStrLn "== Haskell' Status Page =="
  putStrLn "DO NOT EDIT!  This page is automatically generated by [http://darcs.haskell.org/haskell-prime-status/status.hs]"
  -- generate wiki table
 
  let m = Map.fromListWith (++) [(status issue, [issue]) | issue <- issues ]
      [accepts,completes,discussions,olds,old_rejects] = 
         [ sortBySection (Map.findWithDefault [] k m)
         | k <- [Accepted,Complete,Discussion,Old,Old_Reject] ]

  when (not (null accepts)) $ do
    putStrLn "=== Accepted Proposals ==="
    dumpTable accepts
  
  when (not (null completes)) $ do
    putStrLn "=== Complete Proposals ==="
    dumpTable completes
  
  when (not (null discussions)) $ do
    putStrLn "=== Proposals under discussion ==="
    dumpTable discussions
  
  when (not (null olds)) $ do
    putStrLn "=== Old Proposals (needing owners) ==="
    dumpTable olds
  
  when (not (null olds)) $ do
    putStrLn "=== Old Proposals (provisionally rejected) ==="
    dumpTable old_rejects
  
  putStrLn "== Issues by Section =="
  
  let m = Map.fromListWith (++) [(section issue, [issue]) | issue <- issues ]
      secs = [ (sec, filter (not.(==Old_Reject).status) $ 
                     sortByStatus $ 
                     Map.findWithDefault [] sec m)
             | sec <- [NotApplicable ..] ]

  mapM_ dumpSection secs

dumpTable issues = putStr (unlines (concatMap toWikiTable issues))
  where
    toWikiTable :: Issue -> [String]
    toWikiTable Issue{name=name, tickets=tickets, status=status, 
                      section=section, notes=notes} 
      = printf "|| %s || %s || %s || %s"
          name
          (unwords (map (('#':) . show) tickets))
          (showSection section)
          (firstnote notes)
        : extranotes notes

dumpSection (sec, issues) = do
  putStrLn ("=== Section: " ++ showSection sec ++ " ===")
  putStr (unlines (concatMap toWikiTable issues))
  where
    toWikiTable :: Issue -> [String]
    toWikiTable Issue{name=name, tickets=tickets, status=status, 
                       section=section, notes=notes} 
      = printf "|| %s || %s || %s || %s"
          name
          (unwords (map (('#':) . show) tickets))
          (wikiStat status)
          (firstnote notes)
        : extranotes notes

firstnote [] = ""
firstnote (x:xs) = x

extranotes []  = []
extranotes [x] = []
extranotes (x:xs) = map (printf "|| || || || %s") xs
  
sortBySection = sortBy (compare `on` section)
sortByStatus  = sortBy (compare `on` status)
 
wikiStat Accepted     = "accepted"
wikiStat Complete     = "complete"
wikiStat Discussion   = "definition"
wikiStat Old          = "old"
wikiStat Old_Reject   = "old (rejected)"

-- In Data.Function in GHC >=6.8
on :: (b -> b -> c) -> (a -> b) -> a -> a -> c
(*) `on` f = \x y -> f x * f y
