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

module QuickPlot.Vis (
      vis
    , VisJSON (..)
    , VisPlotType (..)
    , VisData
    , VisOptions
) 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)
import Data.Text




type VisData = VisJSON
type VisOptions = VisJSON

-- | Only Network graphs work
data VisPlotType = Network
                 deriving Show


instance Plottable (VisPlotType, VisData) where
    plottableToJSON (plotType, (VisJSON trace)) = [json|{
                                      plotType : #{ plotType }
                                    , data : #{ trace }
                                    , options : {}
                             }|]
    whichLibrary _ = Vis

instance Plottable (VisPlotType, [VisData]) where
    plottableToJSON (plotType, traces) = [json|{
                          plotType : #{ plotType }
                        , data : #{ traces }
                        , options : {}
                    }|]
    whichLibrary _ = Vis

instance Plottable (VisPlotType, VisData, VisOptions) where
    plottableToJSON (plotType, traces, options) = [json|{
                                  plotType : #{ plotType }
                                , data : #{ traces }
                                , options : #{ options }
                              }|]
    whichLibrary _ = Vis

instance Plottable (VisPlotType, [VisData], VisOptions) where
    plottableToJSON (plotType, traces, options) = [json|{
                                  plotType : #{ plotType }
                                , data : #{ traces }
                                , options : #{ options }
                              }|]
    whichLibrary _ = Vis




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


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


data VisJSON = VisJSON Value


instance ToJSON VisJSON where
    toJSON (VisJSON value) = value

instance ToJSON VisPlotType where
    toJSON Network  = String "network"
    -- toJSON Timeline = String "timeline"
    -- toJSON Graph2D  = String "graph2d"
    -- toJSON Graph3D  = String "graph3d"

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