{-# LANGUAGE OverloadedStrings #-}
module Eventloop.Module.Websocket.Canvas.JSONEncoding where

import Data.Aeson
import Data.Aeson.Types
import Control.Applicative
import Control.Monad

import Eventloop.Module.Websocket.Canvas.Types
import Eventloop.Module.Websocket.Canvas.Opcode


instance FromJSON RoutedMessageIn where
    parseJSON (Object v) = do
                            route <- v .: "r" :: Parser [Char]
                            obj <- v .: "o"
                            case route of
                                        "s" -> InSystemCanvas <$> (parseJSON obj)
                                        "u" -> InUserCanvas <$> (parseJSON obj)

instance FromJSON SystemCanvasIn where
    parseJSON (Object v) = do
                            opCode <- v .: "t" :: Parser Int
                            case opCode of
                                        2101 -> SystemMeasuredText <$> (v .: "canvastext" >>= parseJSON)
                                                                   <*> ( (\width height -> (width, height))
                                                                        <$> v .: "width"
                                                                        <*> v .: "height"
                                                                       )

instance FromJSON CanvasIn where
    parseJSON (Object v) = do
                            opCode <- v .: "t" :: Parser Int
                            case opCode of
                                        101 -> MeasuredText <$> (v .: "canvastext" >>= parseJSON)
                                                            <*> ( (\width height -> (width, height))
                                                                <$> v .: "width"
                                                                <*> v .: "height"
                                                                )

instance FromJSON CanvasText where
    parseJSON (Object v) = CanvasText <$>  v .: "text" <*> (v .: "font" >>= parseJSON) <*> (v .: "alignment" >>= parseJSON)


instance FromJSON Font where
    parseJSON (Object v) = Font <$> v .: "fontfamily" <*> v .: "fontsize"


instance FromJSON Alignment where
    parseJSON (Object v) = do
                            alignment <- v .: "t" :: Parser Int
                            return $ case alignment of
                                        1501 -> AlignLeft
                                        1502 -> AlignRight
                                        1503 -> AlignCenter



operationObject :: Opcode -> [Value] -> Value
operationObject opcode []               = object ["t" .= opcode]
operationObject opcode encodedArguments = object ["t" .= opcode, "a" .= encodedArguments]


instance ToJSON RoutedMessageOut where
    toJSON d@(OutUserCanvas canvasOut)   = object ["r" .= route, "o" .= canvasOut]
                                        where
                                            route = "u" :: [Char]
    toJSON d@(OutSystemCanvas canvasOut) = object ["r" .= route, "o" .= canvasOut]
                                        where
                                            route = "s" :: [Char]


instance ToJSON SystemCanvasOut where
    toJSON d@(SystemMeasureText canvasText) = operationObject (toOpcode d) [ toJSON canvasText
                                                                           ]


instance ToJSON CanvasOut where
    toJSON d@(SetupCanvas canvasId zIndex screenDimensions cssPosition) = operationObject (toOpcode d) [ toJSON canvasId
                                                                                                       , toJSON zIndex
                                                                                                       , toJSON screenDimensions
                                                                                                       , toJSON cssPosition
                                                                                                       ]
    toJSON d@(TeardownCanvas canvasId) = operationObject (toOpcode d) [toJSON canvasId]
    toJSON d@(CanvasOperations canvasId canvasOperations) = operationObject (toOpcode d) [ toJSON canvasId
                                                                                         , toJSON canvasOperations
                                                                                         ]
    toJSON d@(MeasureText text) = operationObject (toOpcode d) [ toJSON text
                                                               ]


instance ToJSON CanvasOperation where
    toJSON d@(DrawPath screenStartingPoint screenPathParts pathStroke pathFill) = operationObject (toOpcode d) [ toJSON screenStartingPoint
                                                                                                               , toJSON screenPathParts
                                                                                                               , toJSON pathStroke
                                                                                                               , toJSON pathFill
                                                                                                               ]
    toJSON d@(DrawText canvasText screenPoint textStroke textFill) = operationObject (toOpcode d) [ toJSON canvasText
                                                                                                  , toJSON screenPoint
                                                                                                  , toJSON textStroke
                                                                                                  , toJSON textFill
                                                                                                  ]
    toJSON d@(DoTransform canvasTransform) = operationObject (toOpcode d) [toJSON canvasTransform]
    toJSON d@(Clear clearPart) = operationObject (toOpcode d) [toJSON clearPart]
    toJSON d@(Frame) = operationObject (toOpcode d) []


instance ToJSON ScreenPathPart where
    toJSON d@(MoveTo screenPoint) = operationObject (toOpcode d) [toJSON screenPoint]
    toJSON d@(LineTo screenPoint) = operationObject (toOpcode d) [toJSON screenPoint]
    toJSON d@(BezierCurveTo screenControlPoint1 screenControlPoint2 screenEndPoint) = operationObject (toOpcode d) [ toJSON screenControlPoint1
                                                                                                                   , toJSON screenControlPoint2
                                                                                                                   , toJSON screenEndPoint
                                                                                                                   ]
    toJSON d@(QuadraticCurveTo screenControlPoint screenEndPoint) = operationObject (toOpcode d) [ toJSON screenControlPoint
                                                                                                  , toJSON screenEndPoint
                                                                                                  ]
    toJSON d@(ArcTo screenControlPoint1 screenControlPoint2 screenRadius) = operationObject (toOpcode d) [ toJSON screenControlPoint1
                                                                                                         , toJSON screenControlPoint2
                                                                                                         , toJSON screenRadius
                                                                                                         ]
    toJSON d@(Arc screenCircle screenStartingAngle screenEndAngle) = operationObject (toOpcode d) [ toJSON screenCircle
                                                                                                  , toJSON screenStartingAngle
                                                                                                  , toJSON screenEndAngle
                                                                                                  ]
    toJSON d@(Rectangle screenPoint screenDimensions) = operationObject (toOpcode d) [ toJSON screenPoint
                                                                                     , toJSON screenDimensions
                                                                                     ]
    toJSON d@(ClosePath) = operationObject (toOpcode d) []

instance ToJSON PathStroke where
    toJSON d@(PathStroke screenLineThickness pathRenderStrokeStyle) = operationObject (toOpcode d) [ toJSON screenLineThickness
                                                                                                   , toJSON pathRenderStrokeStyle
                                                                                                   ]
    toJSON d = operationObject (toOpcode d) []


instance ToJSON PathFill where
    toJSON d@(PathFill pathRenderFillStyle) = operationObject (toOpcode d) [toJSON pathRenderFillStyle]
    toJSON d = operationObject (toOpcode d) []


instance ToJSON RenderStyle where
    toJSON d@(CanvasColor screenColor) = operationObject (toOpcode d) [toJSON screenColor]
    toJSON d@(CanvasGradient canvasGradientType canvasColorStops) = operationObject (toOpcode d) [ toJSON canvasGradientType
                                                                                                 , toJSON canvasColorStops
                                                                                                 ]

    toJSON d@(CanvasPattern canvasImage patternRepetition) = operationObject (toOpcode d) [ toJSON canvasImage
                                                                                          , toJSON patternRepetition
                                                                                          ]


instance ToJSON CanvasImage where
    toJSON d@(CanvasElement canvasId screenPoint screenDimensions) = operationObject (toOpcode d) [ toJSON canvasId
                                                                                                  , toJSON screenPoint
                                                                                                  , toJSON screenDimensions
                                                                                                  ]

    toJSON d@(ImageData screenDimensions screenPixels) = operationObject (toOpcode d) [ toJSON screenDimensions
                                                                                      , toJSON screenPixels
                                                                                      ]

instance ToJSON PatternRepetition where
    toJSON d = operationObject (toOpcode d) []


instance ToJSON CanvasGradientType where
    toJSON d@(RadialGradient screenCircle1 screenCircle2) = operationObject (toOpcode d) [ toJSON screenCircle1
                                                                                         , toJSON screenCircle2
                                                                                         ]

    toJSON d@(LinearGradient screenPoint1 screenPoint2) = operationObject (toOpcode d) [ toJSON screenPoint1
                                                                                       , toJSON screenPoint2
                                                                                       ]


instance ToJSON CanvasText where
    toJSON d@(CanvasText text font alignment) = operationObject (toOpcode d) [ toJSON text
                                                                             , toJSON font
                                                                             , toJSON alignment
                                                                             ]


instance ToJSON Font where
    toJSON d@(Font fontFamily fontSize) = operationObject (toOpcode d) [ toJSON fontFamily
                                                                       , toJSON fontSize
                                                                       ]


instance ToJSON TextStroke where
    toJSON d@(TextStroke screenLineThickness textRenderStyle) = operationObject (toOpcode d) [ toJSON screenLineThickness
                                                                                             , toJSON textRenderStyle
                                                                                             ]
    toJSON d@(NoTextStroke) = operationObject (toOpcode d) []

instance ToJSON TextFill where
    toJSON d@(TextFill textRenderStyle) = operationObject (toOpcode d) [ toJSON textRenderStyle
                                                                       ]
    toJSON d@(NoTextFill) = operationObject (toOpcode d) []


instance ToJSON Alignment where
    toJSON d = operationObject (toOpcode d) []


instance ToJSON CanvasTransform where
    toJSON d@(Translate screenPoint) = operationObject (toOpcode d) [toJSON screenPoint]
    toJSON d@(Rotate screenAngle)    = operationObject (toOpcode d) [toJSON screenAngle]
    toJSON d@(Scale x y)             = operationObject (toOpcode d) [toJSON x, toJSON y]
    toJSON d@(Transform tm)          = operationObject (toOpcode d) [toJSON tm]
    toJSON d@(SetTransform tm)       = operationObject (toOpcode d) [toJSON tm]
    toJSON d                         = operationObject (toOpcode d) []


instance ToJSON CSSPosition where
    toJSON d@(CSSPosition cssBindPoint cssMeasurements) = operationObject (toOpcode d) [ toJSON cssBindPoint
                                                                                       , toJSON cssMeasurements
                                                                                       ]

instance ToJSON CSSBindPoint where
    toJSON d = operationObject (toOpcode d) []

instance ToJSON CSSUnit where
    toJSON d@(CSSPixels i)     = operationObject (toOpcode d) [toJSON i]
    toJSON d@(CSSPercentage i) = operationObject (toOpcode d) [toJSON i]


instance ToJSON ClearPart where
    toJSON d@(ClearRectangle screenPoint screenDimensions) = operationObject (toOpcode d) [ toJSON screenPoint
                                                                                          , toJSON screenDimensions
                                                                                          ]
    toJSON d = operationObject (toOpcode d) []