{-# LANGUAGE DeriveGeneric, DeriveAnyClass #-}
module Eventloop.Module.Websocket.Canvas.Types where

import Control.Concurrent.MVar
import GHC.Generics (Generic)
import Control.DeepSeq

import Eventloop.Types.Common

type CanvasSystemReceiveBuffer = MVar SystemCanvasIn

instance Show (MVar a) where
    show _ = "CanvasSystemReceiveBuffer"


type Opcode = Int

type ScreenMetric = Int
type ScreenX = ScreenMetric
type ScreenY = ScreenMetric
type ScreenWidth = ScreenMetric
type ScreenHeight = ScreenMetric
type ScreenRadius = ScreenMetric
type ScreenAngle = ScreenMetric -- ^In degrees

type ScreenPoint = (ScreenX, ScreenY)
type ScreenDimensions = (ScreenWidth, ScreenHeight)

type ScreenStartingPoint = ScreenPoint
type ScreenControlPoint = ScreenPoint
type ScreenEndPoint = ScreenPoint

type ScreenStartingAngle = ScreenAngle
type ScreenEndAngle = ScreenAngle

type CanvasId = NumericId
type ZIndex = Int

type ScreenColorMetric = Int
type ScreenRed = ScreenColorMetric
type ScreenGreen = ScreenColorMetric
type ScreenBlue = ScreenColorMetric
type ScreenAlpha = Float
type ScreenColor = (ScreenRed, ScreenGreen, ScreenBlue, ScreenAlpha)
type ScreenPixel = ScreenColor

type ColorStopOffset = Float

type ScreenCircle = (ScreenPoint, ScreenRadius)

type ScaleUnit = Float
type ScaleX = ScaleUnit
type ScaleY = ScaleUnit

type ScreenLineThickness = Float

type FontFamily = [Char]
type FontSize = Int -- In Pixels


data RoutedMessageIn = InUserCanvas CanvasIn
                     | InSystemCanvas SystemCanvasIn
                     deriving (Eq, Show)

data RoutedMessageOut = OutUserCanvas CanvasOut
                      | OutSystemCanvas SystemCanvasOut
                      deriving (Eq, Show, Generic, NFData)

{- |Opcode: 2100-}
data SystemCanvasIn = SystemMeasuredText CanvasText ScreenDimensions {- ^Opcode: 2101-}
                    deriving (Eq, Show)

{- |Opcode: 2000-}
data SystemCanvasOut = SystemMeasureText CanvasText  {- ^Opcode: 2001-}
                     deriving (Eq, Show, Generic, NFData)

{- |Opcode: 0100-}
data CanvasIn = MeasuredText CanvasText ScreenDimensions {- ^Opcode: 0101-}
              deriving (Eq, Show)


{- Main types -}
{- | Reserved type words
     Type: t      | Opcode
     Arguments: a | List of arguments for that data type
     Route: r     | Either 's' for system or 'u' for user
     Object: o    | The object that is beneath

     Example:
     {'r': 's', 'o': {SystemMeasuredText object}}

     SystemMeasuredText object: {'t':2102, 'a':[CanvasId, CanvasText object, ScreenDimensions]}
-}

{- |Opcode: 0200-}
data CanvasOut = SetupCanvas CanvasId ZIndex ScreenDimensions CSSPosition {- ^Opcode: 0201-}
               | TeardownCanvas CanvasId {- ^Opcode: 0202-}
               | CanvasOperations CanvasId [CanvasOperation] {- ^Opcode: 0203-}
               | MeasureText CanvasText {- ^Opcode: 0204-}
               deriving (Eq, Show, Generic, NFData)

{- |Opcode: 0300-}
data CanvasOperation = DrawPath ScreenStartingPoint [ScreenPathPart] PathStroke PathFill {- ^Opcode: 0301 -}
                     | DrawText CanvasText ScreenPoint TextStroke TextFill {- ^Opcode: 0302 -}
                     | DoTransform CanvasTransform {- ^Opcode: 0303 -}
                     | Clear ClearPart {- ^Opcode: 0304 -}
                     | Frame {- ^Opcode: 0305 -}
                     deriving (Eq, Show, Generic, NFData)

{- |Opcode: 0400-}
data ScreenPathPart = MoveTo ScreenPoint {- ^Opcode: 0401-}
                    | LineTo ScreenPoint {- ^Opcode: 0402-}
                    | BezierCurveTo ScreenControlPoint ScreenControlPoint ScreenEndPoint {- ^Opcode: 0403-}
                    | QuadraticCurveTo ScreenControlPoint ScreenEndPoint {- ^Opcode: 0404-}
                    | ArcTo ScreenControlPoint ScreenControlPoint ScreenRadius {- ^Opcode: 0405-}
                    | Arc ScreenCircle ScreenStartingAngle ScreenEndAngle {- ^Opcode: 0406-}
                    | Rectangle ScreenPoint ScreenDimensions {- ^Opcode: 0407-}
                    | ClosePath {- ^Opcode: 0408-}
                    deriving (Eq, Show, Generic, NFData)

{- Styling of Shapes -}
{- |Opcode: 0500-}
type PathRenderStrokeStyle = RenderStyle

data PathStroke = PathStroke ScreenLineThickness PathRenderStrokeStyle {- ^Opcode: 0501-}
                | NoPathStroke {- ^Opcode: 0502-}
                deriving (Eq, Show, Generic, NFData)

{- |Opcode: 0600-}
type PathRenderFillStyle = RenderStyle

data PathFill = PathFill PathRenderFillStyle {- ^Opcode: 0601-}
              | NoPathFill {- ^Opcode: 0602-}
              deriving (Eq, Show, Generic, NFData)

{- |Opcode: 0700-}
type CanvasColorStop = (ColorStopOffset, ScreenColor)

data RenderStyle = CanvasColor ScreenColor {- ^Opcode: 0701-}
                 | CanvasGradient CanvasGradientType [CanvasColorStop] {- ^Opcode:0702-}
                 | CanvasPattern CanvasImage PatternRepetition {- ^Opcode: 0703-}
                     deriving (Eq, Show, Generic, NFData)

{- |Opcode: 0800-}
data CanvasImage = CanvasElement CanvasId ScreenPoint ScreenDimensions {- ^Opcode: 0801-}
                 | ImageData ScreenDimensions [ScreenPixel] {- ^Opcode: 0802
                                                            [ScreenPixel] should be as long as width * height * 4. Each quad is red,green,blue,alpha
                                                            -}
                 deriving (Eq, Show, Generic, NFData)
{- |Opcode: 0900-}
data PatternRepetition = Repeat {- ^Opcode: 0901-}
                       | RepeatX {- ^Opcode: 0902-}
                       | RepeatY {- ^Opcode: 0903-}
                       | NoRepeat {- ^Opcode: 0904-}
                       deriving (Eq, Show, Generic, NFData)

{- |Opcode: 1000-}
data CanvasGradientType = RadialGradient ScreenCircle ScreenCircle {- ^Opcode: 1001
                                                                       First circle = inner circle, Second circle is enclosing circle
                                                                   -}
                        | LinearGradient ScreenPoint ScreenPoint {- ^Opcode: 1002-}
                        deriving (Eq, Show, Generic, NFData)

{- To Draw Text -}
{- |Opcode: 1200-}
data CanvasText = CanvasText [Char] Font Alignment {- ^Opcode: 1201-}
                deriving (Eq, Show, Generic, NFData)

{- |Opcode: 1300-}
data Font = Font FontFamily FontSize {- ^Opcode: 1301-}
          deriving (Eq, Show, Generic, NFData)

{- |Opcode: 1400-}
type TextStrokeRenderStyle = RenderStyle
type TextFillRenderStyle = RenderStyle

data TextStroke = TextStroke ScreenLineThickness TextStrokeRenderStyle {- ^Opcode: 1401-}
                | NoTextStroke {- ^Opcode: 1402-}
                deriving (Eq, Show, Generic, NFData)

{- |Opcode: 2400-}
data TextFill = TextFill TextFillRenderStyle {- ^Opcode: 2401-}
              | NoTextFill {- ^Opcode: 2402-}
              deriving (Eq, Show, Generic, NFData)

{- |Opcode: 1500-}
data Alignment = AlignLeft {- ^Opcode: 1501-}
               | AlignRight {- ^Opcode: 1502-}
               | AlignCenter {- ^Opcode: 1503-}
               deriving (Eq, Show, Generic, NFData)

{- Transform The Canvas -}
{- |Opcode: 1600-}
type TransformUnit = Float
type TransformationMatrix  = (TransformUnit, TransformUnit, TransformUnit, TransformUnit, TransformUnit, TransformUnit)

data CanvasTransform = Save {- ^Opcode: 1601-}
                     | Restore {- ^Opcode: 1602-}
                     | Translate ScreenPoint {- ^Opcode: 1603-}
                     | Rotate ScreenAngle {- ^Opcode: 1604-}
                     | Scale ScaleX ScaleY {- ^Opcode: 1605-}
                     | Transform TransformationMatrix {- ^Opcode: 1606-}
                     | SetTransform TransformationMatrix {- ^Opcode: 1607-}
                     | ResetTransform {- ^Opcode: 1608-}
                     deriving (Eq, Show, Generic, NFData)

{- CSS Position of DOM elements -}
{- |Opcode: 2200-}
type CSSLeftOffset = CSSUnit
type CSSTopOffset = CSSUnit
type CSSMeasurements = (CSSLeftOffset, CSSTopOffset)

data CSSPosition = CSSPosition CSSBindPoint CSSMeasurements {- ^Opcode: 2201-}
                 deriving (Eq, Show, Generic, NFData)

{- |Opcode: 2300-}
data CSSBindPoint = CSSFromCenter {- ^Opcode: 2301-}
                  | CSSFromDefault {- ^Opcode: 2302 Usually this is the top left corner of the element -}
                  deriving (Eq, Show, Generic, NFData)

{- |Opcode: 1800-}
data CSSUnit = CSSPixels Int {- ^Opcode: 1801-}
             | CSSPercentage Int {- ^Opcode: 1802-}
             deriving (Eq, Show, Generic, NFData)

{- |Opcode: 1900 -}
data ClearPart = ClearRectangle ScreenPoint ScreenDimensions {- ^Opcode: 1901-}
               | ClearCanvas {- ^Opcode: 1902-}
               deriving (Eq, Show, Generic, NFData)