module Graphics.Curves.Compile where

import Prelude hiding (minimum, maximum, any, or, and)
import Control.Applicative
import Data.Foldable
import Data.Monoid

import Graphics.Curves.Math
import Graphics.Curves.BoundingBox
import Graphics.Curves.Image
import Graphics.Curves.Colour
import Graphics.Curves.Curve

import Debug.Trace

-- Compilation ------------------------------------------------------------

type Segments = BBTree (AnnotatedSegment LineStyle)

data FillStyle = FillStyle FillColour Scalar Basis LineStyle
data LineStyle = LineStyle Colour Scalar Scalar

instance Monoid LineStyle where
  mempty  = LineStyle transparent 0 0
  mappend (LineStyle c1 w1 b1) (LineStyle c2 w2 b2) =
    LineStyle (c1 `blend` c2) (max w1 w2) (max b1 b2)

data CompiledImage
      = Segments FillStyle Segments
      | CIUnion (Op (Maybe Colour)) BoundingBox CompiledImage CompiledImage
      | CIEmpty

instance HasBoundingBox CompiledImage where
  bounds (Segments fs b) = relaxBoundingBox (max fw lw) $ bounds b
    where
      fw = case fs of
             FillStyle (SolidFill c) _ _ _ | isTransparent c -> 0
             FillStyle _ w _ _ -> w / 2
      lw = case fs of
             FillStyle _ _ _ (LineStyle c w b) | not $ isTransparent c -> w + b
             _ -> 0
  bounds (CIUnion _ b _ _) = b
  bounds CIEmpty           = Empty

compileImage :: Image -> CompiledImage
compileImage = compileImage' 1

compileImage' :: Scalar -> Image -> CompiledImage
compileImage' res (ICurve c) = Segments fs ss
  where
    s  = curveFillStyle c
    fs = FillStyle (fillColour s) (fillBlur s) (textureBasis s) (foldMap annotation ss)
    ss = fmap (\(_, _, s) -> toLineStyle s) <$> curveToSegments res c
    toLineStyle s = LineStyle (lineColour s) (lineWidth s) (lineBlur s)
compileImage' res IEmpty = CIEmpty
compileImage' res (Combine blend a b) =
  CIUnion blend (bounds (ca, cb)) ca cb
  where
    ca = compileImage' res a
    cb = compileImage' res b