packages feed

EditTimeReport-1.0: Printers.hs

module Printers (
                 -- * Printers
                 printTree, printCSV, printHtml,
                 printPlainText, printXHtml,    

                 -- * Options
                 PrintOptions, POption(..),
                 PrinterF(..), emptyPO,
                 isSet, set, unSet, setPrinters,

                 -- * Time strings
                 showTime, 

                 -- * String converters
                 getMonth, getDow,
                ) where

import QueryAST 
import Stats

import Control.Applicative
import Data.Char
import qualified Data.Set as S
import qualified Text.CSV as C
import qualified Text.Html as H
import qualified Text.XHtml as X
import Text.Printf


type PrintOptions = S.Set POption
data POption      = PrinterF !PrinterF
                  | Ident !Int
                  deriving (Eq, Ord, Show)
data PrinterF = Csv 
              | Html 
              | Text 
              | XHtml 
              deriving (Eq, Ord, Show)

emptyPO :: PrintOptions
emptyPO = S.fromList []


-- Handling PrintOptions
--
isSet       :: POption -> PrintOptions -> Bool
set         :: POption -> PrintOptions -> PrintOptions
unSet       :: POption -> PrintOptions -> PrintOptions
getPrinters :: PrintOptions -> [StatsTree -> String]
setPrinters :: [String] -> E PrintOptions

isSet   = S.member 
set     = S.insert
unSet   = S.delete

getPrinters = map (printer . fromPrinters) . filter isPrinter . S.elems
  where printer Csv               = printCSV 
        printer Html              = printHtml 
        printer Text              = printPlainText 
        printer XHtml             = printXHtml 
        fromPrinters (PrinterF p) = p
        isPrinter (PrinterF _)    = True
        isPrinter _               = False

parsePrinter "CSV"   = Ok Csv
parsePrinter "HTML"  = Ok Html
parsePrinter "TEXT"  = Ok Text
parsePrinter "XHTML" = Ok XHtml
parsePrinter s = Failed $ "No such format `" ++ s ++ "'"

setPrinters [] = Ok (S.fromList [PrinterF Text])
setPrinters p = S.fromList <$> f p
  where f = mapM (fmap PrinterF . parsePrinter . map toUpper) 



-- | Selects the printers described in the PrintOptions.
--
printTree :: PrintOptions -> [StatsTree] -> String
printTree po st = if null p then "No printers selected." 
                            else p >>= (\p' -> concatMap (p'$) (reverse st))
  where p = getPrinters po



-- String Conversions
--
getMonth :: Int -> String
getDow   :: Int -> String
showTime :: Time -> String
months   :: [String]
days     :: [String]

getMonth n = months !! (min 12 (max 1 n) - 1)
months     = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", 
              "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]

getDow n   = days !! min 6 (max 0 n)
days       = ["Sunday"  , "Monday", "Tuesday" , "Wednesday",
              "Thursday", "Friday", "Saturday"]

showTime (h, m, s) = concat [f h, ":", f m, ":", f s]
  where f = printf "%02d"



-- | StatsTree to Plain Text
--
printPlainText :: StatsTree -> String
printPlainText (Root [] _ _ _)   = "No matches"
printPlainText (Root ns _ t ti)  = concatMap (tts' 1) ns ++ "\n\n   Total time: " 
                                ++ showTime ti ++ "\n" 
  where tts' lvl (Leaf time)     = printf "%10s" (showTime time)
        tts' lvl (Node _ _ s tr) = '\n' : replicate (lvl * 4) ' ' 
                                ++ printf "%-70s" s 
                                ++ concatMap (tts' (lvl + 1)) tr


-- | StatsTree to Html table (no HTML header)
--
printHtml :: StatsTree -> String
printHtml = H.prettyHtml . foldTree (root, node, leaf)
  where root ns h t ti = H.h2 (H.toHtml t) H.+++ H.table (headers h 
                         H.+++ makeTable ns H.+++ total) H.+++ H.hr
          where total  = H.tr(H.td (H.toHtml "TOTAL") H.! [H.colspan (length h - 1)] 
                         H.+++ H.td (H.toHtml . showTime $ ti))
        headers        = H.tr . H.concatHtml . map (H.th . H.toHtml) 
        makeTable      = H.concatHtml . concatMap (map H.tr) 
        node cspan t   = concatMap . map  . (H.+++) . H.td . H.toHtml
        leaf           = pure . H.td . H.toHtml . showTime

-- | StatsTree to XHtml table (includes HTML header)
--
printXHtml :: StatsTree -> String
printXHtml = X.prettyHtml . foldTree (root, node, leaf)
  where root ns h t ti = X.h2 (X.toHtml t) X.+++ X.table (headers h 
                         X.+++ makeTable ns X.+++ total) X.+++ X.hr
          where total  = X.tr(X.td (X.toHtml "TOTAL") X.! [X.colspan (length h - 1)] 
                         X.+++ X.td (X.toHtml . showTime $ ti))
        headers        = X.tr . X.concatHtml . map (X.th . X.toHtml) 
        makeTable      = X.concatHtml . concatMap (map X.tr) 
        node cspan t   = concatMap . map  . (X.+++) . X.td . X.toHtml
        leaf           = pure . X.td . X.toHtml . showTime


-- | StatsTree to CSV String.
--
printCSV :: StatsTree -> String
printCSV = C.printCSV . foldTree (root, node, leaf)
  where root ns h _ _ = h : concat ns
        node _ _      = concatMap . map . (:)
        leaf          = pure . pure . showTime