{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE FlexibleInstances #-}

module QuickPlot.Plotly (
      plotly
    , PlotlyJSON (..)
    , PlotlyData
    , PlotlyLayout
) where

import QuickPlot
import QuickPlot.IPC.Protocol
import QuickPlot.IPC.QQParser
import Language.Haskell.TH
import Language.Haskell.TH.Syntax
import Language.Haskell.TH.Quote
import Data.Aeson hiding (json)


type PlotlyData = PlotlyJSON
type PlotlyLayout = PlotlyJSON


instance Plottable PlotlyData where
    plottableToJSON (PlotlyJSON trace) = [json|{
                                    data : [ #{ trace } ]
                                }|]
    whichLibrary _ = Plotly

instance Plottable [PlotlyData] where
    plottableToJSON traces = [json|{
                        data : #{ traces }
                    }|]
    whichLibrary _ = Plotly

instance Plottable (PlotlyData, PlotlyLayout) where
    plottableToJSON (traces, layout) = [json|{
                                  data : [ #{ traces } ]
                                , layout : #{ layout }
                              }|]
    whichLibrary _ = Plotly

instance Plottable ([PlotlyData], PlotlyLayout) where
    plottableToJSON (traces, layout) = [json|{
                                  data : #{ traces }
                                , layout : #{ layout }
                              }|]
    whichLibrary _ = Plotly


-- This quasiquoter is the same as json but it wraps the value with PlotlyJSON
-- It makes writing code more clear when using multiple libraries
plotly :: QuasiQuoter
plotly = QuasiQuoter { quoteExp  = plotlyExp
                     , quotePat  = const $ error "No quotePat defined for jsonQQ"
                     , quoteType = const $ error "No quoteType defined for jsonQQ"
                     , quoteDec  = const $ error "No quoteDec defined for jsonQQ"
                     }

plotlyExp :: String -> ExpQ
plotlyExp string =
    case parseTHJSON string of
        Left errorInfo  -> error $ "JSON is invalid: " ++ show errorInfo
        Right value     -> [| PlotlyJSON value |]


data PlotlyJSON = PlotlyJSON Value

instance ToJSON PlotlyJSON where
    toJSON (PlotlyJSON value) = value

instance Lift PlotlyJSON where
    lift (PlotlyJSON value) = [| PlotlyJSON value |]