{-# LANGUAGE Haskell2010 #-}

module Simplex.Table (mkTable, mkAsciiTable) where

import Simplex.EscapeTeX
import Simplex.Util
import Simplex.Parser

import Data.List (intersperse)
import Data.List.Split
import Data.Maybe

mkAsciiTable :: String -> Table
mkAsciiTable def = (newTableOpt { tableDef = tDef }, rows)
    where
        rows = (SingleBorder, []) : (map fromJust $ filter isJust $ map f (lines def))
        numCols = maximum (map (\(_, r) -> length r) rows) + 1
        tDef = '|' : (intersperse '|' $ take numCols $ repeat 'c')
        f s = case line of
                ('+':_) -> Nothing
                _ -> Just (SingleBorder, tail' $ map g $ linesBy (== '|') line)
            where
                line = dropWhile (flip elem " \t") s
        g s = (Cell Nothing Nothing 1 1 True True Default, s)


mkTable :: Table -> String
mkTable (opt, rows@((t,r):rs))
  = let
        captionTop = maybe "" id (tableCaptionTop opt)
        captionBottom = maybe "" id (tableCaptionBottom opt)

        spec
            | tableDef opt == "" = take numCols $ repeat 'l'
            | otherwise = mkSpec $ tableDef opt

        mkSpec s
            | len < numCols = s ++ (take (numCols - len) $ repeat 'l')
            | otherwise = s
                where
                    len = length (filter (`elem` "crlpmbX") $ rem False s)
                    rem False ('{':xs) = rem True xs
                    rem False (x:xs)   = x : rem False xs
                    rem True  ('}':xs) = rem False xs
                    rem True  (x:xs)   = rem True xs
                    rem _ _ = ""

        numCols = maximum (map (length.snd) rows)

        mkRows ((NoBorder,[]):rs) = mkRows rs
        mkRows ((NoBorder,cs):rs) = mkCells cs : " \\\\\n" : mkRows rs

        mkRows ((SingleBorder,cs):rs) = mkCells cs : " \\\\ \\hline\n" : mkRows rs
        mkRows ((DoubleBorder,cs):rs) = mkCells cs : " \\\\ \\hline \\hline\n" : mkRows rs

        mkRows [] = []

        body
            | r == [] && t == SingleBorder = concat ("\\hline \n" : mkRows rs)
            | r == [] && t == DoubleBorder = concat ("\\hline \\hline \n" : mkRows rs)
            | otherwise = concat (mkRows rows)

        mkCells = concat . intersperse " & " . map mkCell

        mkCell (Cell color Nothing 1 rowSpan l r t, c)
          = rowCell color rowSpan t c
        mkCell (Cell color (Just a) colSpan rowSpan l r t, c)
          = "\\multicolumn{" ++ show colSpan ++ "}{" ++ colSpec l r a ++ "}{" ++ rowCell color rowSpan t c ++ "}"
        mkCell (Cell color _ colSpan rowSpan l r t, c)
          = "\\multicolumn{" ++ show colSpan ++ "}{" ++ colSpec l r 'c' ++ "}{" ++ rowCell color rowSpan t c ++ "}"

        colSpec True  False a = '|' : [a]
        colSpec False True  a = a : "|"
        colSpec True  True  a = '|' : a : "|"
        colSpec False False a = [a]

        rowCell color 1 t c       = colorCell color t c
        rowCell color rowSpan t c = "\\multirow{" ++ show rowSpan ++ "}{*}{" ++ colorCell color t c ++ "}"
        
        colorCell Nothing t c      = cellContent t c
        colorCell (Just color) t c = "\\cellcolor{" ++ color ++ "}" ++ cellContent t c

        cellContent Verb c = "\\verb#" ++ c ++ "#"
        cellContent Head c = "{\\bfseries " ++ escapeTeX "}" c
        cellContent Math c = '$' : safeTeX c ++ "$"
        cellContent _ c = escapeTeX "" c

    in  when' (captionTop /= "" || captionBottom /= "") "\\begin{table}[!h]\n"
        ++ "\\begin{center}\n"
        ++ when' (captionTop /= "") ("\\caption{" ++ escapeTeX "}\n" captionTop)
        ++ ifElse (tableX opt)
            ("\\begin{tabularx}{\\linewidth}{" ++ spec ++ "}\n")
            ("\\begin{tabular}{" ++ spec ++ "}\n")
        ++ body
        ++ ifElse (tableX opt) ("\n\\end{tabularx}\n") ("\n\\end{tabular}\n")
        ++ "\n\\end{center}\n"
        ++ when' (captionBottom /= "") ("\\caption{" ++ escapeTeX "}\n" captionBottom)            
        ++ when' (captionTop /= "" || captionBottom /= "") "\\end{table}\n"
        ++ "\n"



# LANGUAGE Haskell2010 #

module Simplex.Table (mkTable, mkAsciiTable) where

import Simplex.EscapeTeX
import Simplex.Util
import Simplex.Parser

import Data.List (intersperse)
import Data.List.Split
import Data.Maybe

mkAsciiTable :: String -> Table
mkAsciiTable def = (newTableOpt { tableDef = tDef }, rows)
    where
        rows = (SingleBorder, []) : (map fromJust $ filter isJust $ map f (lines def))
        numCols = maximum (map (\(_, r) -> length r) rows) + 1
        tDef = '|' : (intersperse '|' $ take numCols $ repeat 'c')
        f s = case line of
                ('+':_) -> Nothing
                _ -> Just (SingleBorder, tail' $ map g $ linesBy (== '|') line)
            where
                line = dropWhile (flip elem " \t") s
        g s = (Cell Nothing Nothing 1 1 True True Default, s)


mkTable :: Table -> String
mkTable (opt, rows@((t,r):rs))
  = let
        captionTop = maybe "" id (tableCaptionTop opt)
        captionBottom = maybe "" id (tableCaptionBottom opt)

        spec
            | tableDef opt == "" = take numCols $ repeat 'l'
            | otherwise = mkSpec $ tableDef opt

        mkSpec s
            | len < numCols = s ++ (take (numCols - len) $ repeat 'l')
            | otherwise = s
                where
                    len = length (filter (`elem` "crlpmbX") $ rem False s)
                    rem False ('{':xs) = rem True xs
                    rem False (x:xs)   = x : rem False xs
                    rem True  ('}':xs) = rem False xs
                    rem True  (x:xs)   = rem True xs
                    rem _ _ = ""

        numCols = maximum (map (length.snd) rows)

        mkRows ((NoBorder,[]):rs) = mkRows rs
        mkRows ((NoBorder,cs):rs) = mkCells cs : " \\\\\n" : mkRows rs

        mkRows ((SingleBorder,cs):rs) = mkCells cs : " \\\\ \\hline\n" : mkRows rs
        mkRows ((DoubleBorder,cs):rs) = mkCells cs : " \\\\ \\hline \\hline\n" : mkRows rs

        mkRows [] = []

        body
            | r == [] && t == SingleBorder = concat ("\\hline \n" : mkRows rs)
            | r == [] && t == DoubleBorder = concat ("\\hline \\hline \n" : mkRows rs)
            | otherwise = concat (mkRows rows)

        mkCells = concat . intersperse " & " . map mkCell

        mkCell (Cell color Nothing 1 rowSpan l r t, c)
          = rowCell color rowSpan t c
        mkCell (Cell color (Just a) colSpan rowSpan l r t, c)
          = "\\multicolumn{" ++ show colSpan ++ "}{" ++ colSpec l r a ++ "}{" ++ rowCell color rowSpan t c ++ "}"
        mkCell (Cell color _ colSpan rowSpan l r t, c)
          = "\\multicolumn{" ++ show colSpan ++ "}{" ++ colSpec l r 'c' ++ "}{" ++ rowCell color rowSpan t c ++ "}"

        colSpec True  False a = '|' : [a]
        colSpec False True  a = a : "|"
        colSpec True  True  a = '|' : a : "|"
        colSpec False False a = [a]

        rowCell color 1 t c       = colorCell color t c
        rowCell color rowSpan t c = "\\multirow{" ++ show rowSpan ++ "}{*}{" ++ colorCell color t c ++ "}"
        
        colorCell Nothing t c      = cellContent t c
        colorCell (Just color) t c = "\\cellcolor{" ++ color ++ "}" ++ cellContent t c

        cellContent Verb c = "\\verb#" ++ c ++ "#"
        cellContent Head c = "{\\bfseries " ++ escapeTeX "}" c
        cellContent Math c = '$' : safeTeX c ++ "$"
        cellContent _ c = escapeTeX "" c

    in  when' (captionTop /= "" || captionBottom /= "") "\\begin{table}[!h]\n"
        ++ "\\begin{center}\n"
        ++ when' (captionTop /= "") ("\\caption{" ++ escapeTeX "}\n" captionTop)
        ++ ifElse (tableX opt)
            ("\\begin{tabularx}{\\linewidth}{" ++ spec ++ "}\n")
            ("\\begin{tabular}{" ++ spec ++ "}\n")
        ++ body
        ++ ifElse (tableX opt) ("\n\\end{tabularx}\n") ("\n\\end{tabular}\n")
        ++ "\n\\end{center}\n"
        ++ when' (captionBottom /= "") ("\\caption{" ++ escapeTeX "}\n" captionBottom)            
        ++ when' (captionTop /= "" || captionBottom /= "") "\\end{table}\n"
        ++ "\n"


