{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TemplateHaskell #-}
module Graphics.SvgTree.Types.Internal
  ( 
    Coord,
    Origin (..),
    Point,
    RPoint,
    PathCommand (..),
    Transformation (..),
    ElementRef (..),
    CoordinateUnits (..),
    
    serializeNumber,
    serializeTransformation,
    serializeTransformations,
    
    Cap (..),
    LineJoin (..),
    Tree (..),
    TreeBranch (..),
    Number (..),
    Spread (..),
    Texture (..),
    Element (..),
    FillRule (..),
    FontStyle (..),
    Dpi,
    WithDefaultSvg (..),
    
    Document (..),
    documentViewBox,
    documentWidth,
    documentHeight,
    documentElements,
    documentDescription,
    documentLocation,
    documentAspectRatio,
    documentSize,
    
    DrawAttributes (..),
    HasDrawAttributes (..),
    
    FilterElement (..),
    FilterAttributes (..),
    HasFilterAttributes (..),
    FilterSource (..),
    ColorMatrixType (..),
    colorMatrixDrawAttributes,
    colorMatrixFilterAttr,
    colorMatrixIn,
    colorMatrixType,
    colorMatrixValues,
    ColorMatrix (..),
    compositeDrawAttributes,
    compositeFilterAttr,
    compositeIn,
    compositeIn2,
    compositeOperator,
    compositeK1,
    compositeK2,
    compositeK3,
    compositeK4,
    Composite (..),
    CompositeOperator (..),
    EdgeMode (..),
    gaussianBlurDrawAttributes,
    gaussianBlurFilterAttr,
    gaussianBlurIn,
    gaussianBlurStdDeviationX,
    gaussianBlurStdDeviationY,
    gaussianBlurEdgeMode,
    GaussianBlur (..),
    turbulenceDrawAttributes,
    turbulenceFilterAttr,
    turbulenceBaseFrequency,
    turbulenceNumOctaves,
    turbulenceSeed,
    turbulenceStitchTiles,
    turbulenceType,
    Turbulence (..),
    TurbulenceType (..),
    StitchTiles (..),
    DisplacementMap (..),
    displacementMapDrawAttributes,
    displacementMapFilterAttr,
    displacementMapIn,
    displacementMapIn2,
    displacementMapScale,
    displacementMapXChannelSelector,
    displacementMapYChannelSelector,
    ChannelSelector (..),
    
    
    Rectangle (..),
    rectangleDrawAttributes,
    rectUpperLeftCorner,
    rectWidth,
    rectHeight,
    rectCornerRadius,
    
    Line (..),
    lineDrawAttributes,
    linePoint1,
    linePoint2,
    
    Polygon (..),
    polygonDrawAttributes,
    polygonPoints,
    
    PolyLine (..),
    polyLineDrawAttributes,
    polyLinePoints,
    
    Path (..),
    pathDrawAttributes,
    pathDefinition,
    
    Circle (..),
    circleDrawAttributes,
    circleCenter,
    circleRadius,
    
    Ellipse (..),
    ellipseDrawAttributes,
    ellipseCenter,
    ellipseXRadius,
    ellipseYRadius,
    
    GradientPathCommand (..),
    MeshGradientType (..),
    MeshGradient (..),
    meshGradientDrawAttributes,
    meshGradientX,
    meshGradientY,
    meshGradientType,
    meshGradientUnits,
    meshGradientTransform,
    meshGradientRows,
    MeshGradientRow (..),
    meshGradientRowPatches,
    MeshGradientPatch (..),
    meshGradientPatchStops,
    
    Image (..),
    imageDrawAttributes,
    imageCornerUpperLeft,
    imageWidth,
    imageHeight,
    imageHref,
    imageAspectRatio,
    
    Use (..),
    useDrawAttributes,
    useBase,
    useName,
    useWidth,
    useHeight,
    
    
    Group (..),
    groupDrawAttributes,
    groupChildren,
    groupViewBox,
    groupAspectRatio,
    
    Filter (..),
    filterDrawAttributes,
    filterSelfAttributes,
    filterChildren,
    
    
    Text (..),
    textAdjust,
    textRoot,
    TextAnchor (..),
    textAt,
    
    TextPath (..),
    textPathStartOffset,
    textPathName,
    textPathMethod,
    textPathSpacing,
    TextPathSpacing (..),
    TextPathMethod (..),
    
    TextSpanContent (..),
    TextSpan (..),
    spanInfo,
    spanDrawAttributes,
    spanContent,
    TextInfo (..),
    textInfoX,
    textInfoY,
    textInfoDX,
    textInfoDY,
    textInfoRotate,
    textInfoLength,
    TextAdjust (..),
    
    Marker (..),
    Overflow (..),
    MarkerOrientation (..),
    MarkerUnit (..),
    markerDrawAttributes,
    markerRefPoint,
    markerWidth,
    markerHeight,
    markerOrient,
    markerUnits,
    markerViewBox,
    markerOverflow,
    markerAspectRatio,
    markerElements,
    
    GradientStop (..),
    gradientOffset,
    gradientColor,
    gradientPath,
    gradientOpacity,
    
    LinearGradient (..),
    linearGradientDrawAttributes,
    linearGradientUnits,
    linearGradientStart,
    linearGradientStop,
    linearGradientSpread,
    linearGradientTransform,
    linearGradientStops,
    
    RadialGradient (..),
    radialGradientDrawAttributes,
    radialGradientUnits,
    radialGradientCenter,
    radialGradientRadius,
    radialGradientFocusX,
    radialGradientFocusY,
    radialGradientSpread,
    radialGradientTransform,
    radialGradientStops,
    
    Pattern (..),
    patternDrawAttributes,
    patternViewBox,
    patternWidth,
    patternHeight,
    patternPos,
    patternHref,
    patternElements,
    patternUnit,
    patternAspectRatio,
    patternTransform,
    
    Mask (..),
    maskDrawAttributes,
    maskContentUnits,
    maskUnits,
    maskPosition,
    maskWidth,
    maskHeight,
    maskContent,
    
    ClipPath (..),
    clipPathDrawAttributes,
    clipPathUnits,
    clipPathContent,
    
    PreserveAspectRatio (..),
    Alignment (..),
    MeetSlice (..),
    aspectRatioDefer,
    aspectRatioAlign,
    aspectRatioMeetSlice,
    
    nameOfTree,
    toUserUnit,
    mapNumber,
  )
where
import Codec.Picture (PixelRGBA8 (..))
import Control.Lens.TH (makeClassy, makeLenses)
import Data.Function (on)
import Data.Monoid (Last (..))
import qualified Data.Text as T
import GHC.Generics (Generic)
import Graphics.SvgTree.CssTypes
  ( Dpi,
    Number (..),
    mapNumber,
    serializeNumber,
    toUserUnit,
  )
import Graphics.SvgTree.Misc (ppD)
import Graphics.SvgTree.Types.Basic
import Text.Printf (printf)
data PathCommand
  = 
    MoveTo !Origin ![RPoint]
  | 
    LineTo !Origin ![RPoint]
  | 
    HorizontalTo !Origin ![Coord]
  | 
    VerticalTo !Origin ![Coord]
  | 
    CurveTo !Origin ![(RPoint, RPoint, RPoint)]
  | 
    SmoothCurveTo !Origin ![(RPoint, RPoint)]
  | 
    QuadraticBezier !Origin ![(RPoint, RPoint)]
  | 
    SmoothQuadraticBezierCurveTo !Origin ![RPoint]
  | 
    EllipticalArc !Origin ![(Coord, Coord, Coord, Bool, Bool, RPoint)]
  | 
    EndPath
  deriving (Eq, Show, Generic)
data GradientPathCommand
  = 
    GLine !Origin !(Maybe RPoint)
  | 
    GCurve !Origin !RPoint !RPoint !(Maybe RPoint)
  | 
    GClose
  deriving (Eq, Show, Generic)
data PreserveAspectRatio = PreserveAspectRatio
  { _aspectRatioDefer :: !Bool,
    _aspectRatioAlign :: !Alignment,
    _aspectRatioMeetSlice :: !(Maybe MeetSlice)
  }
  deriving (Eq, Show, Generic)
instance WithDefaultSvg PreserveAspectRatio where
  defaultSvg =
    PreserveAspectRatio
      { _aspectRatioDefer = False,
        _aspectRatioAlign = AlignxMidYMid,
        _aspectRatioMeetSlice = Nothing
      }
data Transformation
  = 
    TransformMatrix
      !Coord
      !Coord
      !Coord
      !Coord
      !Coord
      !Coord
  | 
    Translate !Double !Double
  | 
    Scale !Double !(Maybe Double)
  | 
    
    Rotate !Double !(Maybe (Double, Double))
  | 
    SkewX !Double
  | 
    SkewY !Double
  | 
    TransformUnknown
  deriving (Eq, Show, Generic)
serializeTransformation :: Transformation -> String
serializeTransformation t = case t of
  TransformUnknown -> ""
  TransformMatrix a b c d e f ->
    printf
      "matrix(%s, %s, %s, %s, %s, %s)"
      (ppD a)
      (ppD b)
      (ppD c)
      (ppD d)
      (ppD e)
      (ppD f)
  Translate x y -> printf "translate(%s, %s)" (ppD x) (ppD y)
  Scale x Nothing -> printf "scale(%s)" (ppD x)
  Scale x (Just y) -> printf "scale(%s, %s)" (ppD x) (ppD y)
  Rotate angle Nothing -> printf "rotate(%s)" (ppD angle)
  Rotate angle (Just (x, y)) ->
    printf
      "rotate(%s, %s, %s)"
      (ppD angle)
      (ppD x)
      (ppD y)
  SkewX x -> printf "skewX(%s)" (ppD x)
  SkewY y -> printf "skewY(%s)" (ppD y)
serializeTransformations :: [Transformation] -> String
serializeTransformations =
  unwords . fmap serializeTransformation
class WithDefaultSvg a where
  
  defaultSvg :: a
data FontStyle
  = FontStyleNormal
  | FontStyleItalic
  | FontStyleOblique
  deriving (Eq, Show, Generic)
data TextAnchor
  = 
    
    
    
    
    
    
    TextAnchorStart
  | 
    
    
    
    
    
    TextAnchorMiddle
  | 
    
    
    
    
    TextAnchorEnd
  deriving (Eq, Show, Generic)
data ElementRef
  = 
    RefNone
  | 
    Ref String
  deriving (Eq, Show, Generic)
data FilterSource
  = SourceGraphic
  | SourceAlpha
  | BackgroundImage
  | BackgroundAlpha
  | FillPaint
  | StrokePaint
  | SourceRef String
  deriving (Eq, Show, Generic)
data FilterAttributes = FilterAttributes
  { _filterHeight :: !(Last Number),
    _filterResult :: !(Maybe String),
    _filterWidth :: !(Last Number),
    _filterX :: !(Last Number),
    _filterY :: !(Last Number)
  }
  deriving (Eq, Show, Generic)
instance WithDefaultSvg FilterAttributes where
  defaultSvg =
    FilterAttributes
      { _filterHeight = Last Nothing,
        _filterResult = Nothing,
        _filterWidth = Last Nothing,
        _filterX = Last Nothing,
        _filterY = Last Nothing
      }
data DrawAttributes = DrawAttributes
  { 
    
    _strokeWidth :: !(Last Number),
    
    _strokeColor :: !(Last Texture),
    
    
    _strokeOpacity :: !(Maybe Float),
    
    
    _strokeLineCap :: !(Last Cap),
    
    
    _strokeLineJoin :: !(Last LineJoin),
    
    
    _strokeMiterLimit :: !(Last Double),
    
    
    _fillColor :: !(Last Texture),
    
    
    _fillOpacity :: !(Maybe Float),
    
    _groupOpacity :: !(Maybe Float),
    
    _transform :: !(Maybe [Transformation]),
    
    _fillRule :: !(Last FillRule),
    
    _maskRef :: !(Last ElementRef),
    
    _clipPathRef :: !(Last ElementRef),
    
    _clipRule :: !(Last FillRule),
    
    
    _attrClass :: ![T.Text],
    
    
    _attrId :: !(Maybe String),
    
    
    _strokeOffset :: !(Last Number),
    
    
    _strokeDashArray :: !(Last [Number]),
    
    
    _fontSize :: !(Last Number),
    
    
    _fontFamily :: !(Last [String]),
    
    _fontStyle :: !(Last FontStyle),
    
    
    _textAnchor :: !(Last TextAnchor),
    
    
    _markerStart :: !(Last ElementRef),
    
    
    
    _markerMid :: !(Last ElementRef),
    
    
    _markerEnd :: !(Last ElementRef),
    _filterRef :: !(Last ElementRef)
  }
  deriving (Eq, Show, Generic)
makeClassy ''DrawAttributes
data PolyLine = PolyLine
  { _polyLineDrawAttributes :: DrawAttributes,
    
    
    _polyLinePoints :: [RPoint]
  }
  deriving (Eq, Show, Generic)
instance WithDefaultSvg PolyLine where
  defaultSvg = PolyLine mempty mempty
data Polygon = Polygon
  { _polygonDrawAttributes :: DrawAttributes,
    
    
    _polygonPoints :: [RPoint]
  }
  deriving (Eq, Show, Generic)
instance WithDefaultSvg Polygon where
  defaultSvg = Polygon mempty mempty
data Line = Line
  { _lineDrawAttributes :: DrawAttributes,
    
    
    _linePoint1 :: !Point,
    
    
    _linePoint2 :: !Point
  }
  deriving (Eq, Show, Generic)
instance WithDefaultSvg Line where
  defaultSvg =
    Line
      { _lineDrawAttributes = mempty,
        _linePoint1 = zeroPoint,
        _linePoint2 = zeroPoint
      }
    where
      zeroPoint = (Num 0, Num 0)
data Rectangle = Rectangle
  { _rectangleDrawAttributes :: DrawAttributes,
    
    
    _rectUpperLeftCorner :: !Point,
    
    
    _rectWidth :: !(Maybe Number),
    
    
    _rectHeight :: !(Maybe Number),
    
    
    
    _rectCornerRadius :: !(Maybe Number, Maybe Number)
  }
  deriving (Eq, Show, Generic)
instance WithDefaultSvg Rectangle where
  defaultSvg =
    Rectangle
      { _rectangleDrawAttributes = mempty,
        _rectUpperLeftCorner = (Num 0, Num 0),
        _rectWidth = Nothing,
        _rectHeight = Nothing,
        _rectCornerRadius = (Nothing, Nothing)
      }
data Path = Path
  { _pathDrawAttributes :: DrawAttributes,
    
    
    _pathDefinition :: [PathCommand]
  }
  deriving (Eq, Show, Generic)
instance WithDefaultSvg Path where
  defaultSvg = Path mempty mempty
data Group = Group
  { _groupDrawAttributes :: DrawAttributes,
    
    
    _groupChildren :: ![Tree],
    
    _groupViewBox :: !(Maybe (Double, Double, Double, Double)),
    
    _groupAspectRatio :: !PreserveAspectRatio
  }
  deriving (Eq, Show, Generic)
instance WithDefaultSvg Group where
  defaultSvg =
    Group
      { _groupDrawAttributes = mempty,
        _groupChildren = [],
        _groupViewBox = Nothing,
        _groupAspectRatio = defaultSvg
      }
data Filter = Filter
  { _filterDrawAttributes :: DrawAttributes,
    _filterSelfAttributes :: !FilterAttributes,
    _filterChildren :: ![FilterElement]
  }
  deriving (Eq, Show, Generic)
instance WithDefaultSvg Filter where
  defaultSvg =
    Filter
      { _filterDrawAttributes = mempty,
        _filterSelfAttributes = defaultSvg,
        _filterChildren = []
      }
data Circle = Circle
  { _circleDrawAttributes :: DrawAttributes,
    
    
    _circleCenter :: !Point,
    
    
    _circleRadius :: !Number
  }
  deriving (Eq, Show, Generic)
instance WithDefaultSvg Circle where
  defaultSvg =
    Circle
      { _circleDrawAttributes = mempty,
        _circleCenter = (Num 0, Num 0),
        _circleRadius = Num 0
      }
data Ellipse = Ellipse
  { _ellipseDrawAttributes :: DrawAttributes,
    
    
    _ellipseCenter :: !Point,
    
    
    _ellipseXRadius :: !Number,
    
    
    _ellipseYRadius :: !Number
  }
  deriving (Eq, Show, Generic)
instance WithDefaultSvg Ellipse where
  defaultSvg =
    Ellipse
      { _ellipseDrawAttributes = mempty,
        _ellipseCenter = (Num 0, Num 0),
        _ellipseXRadius = Num 0,
        _ellipseYRadius = Num 0
      }
data GradientStop = GradientStop
  { 
    
    _gradientOffset :: !Float,
    
    
    _gradientColor :: !PixelRGBA8,
    
    _gradientPath :: !(Maybe GradientPathCommand),
    
    _gradientOpacity :: !(Maybe Float)
  }
  deriving (Eq, Show, Generic)
instance WithDefaultSvg GradientStop where
  defaultSvg =
    GradientStop
      { _gradientOffset = 0.0,
        _gradientColor = PixelRGBA8 0 0 0 255,
        _gradientPath = Nothing,
        _gradientOpacity = Nothing
      }
data MeshGradientPatch = MeshGradientPatch
  { 
    _meshGradientPatchStops :: ![GradientStop]
  }
  deriving (Eq, Show, Generic)
instance WithDefaultSvg MeshGradientPatch where
  defaultSvg = MeshGradientPatch []
data MeshGradientRow = MeshGradientRow
  { 
    _meshGradientRowPatches :: ![MeshGradientPatch]
  }
  deriving (Eq, Show, Generic)
instance WithDefaultSvg MeshGradientRow where
  defaultSvg = MeshGradientRow []
data MeshGradient = MeshGradient
  { _meshGradientDrawAttributes :: DrawAttributes,
    
    _meshGradientX :: !Number,
    
    _meshGradientY :: !Number,
    
    _meshGradientType :: !MeshGradientType,
    
    _meshGradientUnits :: !CoordinateUnits,
    
    _meshGradientTransform :: ![Transformation],
    
    _meshGradientRows :: ![MeshGradientRow]
  }
  deriving (Eq, Show, Generic)
instance WithDefaultSvg MeshGradient where
  defaultSvg =
    MeshGradient
      { _meshGradientDrawAttributes = mempty,
        _meshGradientX = Percent 0,
        _meshGradientY = Percent 0,
        _meshGradientType = GradientBilinear,
        _meshGradientUnits = CoordBoundingBox,
        _meshGradientTransform = mempty,
        _meshGradientRows = mempty
      }
data Image = Image
  { _imageDrawAttributes :: DrawAttributes,
    
    
    _imageCornerUpperLeft :: !Point,
    
    _imageWidth :: !Number,
    
    _imageHeight :: !Number,
    
    _imageHref :: !String,
    
    _imageAspectRatio :: !PreserveAspectRatio
  }
  deriving (Eq, Show, Generic)
instance WithDefaultSvg Image where
  defaultSvg =
    Image
      { _imageDrawAttributes = mempty,
        _imageCornerUpperLeft = (Num 0, Num 0),
        _imageWidth = Num 0,
        _imageHeight = Num 0,
        _imageHref = "",
        _imageAspectRatio = defaultSvg
      }
data Use = Use
  { _useDrawAttributes :: DrawAttributes,
    
    
    _useBase :: Point,
    
    
    _useName :: String,
    
    
    
    _useWidth :: Maybe Number,
    
    
    
    _useHeight :: Maybe Number
  }
  deriving (Eq, Show, Generic)
instance WithDefaultSvg Use where
  defaultSvg =
    Use
      { _useDrawAttributes = mempty,
        _useBase = (Num 0, Num 0),
        _useName = "",
        _useWidth = Nothing,
        _useHeight = Nothing
      }
data TextInfo = TextInfo
  { 
    _textInfoX :: ![Number],
    
    _textInfoY :: ![Number],
    
    _textInfoDX :: ![Number],
    
    _textInfoDY :: ![Number],
    
    _textInfoRotate :: ![Double],
    
    _textInfoLength :: !(Maybe Number)
  }
  deriving (Eq, Show, Generic)
instance Semigroup TextInfo where
  (<>)
    (TextInfo x1 y1 dx1 dy1 r1 l1)
    (TextInfo x2 y2 dx2 dy2 r2 l2) =
      TextInfo
        (x1 <> x2)
        (y1 <> y2)
        (dx1 <> dx2)
        (dy1 <> dy2)
        (r1 <> r2)
        (getLast $ Last l1 <> Last l2)
instance Monoid TextInfo where
  mempty = TextInfo [] [] [] [] [] Nothing
  mappend = (<>)
instance WithDefaultSvg TextInfo where
  defaultSvg = mempty
data TextSpanContent
  = 
    SpanText !T.Text
  | 
    SpanTextRef !String
  | 
    SpanSub !TextSpan
  deriving (Eq, Show, Generic)
data TextSpan = TextSpan
  { 
    _spanInfo :: !TextInfo,
    
    _spanDrawAttributes :: !DrawAttributes,
    
    _spanContent :: ![TextSpanContent]
  }
  deriving (Eq, Show, Generic)
instance WithDefaultSvg TextSpan where
  defaultSvg =
    TextSpan
      { _spanInfo = defaultSvg,
        _spanDrawAttributes = mempty,
        _spanContent = mempty
      }
data TextPathMethod
  = 
    TextPathAlign
  | 
    TextPathStretch
  deriving (Eq, Show, Generic)
data TextPathSpacing
  = 
    TextPathSpacingExact
  | 
    TextPathSpacingAuto
  deriving (Eq, Show, Generic)
data TextPath = TextPath
  { 
    
    _textPathStartOffset :: !Number,
    
    _textPathName :: !String,
    
    _textPathMethod :: !TextPathMethod,
    
    _textPathSpacing :: !TextPathSpacing
  }
  deriving (Eq, Show, Generic)
instance WithDefaultSvg TextPath where
  defaultSvg =
    TextPath
      { _textPathStartOffset = Num 0,
        _textPathName = mempty,
        _textPathMethod = TextPathAlign,
        _textPathSpacing = TextPathSpacingExact
      }
data TextAdjust
  = 
    TextAdjustSpacing
  | 
    TextAdjustSpacingAndGlyphs
  deriving (Eq, Show, Generic)
data Text = Text
  { 
    _textAdjust :: !TextAdjust,
    
    _textRoot :: !TextSpan
  }
  deriving (Eq, Show, Generic)
textAt :: Point -> T.Text -> Text
textAt (x, y) txt = Text TextAdjustSpacing tspan
  where
    tspan =
      defaultSvg
        { _spanContent = [SpanText txt],
          _spanInfo =
            defaultSvg
              { _textInfoX = [x],
                _textInfoY = [y]
              }
        }
instance WithDefaultSvg Text where
  defaultSvg =
    Text
      { _textRoot = defaultSvg,
        _textAdjust = TextAdjustSpacing
      }
data Tree = CachedTree
  { _treeBranch :: TreeBranch,
    _treeHash :: Int
  }
  deriving (Eq, Show, Generic)
data TreeBranch
  = NoNode
  | UseNode
      { useInformation :: !Use,
        useSubTree :: !(Maybe Tree)
      }
  | GroupNode !Group
  | SymbolNode !Group
  | DefinitionNode !Group
  | FilterNode !Filter
  | PathNode !Path
  | CircleNode !Circle
  | PolyLineNode !PolyLine
  | PolygonNode !Polygon
  | EllipseNode !Ellipse
  | LineNode !Line
  | RectangleNode !Rectangle
  | TextNode !(Maybe TextPath) !Text
  | ImageNode !Image
  | LinearGradientNode !LinearGradient
  | RadialGradientNode !RadialGradient
  | MeshGradientNode !MeshGradient
  | PatternNode !Pattern
  | MarkerNode !Marker
  | MaskNode !Mask
  | ClipPathNode !ClipPath
  | SvgNode !Document
  deriving (Eq, Show, Generic)
instance WithDefaultSvg TreeBranch where
  defaultSvg = NoNode
data FilterElement
  = FEBlend
  | FEColorMatrix ColorMatrix
  | FEComponentTransfer 
  | FEComposite Composite
  | FEConvolveMatrix
  | FEDiffuseLighting
  | FEDisplacementMap DisplacementMap
  | FEDropShadow
  | FEFlood
  | FEFuncA 
  | FEFuncB
  | FEFuncG
  | FEFuncR
  | FEGaussianBlur GaussianBlur
  | FEImage
  | FEMerge
  | FEMergeNode
  | FEMorphology
  | FEOffset
  | FESpecularLighting
  | FETile
  | FETurbulence Turbulence
  | FENone
  deriving (Eq, Show, Generic)
instance WithDefaultSvg FilterElement where
  defaultSvg = FENone
data TransferFunctionType
  = TFIdentity
  | TFTable
  | TFDiscrete
  | TFLinear
  | TFGamma
  deriving (Eq, Show, Generic)
data TransferFunction = TransferFunction
  { _transferFunctionDrawAttributes :: !DrawAttributes,
    _transferFunctionFilterAttr :: !FilterAttributes,
    _transferFunctionType :: TransferFunctionType,
    _transferFunctionTableValues :: [Double],
    _transferFunctionSlope :: Double,
    _transferFunctionIntercept :: Double,
    _transferFunctionAmplitude :: Double,
    _transferFunctionExponent :: Double,
    _transferFunctionOffset :: Double
  }
  deriving (Eq, Show, Generic)
data ChannelSelector
  = ChannelR
  | ChannelG
  | ChannelB
  | ChannelA
  deriving (Eq, Show, Generic)
data DisplacementMap = DisplacementMap
  { _displacementMapDrawAttributes :: !DrawAttributes,
    _displacementMapFilterAttr :: !FilterAttributes,
    _displacementMapIn :: !(Last FilterSource),
    _displacementMapIn2 :: !(Last FilterSource),
    _displacementMapScale :: !(Last Double),
    _displacementMapXChannelSelector :: ChannelSelector,
    _displacementMapYChannelSelector :: ChannelSelector
  }
  deriving (Eq, Show, Generic)
instance WithDefaultSvg DisplacementMap where
  defaultSvg =
    DisplacementMap
      { _displacementMapDrawAttributes = defaultSvg,
        _displacementMapFilterAttr = defaultSvg,
        _displacementMapIn = Last Nothing,
        _displacementMapIn2 = Last Nothing,
        _displacementMapScale = Last Nothing,
        _displacementMapXChannelSelector = ChannelA,
        _displacementMapYChannelSelector = ChannelA
      }
data ColorMatrixType
  = Matrix
  | Saturate
  | HueRotate
  | LuminanceToAlpha
  deriving (Eq, Show, Generic)
data ColorMatrix = ColorMatrix
  { _colorMatrixDrawAttributes :: !DrawAttributes,
    _colorMatrixFilterAttr :: !FilterAttributes,
    _colorMatrixIn :: !(Last FilterSource),
    _colorMatrixType :: !ColorMatrixType,
    _colorMatrixValues :: !String
  }
  deriving (Eq, Show, Generic)
instance WithDefaultSvg ColorMatrix where
  defaultSvg =
    ColorMatrix
      { _colorMatrixDrawAttributes = defaultSvg,
        _colorMatrixFilterAttr = defaultSvg,
        _colorMatrixIn = Last Nothing,
        _colorMatrixType = Matrix,
        _colorMatrixValues = ""
      }
data CompositeOperator
  = CompositeOver 
  | CompositeIn
  | CompositeOut
  | CompositeAtop
  | CompositeXor
  | CompositeArithmetic
  deriving (Eq, Show, Generic)
data Composite = Composite
  { _compositeDrawAttributes :: DrawAttributes,
    _compositeFilterAttr :: !FilterAttributes,
    _compositeIn :: Last FilterSource,
    _compositeIn2 :: Last FilterSource,
    _compositeOperator :: CompositeOperator,
    _compositeK1 :: Number,
    _compositeK2 :: Number,
    _compositeK3 :: Number,
    _compositeK4 :: Number
  }
  deriving (Eq, Show, Generic)
instance WithDefaultSvg Composite where
  defaultSvg =
    Composite
      { _compositeDrawAttributes = defaultSvg,
        _compositeFilterAttr = defaultSvg,
        _compositeIn = Last Nothing,
        _compositeIn2 = Last Nothing,
        _compositeOperator = CompositeOver,
        _compositeK1 = Num 0,
        _compositeK2 = Num 0,
        _compositeK3 = Num 0,
        _compositeK4 = Num 0
      }
data Turbulence = Turbulence
  { _turbulenceDrawAttributes :: !DrawAttributes,
    _turbulenceFilterAttr :: !FilterAttributes,
    _turbulenceBaseFrequency :: !(Double, Last Double), 
    _turbulenceNumOctaves :: Int, 
    _turbulenceSeed :: Double,
    _turbulenceStitchTiles :: StitchTiles,
    _turbulenceType :: TurbulenceType
  }
  deriving (Eq, Show, Generic)
data StitchTiles
  = NoStitch
  | Stitch
  deriving (Eq, Show, Generic)
data TurbulenceType
  = FractalNoiseType
  | TurbulenceType
  deriving (Eq, Show, Generic)
instance WithDefaultSvg Turbulence where
  defaultSvg =
    Turbulence
      { _turbulenceDrawAttributes = defaultSvg,
        _turbulenceFilterAttr = defaultSvg,
        _turbulenceBaseFrequency = (0, Last Nothing),
        _turbulenceNumOctaves = 1,
        _turbulenceSeed = 0,
        _turbulenceStitchTiles = NoStitch,
        _turbulenceType = TurbulenceType
      }
data EdgeMode
  = EdgeDuplicate
  | EdgeWrap
  | EdgeNone
  deriving (Eq, Show, Generic)
data GaussianBlur = GaussianBlur
  { _gaussianBlurDrawAttributes :: DrawAttributes,
    _gaussianBlurFilterAttr :: !FilterAttributes,
    _gaussianBlurIn :: Last FilterSource,
    _gaussianBlurStdDeviationX :: Number,
    _gaussianBlurStdDeviationY :: Last Number,
    _gaussianBlurEdgeMode :: EdgeMode
  }
  deriving (Eq, Show, Generic)
instance WithDefaultSvg GaussianBlur where
  defaultSvg =
    GaussianBlur
      { _gaussianBlurDrawAttributes = defaultSvg,
        _gaussianBlurFilterAttr = defaultSvg,
        _gaussianBlurIn = Last Nothing,
        _gaussianBlurStdDeviationX = Num 0,
        _gaussianBlurStdDeviationY = Last Nothing,
        _gaussianBlurEdgeMode = EdgeDuplicate
      }
data MarkerOrientation
  = 
    OrientationAuto
  | 
    OrientationAngle Coord
  deriving (Eq, Show, Generic)
data MarkerUnit
  = 
    MarkerUnitStrokeWidth
  | 
    MarkerUnitUserSpaceOnUse
  deriving (Eq, Show, Generic)
data Overflow
  = 
    OverflowVisible
  | 
    OverflowHidden
  deriving (Eq, Show, Generic)
data Marker = Marker
  { _markerDrawAttributes :: DrawAttributes,
    
    
    _markerRefPoint :: !(Number, Number),
    
    
    _markerWidth :: !(Maybe Number),
    
    
    _markerHeight :: !(Maybe Number),
    
    _markerOrient :: !(Maybe MarkerOrientation),
    
    _markerUnits :: !(Maybe MarkerUnit),
    
    _markerViewBox :: !(Maybe (Double, Double, Double, Double)),
    
    _markerOverflow :: !(Maybe Overflow),
    
    _markerAspectRatio :: !PreserveAspectRatio,
    
    _markerElements :: [Tree]
  }
  deriving (Eq, Show, Generic)
instance WithDefaultSvg Marker where
  defaultSvg =
    Marker
      { _markerDrawAttributes = mempty,
        _markerRefPoint = (Num 0, Num 0),
        _markerWidth = Just (Num 3),
        _markerHeight = Just (Num 3),
        _markerOrient = Nothing, 
        _markerUnits = Nothing, 
        _markerViewBox = Nothing,
        _markerOverflow = Nothing,
        _markerElements = mempty,
        _markerAspectRatio = defaultSvg
      }
nameOfTree :: Tree -> T.Text
nameOfTree v =
  case _treeBranch v of
    NoNode -> ""
    UseNode _ _ -> "use"
    GroupNode _ -> "g"
    SymbolNode _ -> "symbol"
    DefinitionNode _ -> "defs"
    FilterNode _ -> "filter"
    PathNode _ -> "path"
    CircleNode _ -> "circle"
    PolyLineNode _ -> "polyline"
    PolygonNode _ -> "polygon"
    EllipseNode _ -> "ellipse"
    LineNode _ -> "line"
    RectangleNode _ -> "rectangle"
    TextNode _ _ -> "text"
    ImageNode _ -> "image"
    LinearGradientNode _ -> "lineargradient"
    RadialGradientNode _ -> "radialgradient"
    MeshGradientNode _ -> "meshgradient"
    PatternNode _ -> "pattern"
    MarkerNode _ -> "marker"
    MaskNode _ -> "mask"
    ClipPathNode _ -> "clipPath"
    SvgNode {} -> "svg"
data Spread
  = 
    SpreadRepeat
  | 
    SpreadPad
  | 
    SpreadReflect
  deriving (Eq, Show, Generic)
data LinearGradient = LinearGradient
  { _linearGradientDrawAttributes :: DrawAttributes,
    
    
    _linearGradientUnits :: CoordinateUnits,
    
    
    _linearGradientStart :: Point,
    
    
    _linearGradientStop :: Point,
    
    
    
    _linearGradientSpread :: Spread,
    
    
    
    _linearGradientTransform :: [Transformation],
    
    _linearGradientStops :: [GradientStop]
  }
  deriving (Eq, Show, Generic)
instance WithDefaultSvg LinearGradient where
  defaultSvg =
    LinearGradient
      { _linearGradientDrawAttributes = mempty,
        _linearGradientUnits = CoordBoundingBox,
        _linearGradientStart = (Percent 0, Percent 0),
        _linearGradientStop = (Percent 1, Percent 0),
        _linearGradientSpread = SpreadPad,
        _linearGradientTransform = [],
        _linearGradientStops = []
      }
data RadialGradient = RadialGradient
  { _radialGradientDrawAttributes :: DrawAttributes,
    
    
    _radialGradientUnits :: CoordinateUnits,
    
    
    _radialGradientCenter :: Point,
    
    
    _radialGradientRadius :: Number,
    
    
    _radialGradientFocusX :: Maybe Number,
    
    
    _radialGradientFocusY :: Maybe Number,
    
    
    
    _radialGradientSpread :: Spread,
    
    
    
    _radialGradientTransform :: [Transformation],
    
    _radialGradientStops :: [GradientStop]
  }
  deriving (Eq, Show, Generic)
instance WithDefaultSvg RadialGradient where
  defaultSvg =
    RadialGradient
      { _radialGradientDrawAttributes = mempty,
        _radialGradientUnits = CoordBoundingBox,
        _radialGradientCenter = (Percent 0.5, Percent 0.5),
        _radialGradientRadius = Percent 0.5,
        _radialGradientFocusX = Nothing,
        _radialGradientFocusY = Nothing,
        _radialGradientSpread = SpreadPad,
        _radialGradientTransform = [],
        _radialGradientStops = []
      }
data Mask = Mask
  { _maskDrawAttributes :: DrawAttributes,
    
    _maskContentUnits :: CoordinateUnits,
    
    _maskUnits :: CoordinateUnits,
    
    _maskPosition :: Point,
    
    _maskWidth :: Number,
    
    _maskHeight :: Number,
    
    _maskContent :: [Tree]
  }
  deriving (Eq, Show, Generic)
instance WithDefaultSvg Mask where
  defaultSvg =
    Mask
      { _maskDrawAttributes = mempty,
        _maskContentUnits = CoordUserSpace,
        _maskUnits = CoordBoundingBox,
        _maskPosition = (Percent (-0.1), Percent (-0.1)),
        _maskWidth = Percent 1.2,
        _maskHeight = Percent 1.2,
        _maskContent = []
      }
data ClipPath = ClipPath
  { _clipPathDrawAttributes :: DrawAttributes,
    
    _clipPathUnits :: CoordinateUnits,
    
    _clipPathContent :: [Tree]
  }
  deriving (Eq, Show, Generic)
instance WithDefaultSvg ClipPath where
  defaultSvg =
    ClipPath
      { _clipPathDrawAttributes = mempty,
        _clipPathUnits = CoordUserSpace,
        _clipPathContent = mempty
      }
data Pattern = Pattern
  { _patternDrawAttributes :: DrawAttributes,
    
    _patternViewBox :: !(Maybe (Double, Double, Double, Double)),
    
    
    _patternWidth :: !Number,
    
    
    _patternHeight :: !Number,
    
    
    _patternPos :: !Point,
    
    
    _patternHref :: !String,
    
    _patternElements :: ![Tree],
    
    
    
    _patternUnit :: !CoordinateUnits,
    
    _patternAspectRatio :: !PreserveAspectRatio,
    
    _patternTransform :: !(Maybe [Transformation])
  }
  deriving (Eq, Show, Generic)
instance WithDefaultSvg Pattern where
  defaultSvg =
    Pattern
      { _patternDrawAttributes = mempty,
        _patternViewBox = Nothing,
        _patternWidth = Num 0,
        _patternHeight = Num 0,
        _patternPos = (Num 0, Num 0),
        _patternElements = [],
        _patternUnit = CoordBoundingBox,
        _patternAspectRatio = defaultSvg,
        _patternHref = "",
        _patternTransform = mempty
      }
data Element
  = ElementLinearGradient LinearGradient
  | ElementRadialGradient RadialGradient
  | ElementMeshGradient MeshGradient
  | ElementGeometry Tree
  | ElementPattern Pattern
  | ElementMarker Marker
  | ElementMask Mask
  | ElementClipPath ClipPath
  deriving (Eq, Show, Generic)
data Document = Document
  { _documentViewBox :: Maybe (Double, Double, Double, Double),
    _documentWidth :: Maybe Number,
    _documentHeight :: Maybe Number,
    _documentElements :: [Tree],
    _documentDescription :: String,
    _documentLocation :: FilePath,
    _documentAspectRatio :: PreserveAspectRatio
  }
  deriving (Show, Eq, Generic)
documentSize :: Dpi -> Document -> (Int, Int)
documentSize
  _
  Document
    { _documentViewBox = Just (x1, y1, x2, y2),
      _documentWidth = Just (Percent pw),
      _documentHeight = Just (Percent ph)
    } =
    (floor $ dx * pw, floor $ dy * ph)
    where
      dx = abs $ x2 - x1
      dy = abs $ y2 - y1
documentSize
  _
  Document
    { _documentWidth = Just (Num w),
      _documentHeight = Just (Num h)
    } = (floor w, floor h)
documentSize
  dpi
  doc@( Document
          { _documentWidth = Just w,
            _documentHeight = Just h
          }
        ) =
    documentSize dpi $
      doc
        { _documentWidth = Just $ toUserUnit dpi w,
          _documentHeight = Just $ toUserUnit dpi h
        }
documentSize _ Document {_documentViewBox = Just (x1, y1, x2, y2)} =
  (floor . abs $ x2 - x1, floor . abs $ y2 - y1)
documentSize _ _ = (1, 1)
mayMerge :: Monoid a => Maybe a -> Maybe a -> Maybe a
mayMerge (Just a) (Just b) = Just $ mappend a b
mayMerge _ b@(Just _) = b
mayMerge a Nothing = a
instance Semigroup DrawAttributes where
  (<>) a b =
    DrawAttributes
      { _strokeWidth = (mappend `on` _strokeWidth) a b,
        _strokeColor = (mappend `on` _strokeColor) a b,
        _strokeLineCap = (mappend `on` _strokeLineCap) a b,
        _strokeOpacity = (opacityMappend `on` _strokeOpacity) a b,
        _strokeLineJoin = (mappend `on` _strokeLineJoin) a b,
        _strokeMiterLimit = (mappend `on` _strokeMiterLimit) a b,
        _fillColor = (mappend `on` _fillColor) a b,
        _fillOpacity = (opacityMappend `on` _fillOpacity) a b,
        _fontSize = (mappend `on` _fontSize) a b,
        _transform = (mayMerge `on` _transform) a b,
        _fillRule = (mappend `on` _fillRule) a b,
        _attrClass = _attrClass b,
        _attrId = _attrId b,
        _groupOpacity = _groupOpacity b,
        _strokeOffset = (mappend `on` _strokeOffset) a b,
        _strokeDashArray = (mappend `on` _strokeDashArray) a b,
        _fontFamily = (mappend `on` _fontFamily) a b,
        _fontStyle = (mappend `on` _fontStyle) a b,
        _textAnchor = (mappend `on` _textAnchor) a b,
        _maskRef = (mappend `on` _maskRef) a b,
        _clipPathRef = (mappend `on` _clipPathRef) a b,
        _clipRule = (mappend `on` _clipRule) a b,
        _markerStart = (mappend `on` _markerStart) a b,
        _markerMid = (mappend `on` _markerMid) a b,
        _markerEnd = (mappend `on` _markerEnd) a b,
        _filterRef = (mappend `on` _filterRef) a b
      }
    where
      opacityMappend Nothing Nothing = Nothing
      opacityMappend (Just v) Nothing = Just v
      opacityMappend Nothing (Just v) = Just v
      opacityMappend (Just v) (Just v2) = Just $ v * v2
instance Monoid DrawAttributes where
  mappend = (<>)
  mempty =
    DrawAttributes
      { _strokeWidth = Last Nothing,
        _strokeColor = Last Nothing,
        _strokeOpacity = Nothing,
        _strokeLineCap = Last Nothing,
        _strokeLineJoin = Last Nothing,
        _strokeMiterLimit = Last Nothing,
        _fillColor = Last Nothing,
        _groupOpacity = Nothing,
        _fillOpacity = Nothing,
        _fontSize = Last Nothing,
        _fontFamily = Last Nothing,
        _fontStyle = Last Nothing,
        _transform = Nothing,
        _fillRule = Last Nothing,
        _attrClass = mempty,
        _attrId = Nothing,
        _strokeOffset = Last Nothing,
        _strokeDashArray = Last Nothing,
        _textAnchor = Last Nothing,
        _maskRef = Last Nothing,
        _clipPathRef = Last Nothing,
        _clipRule = Last Nothing,
        _markerStart = Last Nothing,
        _markerMid = Last Nothing,
        _markerEnd = Last Nothing,
        _filterRef = Last Nothing
      }
instance WithDefaultSvg DrawAttributes where
  defaultSvg = mempty
makeLenses ''Rectangle
makeLenses ''Pattern
makeLenses ''Document
makeLenses ''Filter
makeLenses ''Line
makeLenses ''Polygon
makeLenses ''PolyLine
makeLenses ''PreserveAspectRatio
makeLenses ''Path
makeLenses ''Circle
makeLenses ''Text
makeLenses ''TextPath
makeLenses ''Ellipse
makeLenses ''MeshGradientPatch
makeLenses ''MeshGradientRow
makeLenses ''MeshGradient
makeLenses ''Image
makeLenses ''Use
makeLenses ''TextSpan
makeLenses ''TextInfo
makeLenses ''Marker
makeLenses ''GradientStop
makeLenses ''LinearGradient
makeLenses ''RadialGradient
makeLenses ''Mask
makeLenses ''ClipPath
makeLenses ''ColorMatrix
makeLenses ''Composite
makeLenses ''GaussianBlur
makeLenses ''Turbulence
makeLenses ''DisplacementMap
makeLenses ''Group
makeClassy ''FilterAttributes