module FPPrac.Trees.GeneralTree where

import EventLoop.CommonTypes
import EventLoop.Output
import FPPrac.Trees.LayoutTree


-- Courier 16px
textFont = "Courier"
textHeight = 16 :: Float -- px
charWidth  = 10 :: Float

marginBetweenTrees = 10 :: Float
marginBetweenNodeContent = 2 :: Float
marginBetweenNodeRows = 20 :: Float
marginBetweenNodeColumns = 20 :: Float

data GeneralTree = GeneralTreeBox [GeneralNodeContent] [(GeneralLine, GeneralTree)] deriving (Show)

data GeneralNodeContent = GeneralNodeText Color String
                        | GeneralNode Color Radius
                        deriving (Show)
                        
data GeneralLine = GeneralLine Color  
                    deriving (Show)

type Offset       = Float
type LeftOffset   = Offset
type TopOffset    = Offset
type RightOffset  = Offset
type BottomOffset = Offset
type Middle = Float
type Height = Float

class GeneralizeTree a where
    generalizeTree :: a -> GeneralTree
    
instance GeneralizeTree GeneralTree where
    generalizeTree a = a

generalNodeDimension :: GeneralTree -> Dimension
generalNodeDimension (GeneralTreeBox content _) = flattenDimensions contentDimensions
                                                where
                                                    contentDimensions = map generalNodeContentDimension content
                                                    
flattenDimensions :: [Dimension] -> Dimension
flattenDimensions [] = (0.0,0.0)
flattenDimensions [d] = d
flattenDimensions ((w,h):ds) = (max w wTotal, h + marginBetweenNodeContent + hTotal)
                            where
                                (wTotal, hTotal) = flattenDimensions ds
                                                    
generalNodeContentDimension :: GeneralNodeContent -> Dimension
generalNodeContentDimension (GeneralNodeText _ str) = textSize str
generalNodeContentDimension (GeneralNode _ rad    ) = (2*rad, 2*rad)
                       
layoutGeneralTree :: LeftOffset -> TopOffset -> GeneralTree -> (LayoutTree, RightOffset, BottomOffset)
layoutGeneralTree leftOffset topOffset box@(GeneralTreeBox content children) = (LBox (x, y) topConnect bottomConnect lcs lchildrenWithLines, rightOffset, bottomOffsetChildren)
                                                                        where
                                                                            x               = leftBorder
                                                                            y               = topOffset
                                                                            middle          = (rightOffset - leftOffset) / 2 + leftOffset
                                                                            rightOffset     = max rightOffsetChildren (leftOffset + width)
                                                                            leftBorder      = middle - (width / 2)
                                                                            topConnect      = (width / 2, 0)
                                                                            bottomConnect   = (width / 2, height)
                                                                            (width, height) = generalNodeDimension box
                                                                            lcs             = layoutGeneralNodeContentList (width / 2) 0 content
                                                                            (lchildrenWithLines, rightOffsetChildren, bottomOffsetChildren) = layoutGeneralTreeChildren leftOffset (topOffset + marginBetweenNodeRows + height) children

layoutGeneralTreeChildren :: LeftOffset -> TopOffset -> [(GeneralLine, GeneralTree)] -> ([(LayoutLine, LayoutTree)], RightOffset, BottomOffset)
layoutGeneralTreeChildren left top treesWithLines =(zip lLines lTrees, right, bottom)
                                    where
                                        lines        = map fst treesWithLines
                                        generalTrees = map snd treesWithLines
                                        lLines       = map layoutLine lines
                                        (lTrees, right, bottom) = layoutGeneralTrees left top generalTrees
                                        
layoutLine :: GeneralLine -> LayoutLine
layoutLine (GeneralLine color) = LayoutLine color 
                                                                            
layoutGeneralTrees :: LeftOffset -> TopOffset -> [GeneralTree] -> ([LayoutTree], RightOffset, BottomOffset)
layoutGeneralTrees left top [] = ([], left, top)
layoutGeneralTrees left top [box] = (\(a,b,c) -> ([a],b,c)) $ layoutGeneralTree left top box
layoutGeneralTrees left top (box:bs) = (lbox:lrest, rightRest, max bottom bottomRest)
                                            where
                                                (lbox, right , bottom) = layoutGeneralTree left top box
                                                (lrest, rightRest, bottomRest) = (layoutGeneralTrees (right + marginBetweenNodeColumns) top bs)
                                      
layoutGeneralNodeContentList :: Middle -> Height -> [GeneralNodeContent] -> [LayoutNodeContent]
layoutGeneralNodeContentList _ _ [] = []
layoutGeneralNodeContentList middle height [nc] = [layoutGeneralNodeContent (middle, height) nc]
layoutGeneralNodeContentList middle height (nc:ncs) = lnc:(layoutGeneralNodeContentList middle height' ncs)
                                                    where
                                                        height' = height + ncHeight + marginBetweenNodeContent
                                                        (_, ncHeight) = generalNodeContentDimension nc
                                                        lnc = layoutGeneralNodeContent (middle, height) nc
                                                                            
layoutGeneralNodeContent :: Pos -> GeneralNodeContent -> LayoutNodeContent
layoutGeneralNodeContent (middle, top) gnc@(GeneralNodeText color str) = LayoutNodeText color (x,y) str (textSize str)
                                                                    where
                                                                        x = middle
                                                                        y = top + h/2
                                                                        (w, h) = generalNodeContentDimension gnc
                                                                        
layoutGeneralNodeContent (middle, top) gnc@(GeneralNode color rad)     = LayoutNode color (x,y) rad
                                                                where
                                                                    x = middle
                                                                    y = top + h/2
                                                                    (w, h) = generalNodeContentDimension gnc

-- (width, height)                        
textSize :: [Char] -> (Float, Float)
textSize str = (textWidth, textHeight)
             where
                textWidth = charWidth * (fromIntegral (length str))


showTree :: (GeneralizeTree a) => a -> IO ()
showTree a = showTreeList [a]

showTreeList :: (GeneralizeTree a) => [a] -> IO ()
showTreeList list = outSingle (OutGraphical (Draw (showTreeList' 0 0 0 0 list) "trees")) 

showTreeList' :: (GeneralizeTree a) => LeftOffset -> TopOffset -> Float -> Int -> [a] -> GObject
showTreeList' _ _ _ _ [] = Container []
showTreeList' left top maxBottom i (x:xs) | right <= 1024 = Container (text:gtree:gtrees)
                                          | width > 1024  = Container (text:gtree:gtrees)
                                          | otherwise     = showTreeList' 0 maxBottom' maxBottom' i (x:xs)
                                        where
                                            maxBottom' = max maxBottom bottom
                                            (ltree, right, bottom) = layoutGeneralTree left top (generalizeTree x)
                                            gtree = printTree ltree
                                            Container gtrees = showTreeList' (right + marginBetweenTrees) top maxBottom' i' xs
                                            i' = i + 1
                                            text = treeIndex i (left, top)
                                            width = right - left

treeIndex :: Int -> Pos -> GObject
treeIndex i pos = GObject "treeIndex" (Text (255, 125, 125) 0 (255,75,75) pos 20 "Courier" (show i) False)  []




                
{- Calibri height 16px            
charWidth :: Char -> Number
charWidth c = case c of
                'a' -> 7.509259481
                'b' -> 7.509259481
                'c' -> 7.509259481
                'd' -> 7.509259481
                'e' -> 7.509259481
                'f' -> 5.65740763
                'g' -> 8.435185407
                'h' -> 7.509259481
                'i' -> 3.805555778
                'j' -> 5.65740763
                'k' -> 7.509259481
                'l' -> 3.342592815
                'm' -> 12.13888911
                'n' -> 7.509259481
                'o' -> 7.509259481
                'p' -> 7.509259481
                'q' -> 7.509259481
                'r' -> 5.65740763
                's' -> 6.583333556
                't' -> 6.583333556
                'u' -> 7.509259481
                'v' -> 8.435185407
                'w' -> 12.13888911
                'x' -> 7.509259481
                'y' -> 8.435185407
                'z' -> 6.583333556
                '0' -> 7.509259481
                '1' -> 7.509259481
                '2' -> 7.509259481
                '3' -> 7.509259481
                '4' -> 9.361111333
                '5' -> 7.509259481
                '6' -> 7.509259481
                '7' -> 8.435185407
                '8' -> 8.435185407
                '9' -> 7.509259481
                ' ' -> 5.65740763              
                _   -> 7.509259481
-}