{-# LANGUAGE OverloadedStrings,MultiParamTypeClasses,FlexibleInstances,ExistentialQuantification,TypeSynonymInstances #-}

module D3JS.Syntax where

import Data.Text (Text)
import qualified Data.Text as T

import D3JS.Type
import D3JS.Reify

import Control.Monad.RWS

-- | St (which means Statement) monad represents JavaScript statements.
-- "D3JS.Chart" uses St monad extensively.
type St r =  RWS () Text Int r

getUniqueNum :: St Int
getUniqueNum = do
	n <- get
	put (n+1)
	return n

instance Reifiable (St r) where
	reify st =
		let (a,s,w) = runRWS st () 0
		in w

-- Run a chain without assignment.
execute :: Chain () b -> St ()
execute chain = tell $ T.concat [reify chain,";\n"]

-- | d[0] as a user-defined function.
idx0 = Index 0 DataParam

-- | d[1] as a user-defined function.
idx1 = Index 1 DataParam

-- | d.x as a user-defined function.
_x = Field "x" DataParam

-- | d.y as a user-defined function.
_y = Field "y" DataParam

class Assignable a where
	newVar :: St (Var' a)

	assign :: Chain () a -> St (Var' a)
	assign chain = do
		v@(Var' n) <- newVar
		tell $ T.concat ["var ",n," = ",reify chain,";\n"]
		return v

instance Assignable Data2D where
	newVar = newVar' "dat"

instance Assignable (SelData Data2D) where
	newVar = newVar' "sel_dat"

instance Assignable Selection where
	newVar = newVar' "sel"

newVar' :: Text -> St (Var' a)
newVar' baseName = getUniqueNum >>= (return . Var' . T.append baseName . show')