module Text.Tabular.AsciiArt where

import Data.List (intersperse, transpose)
import Text.Tabular

-- | for simplicity, we assume that each cell is rendered
--   on a single line
render :: (rh -> String)
       -> (ch -> String)
       -> (a -> String)
       -> Table rh ch a
       -> String
render :: forall rh ch a.
(rh -> String)
-> (ch -> String) -> (a -> String) -> Table rh ch a -> String
render rh -> String
fr ch -> String
fc a -> String
f (Table Header rh
rh Header ch
ch [[a]]
cells) =
  [String] -> String
unlines forall a b. (a -> b) -> a -> b
$ [ Properties -> String
bar Properties
SingleLine   -- +--------------------------------------+
            , [Int] -> Header String -> String
renderColumns [Int]
sizes Header String
ch2
            , Properties -> String
bar Properties
DoubleLine   -- +======================================+
            ] forall a. [a] -> [a] -> [a]
++
            (Header String -> [String]
renderRs forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ([a], String) -> String
renderR forall a b. (a -> b) -> a -> b
$ forall h a. h -> [h] -> Header a -> Header (h, a)
zipHeader [] [[a]]
cells forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap rh -> String
fr Header rh
rh) forall a. [a] -> [a] -> [a]
++
            [ Properties -> String
bar Properties
SingleLine ] -- +--------------------------------------+
 where
  bar :: Properties -> String
bar = forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Int] -> Header String -> Properties -> [String]
renderHLine [Int]
sizes Header String
ch2
  -- ch2 and cell2 include the row and column labels
  ch2 :: Header String
ch2 = forall h. Properties -> [Header h] -> Header h
Group Properties
DoubleLine [forall h. h -> Header h
Header String
"", forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ch -> String
fc Header ch
ch]
  cells2 :: [[String]]
cells2 = forall h. Header h -> [h]
headerContents Header String
ch2
         forall a. a -> [a] -> [a]
: forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith (\String
h [a]
cs -> String
h forall a. a -> [a] -> [a]
: forall a b. (a -> b) -> [a] -> [b]
map a -> String
f [a]
cs) [String]
rhStrings [[a]]
cells
  --
  renderR :: ([a], String) -> String
renderR ([a]
cs,String
h) = [Int] -> Header String -> String
renderColumns [Int]
sizes forall a b. (a -> b) -> a -> b
$ forall h. Properties -> [Header h] -> Header h
Group Properties
DoubleLine
                    [ forall h. h -> Header h
Header String
h
                    , forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a b. (a, b) -> a
fst forall a b. (a -> b) -> a -> b
$ forall h a. h -> [h] -> Header a -> Header (h, a)
zipHeader String
"" (forall a b. (a -> b) -> [a] -> [b]
map a -> String
f [a]
cs) Header ch
ch]
  rhStrings :: [String]
rhStrings = forall a b. (a -> b) -> [a] -> [b]
map rh -> String
fr forall a b. (a -> b) -> a -> b
$ forall h. Header h -> [h]
headerContents Header rh
rh
  -- maximum width for each column
  sizes :: [Int]
sizes   = forall a b. (a -> b) -> [a] -> [b]
map (forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
maximum forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map forall (t :: * -> *) a. Foldable t => t a -> Int
length) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. [[a]] -> [[a]]
transpose forall a b. (a -> b) -> a -> b
$ [[String]]
cells2
  renderRs :: Header String -> [String]
renderRs (Header String
s)   = [String
s]
  renderRs (Group Properties
p [Header String]
hs) = forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. a -> [a] -> [a]
intersperse [String]
sep forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map Header String -> [String]
renderRs forall a b. (a -> b) -> a -> b
$ [Header String]
hs
    where sep :: [String]
sep = [Int] -> Header String -> Properties -> [String]
renderHLine [Int]
sizes Header String
ch2 Properties
p

-- | We stop rendering on the shortest list!
renderColumns :: [Int] -- ^ max width for each column
              -> Header String
              -> String
renderColumns :: [Int] -> Header String -> String
renderColumns [Int]
is Header String
h = String
"| " forall a. [a] -> [a] -> [a]
++ String
coreLine forall a. [a] -> [a] -> [a]
++ String
" |"
 where
  coreLine :: String
coreLine = forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap Either Properties (Int, String) -> String
helper forall a b. (a -> b) -> a -> b
$ forall h. Header h -> [Either Properties h]
flattenHeader forall a b. (a -> b) -> a -> b
$ forall h a. h -> [h] -> Header a -> Header (h, a)
zipHeader Int
0 [Int]
is Header String
h
  helper :: Either Properties (Int, String) -> String
helper = forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either Properties -> String
hsep (forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry Int -> String -> String
padLeft)
  hsep :: Properties -> String
  hsep :: Properties -> String
hsep Properties
NoLine     = String
" "
  hsep Properties
SingleLine = String
" | "
  hsep Properties
DoubleLine = String
" || "

renderHLine :: [Int] -- ^ width specifications
            -> Header String
            -> Properties
            -> [String]
renderHLine :: [Int] -> Header String -> Properties -> [String]
renderHLine [Int]
_ Header String
_ Properties
NoLine = []
renderHLine [Int]
w Header String
h Properties
SingleLine = [[Int] -> Char -> Header String -> String
renderHLine' [Int]
w Char
'-' Header String
h]
renderHLine [Int]
w Header String
h Properties
DoubleLine = [[Int] -> Char -> Header String -> String
renderHLine' [Int]
w Char
'=' Header String
h]

renderHLine' :: [Int] -> Char -> Header String -> String
renderHLine' :: [Int] -> Char -> Header String -> String
renderHLine' [Int]
is Char
sep Header String
h = [ Char
'+', Char
sep ] forall a. [a] -> [a] -> [a]
++ String
coreLine forall a. [a] -> [a] -> [a]
++ [Char
sep, Char
'+']
 where
  coreLine :: String
coreLine        = forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap forall {b}. Either Properties (Int, b) -> String
helper forall a b. (a -> b) -> a -> b
$ forall h. Header h -> [Either Properties h]
flattenHeader forall a b. (a -> b) -> a -> b
$ forall h a. h -> [h] -> Header a -> Header (h, a)
zipHeader Int
0 [Int]
is Header String
h
  helper :: Either Properties (Int, b) -> String
helper          = forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either Properties -> String
vsep forall {b}. (Int, b) -> String
dashes
  dashes :: (Int, b) -> String
dashes (Int
i,b
_)    = forall a. Int -> a -> [a]
replicate Int
i Char
sep
  vsep :: Properties -> String
vsep Properties
NoLine     = [Char
sep]
  vsep Properties
SingleLine = Char
sep forall a. a -> [a] -> [a]
: String
"+"  forall a. [a] -> [a] -> [a]
++ [Char
sep]
  vsep Properties
DoubleLine = Char
sep forall a. a -> [a] -> [a]
: String
"++" forall a. [a] -> [a] -> [a]
++ [Char
sep]

padLeft :: Int -> String -> String
padLeft :: Int -> String -> String
padLeft Int
l String
s = String
padding forall a. [a] -> [a] -> [a]
++ String
s
 where padding :: String
padding = forall a. Int -> a -> [a]
replicate (Int
l forall a. Num a => a -> a -> a
- forall (t :: * -> *) a. Foldable t => t a -> Int
length String
s) Char
' '