module Data.Text.ParagraphLayout.PrettyShow
    ( PrettyShow
    , prettyShow
    , Pages (..)
    , ShapedRuns (..)
    )
where
import Data.List (intersperse)
import Data.Text.ParagraphLayout
import Data.Text.ParagraphLayout.Internal.Fragment (ShapedRun)
class PrettyShow a where
    prettyShow :: a -> String
newtype ShapedRuns = ShapedRuns { getShapedRuns :: [ShapedRun] }
    deriving (Eq)
instance PrettyShow ShapedRuns where
    prettyShow (ShapedRuns xs) =
        concat $ commaFirstList indent0 $ map (prettyShow . ShapedRun') xs
newtype ShapedRun' = ShapedRun' ShapedRun
instance PrettyShow ShapedRun' where
    prettyShow (ShapedRun' (x, y, glyphs)) = concat
        [ "("
        , show x
        , ", "
        , show y
        , ", "
        , newline
        , concat $ commaFirstList indent1 $ map prettyShowPair glyphs
        , ")"
        ]
type Page = (PageContinuity, ParagraphLayout)
newtype Pages = Pages { getPages :: [Page] }
    deriving (Eq)
instance PrettyShow Pages where
    prettyShow (Pages ps) =
        concat (commaFirstList indent0 $ map (prettyShow . Page') ps)
        ++ newline
newtype Page' = Page' Page
instance PrettyShow Page' where
    prettyShow (Page' (c, pl)) = concat
        [ "("
        , show c
        , ", "
        , prettyShow pl
        , ")"
        ]
instance PrettyShow ParagraphLayout where
    prettyShow (ParagraphLayout pr sls) = concat
        [ "ParagraphLayout"
        , newline
        , indent1
        , "{ paragraphRect = "
        , show pr
        , newline
        , indent1
        , ", spanLayouts = ["
        , newline
        , concat $ commaAloneList indent2 $ map prettyShow sls
        , newline
        , indent1
        , "]}"
        , newline
        ]
instance PrettyShow SpanLayout where
    prettyShow (SpanLayout frags) = concat
        [ "SpanLayout"
        , newline
        , concat $ commaFirstList indent2 $ map prettyShow frags
        ]
instance PrettyShow Fragment where
    prettyShow (Fragment r pen glyphs) = concat
        [ "Fragment"
        , newline
        , indent3
        , "{ fragmentRect = "
        , show r
        , newline
        , indent3
        , ", fragmentPen = "
        , prettyShowPair pen
        , newline
        , indent3
        , ", fragmentGlyphs ="
        , newline
        , concat $ commaFirstList indent4 $ map prettyShowPair glyphs
        , newline
        , indent3
        , "}"
        ]
prettyShowPair :: (Show a, Show b) => (a, b) -> String
prettyShowPair (a, b) = "(" ++ show a ++ ", " ++ show b ++ ")"
commaAloneList :: String -> [String] -> [String]
commaAloneList indent items =
    map (indent ++) $
    suffixInit newline $
    intersperse "," $
    items
commaFirstList :: String -> [String] -> [String]
commaFirstList indent [] = [indent ++ "[]"]
commaFirstList indent items =
    prefixHead (indent ++ "[ ") $
    prefixTail (indent ++ ", ") $
    suffixInit newline $
    suffixLast (newline ++ indent ++ "]") $
    items
suffixInit :: String -> [String] -> [String]
suffixInit suffix = mapInit (++ suffix)
mapInit :: (a -> a) -> [a] -> [a]
mapInit _ [] = []
mapInit _ [x] = [x]
mapInit f (x : y : ys) = f x : mapInit f (y : ys)
prefixTail :: String -> [String] -> [String]
prefixTail prefix = mapTail (prefix ++)
mapTail :: (a -> a) -> [a] -> [a]
mapTail _ [] = []
mapTail f (x : xs) = x : (map f xs)
prefixHead :: String -> [String] -> [String]
prefixHead prefix = mapHead (prefix ++)
mapHead :: (a -> a) -> [a] -> [a]
mapHead _ [] = []
mapHead f (x : xs) = f x : xs
suffixLast :: String -> [String] -> [String]
suffixLast suffix = mapLast (++ suffix)
mapLast :: (a -> a) -> [a] -> [a]
mapLast _ [] = []
mapLast f [x] = [f x]
mapLast f (x : y : ys) = x : mapLast f (y : ys)
indent0 :: String
indent0 = ""
indent1 :: String
indent1 = "    "
indent2 :: String
indent2 = indent1 ++ indent1
indent3 :: String
indent3 = indent1 ++ indent2
indent4 :: String
indent4 = indent1 ++ indent3
newline :: String
newline = "\n"