module HAHP.Reporting where

import           Data.List
import qualified Data.Map                      as M
import           Data.Time
import           HAHP.Data
import           Numeric.LinearAlgebra.HMatrix
import           Text.Printf

-- * Report making

-- | Given a title, an author and a timestamp, builds a Pandoc Markdown document header
reportHeader :: String  -- ^ Report title
             -> String  -- ^ Report author
             -> UTCTime -- ^ Report timestamp
             -> String  -- ^ Report header
reportHeader title author time = unlines
    [ "% " ++ title
    , "% " ++ author
    , "% " ++ showGregorian(utctDay time)
    ]

-- | Print a simple report about an AHP tree and ranking result
simpleSummary :: (AHPDataSet, [TreeError], [AlternativesError]) -- ^ AHP tree, some alternatives and the result of tree validation
              -> String                                                     -- ^ Report build from input
simpleSummary ((ahpTree, alts), treeErrors, altsErrors) =  treeSummary ++ altSummary ++ errorSummary ++ "\\newpage \n"
    where treeSummary = showConfiguration ahpTree
          altSummary = showAlternatives alts
          errorSummary = showErrors treeErrors altsErrors

-- | Print an AHP tree and some additional information about it
showConfiguration :: AHPTree -- ^ AHP tree
                  -> String  -- ^ Report about the AHP tree
showConfiguration ahpTree = unlines $
    [ "# Configuration \"" ++ name ahpTree ++ "\""
    , ""
    , "## AHP tree preview"
    , ""
    ]
    ++
    lines (showAhpTree ahpTree)

-- * Errors

showErrors :: [TreeError]         -- ^ List of errors
           -> [AlternativesError] -- ^ List of errors
           -> String              -- ^ Report errors
showErrors treeErrors altsErrors = unlines $
    [ ""
    , "## Input data validation"
    , ""
    , "### Summary"
    , ""
    , if null treeErrors
        then "This tree is valid"
        else "This tree is NOT valid"
    , ""
    , if null altsErrors
        then "Theses alternatives are valid"
        else "Theses alternatives are NOT valid"
    , ""
    , "### Tree errors"
    , ""
    ]
    ++
    lines (concatMap showTreeError treeErrors)
    ++
    [ ""
    , "### Alternatives errors"
    , ""
    ]
    ++
    lines (concatMap showAltsError altsErrors)


showTreeError :: TreeError
              -> String
showTreeError validationError = "* in \"" ++ (name . ahpTree $ validationError) ++ "\": " ++
    case validationError of
        (ConsistencyError ahpTree consistencyTreshold consistency) ->
            "too much unconsistency, $value = " ++ printf "%.4f" consistency ++ "$, $treshold = " ++ show consistencyTreshold ++ "$\n"
        (ChildrenUnicityError ahpTree repeated) ->
            "repeated children names: " ++ show repeated ++ "\n"
        (InverseError ahpTree) ->
            "preference values $M(i,j) \\neq \\dfrac{1}{M(j,i)}$" ++ "\n"
        (LeavesUnicityError ahpTree repeated) ->
            "repeated leaves names: " ++ show repeated ++ "\n"
        (NotComputedConsistencyError ahpTree) ->
            "consistency not computed !" ++ "\n"
        (NotUnitaryDiagError ahpTree) ->
            "diagonal is not '1'" ++ "\n"
        (NullDivisionError ahpTree) ->
            "divide by zero !" ++ "\n"
        (ParentChildrenSizeMismatchError ahpTree parent children) ->
            "parent and child size mismatch, $parent size = " ++ show parent ++ "$, $children size = " ++ show children ++ "$\n"
        (PositivePreferenceError ahpTree) ->
            "one or more preference value is $\\leq 0$ !" ++ "\n"
        (SquareMatrixError ahpTree rows cols) ->
            "matrix not square, $rows = " ++ show rows ++ "$, $columns = " ++ show cols ++ "$\n"

showAltsError :: AlternativesError
              -> String
showAltsError altError = "* " ++
    case altError of
        NoAlternativesError ->
            "no alternatives !" ++ "\n"
        (AlternativesUnicityError names) ->
            "repeated alternatives names: " ++ show names ++ "\n"
        (IndicatorsValuesExistenceError errors) ->
            "missing indicators values:" ++ show (map (\x -> ((altName . fst) x, snd x)) errors) ++ "\n"

-- * Alternatives printing

-- | Print AHP Alternatives and some additional information about them
showAlternatives :: [Alternative] -- ^ AHP Alternatives
                 -> String        -- ^ Report alternatives with indicator values
showAlternatives alts = unlines $
    [ ""
    , "## Alternatives values"
    , ""
    ]
    ++
    lines (concatMap (showAlternative 0) alts)

-- | Print an AHP Alternative and some additional information about it
showAlternative :: Int         -- ^ Deep level. Used to intercalate separators
                -> Alternative -- ^ Alternative
                -> String      -- ^ Report about the alternative
showAlternative level a = unlines $
    (tabs ++ "1. " ++ altName a)
    :
    lines (showIndicatorValues (level + 1) (indValues a))
  where tabs = variableTabs level

-- | Print an AHP IndicatorValues wit name and value
showIndicatorValues :: Int              -- ^ Deep level. Used to intercalate separators
                    -> IndicatorValues  -- ^ IndicatorValues
                    -> String           -- ^ Report about the values
showIndicatorValues level values = unlines $
    [ tabs ++ ""
    , tabs ++ "| Indicator | Value |"
    , tabs ++ "|-----------|-------|"
    ]
    ++
    map (showIndicatorValue level) (M.toList values)
    ++
    [""]
  where tabs = variableTabs level

showIndicatorValue :: Int -> (String, Double) -> String
showIndicatorValue level (key, value) = tabs ++ "| " ++ key ++ " | " ++ show value ++ " |"
    where tabs = variableTabs level

-- * AHP tree printing

showAhpTree :: AHPTree -> String
showAhpTree = showAhpSubTree 0

showAhpSubTree :: Int -> AHPTree -> String
showAhpSubTree level (AHPTree name prefMatrix consistency childrenPriority alternativesPriority children) = unlines $
    [ tabs ++ "* Tree : " ++ name
    , tabs ++ "\t- pairwise comparison matrix :"
    , tabs
    ]
    ++
    lines (showMatrix (level + 2) prefMatrix)
    ++
    [ tabs ++ "\t- consistency ratio = " ++ maybe "N/A" show consistency
    , tabs ++ "\t- children priority vector :"
    , tabs
    ]
    ++
    lines (maybe (variableTabs (level + 2) ++ "N/A") (showMatrix (level + 2)) childrenPriority)
    ++
    [ tabs ++ "\t- alternatives priority vector :"
    , tabs
    ]
    ++
    lines (maybe (variableTabs (level + 2) ++ "N/A") (showMatrix (level + 2)) alternativesPriority)
    ++
    lines (concatMap (showAhpSubTree (level + 1)) children)
        where tabs = variableTabs level

showAhpSubTree level (AHPLeaf name maximize alternativesPriority) = unlines $
    [ tabs ++ "* Leaf : " ++ name
    , tabs ++ "\t- " ++ (if maximize then "indicator is maximized" else "indicator is minimized")
    , tabs ++ "\t- alternatives priority vector :"
    , tabs
    ]
    ++
    lines (maybe (variableTabs (level + 2) ++ "N/A") (showMatrix (level + 1)) alternativesPriority)
        where tabs = variableTabs level

-- * Matrix printing

showMatrix :: Int -> Matrix Double -> String
showMatrix level = showMatrix' (level + 2)

showMatrix' :: Int -> Matrix Double -> String
showMatrix' level matrix = concatMap showMatrixLine lists
    where lists = toLists matrix
          showMatrixLine line = variableTabs level ++ "  | " ++
                                concatMap (\x -> printf "%.4f" x ++ " ") line ++
                                "|\n"

variableTabs :: Int -> String
variableTabs level = replicate level '\t'