{-|
Module      : Graphics.Vega.VegaLite.Data
Copyright   : (c) Douglas Burke, 2018-2019
License     : BSD3

Maintainer  : dburke.gw@gmail.com
Stability   : unstable

Representing data values (excluding base time
types).

-}

module Graphics.Vega.VegaLite.Data
       ( DataValue(..)
       , DataValues(..)

       -- not for external export
       , dataValueSpec
       , dataValuesSpecs

       ) where

import qualified Data.Aeson as A
import qualified Data.Text as T

import Data.Aeson (toJSON)


import Graphics.Vega.VegaLite.Specification (VLSpec)
import Graphics.Vega.VegaLite.Time
  ( DateTime
  , dateTimeSpec
  )


{-|

A single data value. This is used when a function or constructor
can accept values of different types (e.g. either a number or a string),
such as:
'Graphics.Vega.VegaLite.dataRow', 'Graphics.Vega.VegaLite.geometry', many constructors of the 'Graphics.Vega.VegaLite.Filter' type,
'Graphics.Vega.VegaLite.ImNewValue', and 'Graphics.Vega.VegaLite.SInit'.

-}
data DataValue
    = Boolean Bool
    | DateTime [DateTime]
    | Number Double
    | Str T.Text
    | NullValue
      -- ^ Create a JavaScript @null@ value. This can be useful when
      --   explictly recoding a value as undefined, such as in the following
      --   example:
      --
      --   @
      --   'Graphics.Vega.VegaLite.dataFromRows' []
      --     . 'Graphics.Vega.VegaLite.dataRow' [("x", 'Number' 1), ("y", 'Str' "good")]
      --     . 'Graphics.Vega.VegaLite.dataRow' [("x", 'Number' 2), ("y", 'NullValue')]
      --     . 'Graphics.Vega.VegaLite.dataRow' [("x", 'Number' 3), ("y", 'String' "bad")]
      --   @
      --
      --   For more-complex data sources - such as lists of defined
      --   and un-specified values, it is suggested that 'Graphics.Vega.VegaLite.dataFromJson'
      --   be used rather than 'Graphics.Vega.VegaLite.dataFromRows' or 'Graphics.Vega.VegaLite.dataFromColumns'.
      --
      --   @since 0.4.0.0

dataValueSpec :: DataValue -> VLSpec
dataValueSpec :: DataValue -> VLSpec
dataValueSpec (Boolean Bool
b) = Bool -> VLSpec
forall a. ToJSON a => a -> VLSpec
toJSON Bool
b
dataValueSpec (DateTime [DateTime]
dt) = [DateTime] -> VLSpec
dateTimeSpec [DateTime]
dt
dataValueSpec (Number Double
x) = Double -> VLSpec
forall a. ToJSON a => a -> VLSpec
toJSON Double
x
dataValueSpec (Str Text
t) = Text -> VLSpec
forall a. ToJSON a => a -> VLSpec
toJSON Text
t
dataValueSpec DataValue
NullValue = VLSpec
A.Null


{-|

A list of data values. This is used when a function or constructor
can accept lists of different types (e.g. either a list of numbers
or a list of strings), such as:
'Graphics.Vega.VegaLite.dataColumn', 'Graphics.Vega.VegaLite.CustomSort', 'Graphics.Vega.VegaLite.FOneOf', or 'Graphics.Vega.VegaLite.ImKeyVals'.

If your data contains undefined values then it is suggested that
you convert it to JSON (e.g. 'A.Value') and then use 'Graphics.Vega.VegaLite.dataFromJson'.

-}
data DataValues
    = Booleans [Bool]
    | DateTimes [[DateTime]]
    | Numbers [Double]
    | Strings [T.Text]


dataValuesSpecs :: DataValues -> [VLSpec]
dataValuesSpecs :: DataValues -> [VLSpec]
dataValuesSpecs (Booleans [Bool]
bs) = (Bool -> VLSpec) -> [Bool] -> [VLSpec]
forall a b. (a -> b) -> [a] -> [b]
map Bool -> VLSpec
forall a. ToJSON a => a -> VLSpec
toJSON [Bool]
bs
dataValuesSpecs (DateTimes [[DateTime]]
dtss) = ([DateTime] -> VLSpec) -> [[DateTime]] -> [VLSpec]
forall a b. (a -> b) -> [a] -> [b]
map [DateTime] -> VLSpec
dateTimeSpec [[DateTime]]
dtss
dataValuesSpecs (Numbers [Double]
xs) = (Double -> VLSpec) -> [Double] -> [VLSpec]
forall a b. (a -> b) -> [a] -> [b]
map Double -> VLSpec
forall a. ToJSON a => a -> VLSpec
toJSON [Double]
xs
dataValuesSpecs (Strings [Text]
ss) = (Text -> VLSpec) -> [Text] -> [VLSpec]
forall a b. (a -> b) -> [a] -> [b]
map Text -> VLSpec
forall a. ToJSON a => a -> VLSpec
toJSON [Text]
ss