{-# LANGUAGE OverloadedStrings #-}

--
-- Based on the Elm VegaLite GalleryFacet.elm (from development of version
-- 1.13.0)
--
module Gallery.Facet (testSpecs) where

import Graphics.Vega.VegaLite

import qualified Data.Text as T

import Prelude hiding (filter, lookup, repeat)

import Data.Aeson (Value, (.=), object, toJSON)


testSpecs :: [(String, VegaLite)]
testSpecs = [ ("facet1", facet1)
            , ("facet2", facet2)
            , ("facet3", facet3)
            , ("facet4", facet4)
            , ("facet5", facet5)
            , ("facet6", facet6)
            , ("facet7", facet7)
            , ("trellisareaseattle", trellisAreaSeattle)
            , ("facetgridbar", facetGridBar)
            , ("facet_bullet", facetBullet)
            ]


facet1 :: VegaLite
facet1 =
    let
        des =
            description "A trellis bar chart showing the US population distribution of age groups and gender in 2000"

        dvals =
            dataFromUrl "https://vega.github.io/vega-lite/data/population.json"

        trans =
            transform
                . filter (FExpr "datum.year == 2000")
                . calculateAs "datum.sex == 2 ? 'Female' : 'Male'" "gender"

        enc =
            encoding
                . position X [ PName "age", PmType Ordinal ]
                . position Y [ PName "people", PmType Quantitative, PAggregate Sum, PAxis [ AxTitle "Population" ] ]
                . color [ MName "gender", MmType Nominal, MScale [ SRange (RStrings [ "#EA98D2", "#659CCA" ]) ] ]
                . row [ FName "gender", FmType Nominal ]
    in
    toVegaLite [ des, dvals [], trans [], mark Bar [], widthStep 17, enc [] ]


facet2 :: VegaLite
facet2 =
    let
        des =
            description "Barley crop yields in 1931 and 1932 shown as stacked bar charts"

        enc =
            encoding
                . position X [ PName "yield", PmType Quantitative, PAggregate Sum ]
                . position Y [ PName "variety", PmType Nominal ]
                . color [ MName "site", MmType Nominal ]
                . column [ FName "year", FmType Ordinal ]
    in
    toVegaLite
        [ des
        , dataFromUrl "https://vega.github.io/vega-lite/data/barley.json" []
        , mark Bar []
        , enc []
        ]


facet3 :: VegaLite
facet3 =
    let
        des =
            description "Scatterplots of movie takings vs profits for different MPAA ratings"

        enc =
            encoding
                . position X [ PName "Worldwide_Gross", PmType Quantitative ]
                . position Y [ PName "US_DVD_Sales", PmType Quantitative ]
                . column [ FName "MPAA_Rating", FmType Ordinal ]
    in
    toVegaLite
        [ des
        , dataFromUrl "https://vega.github.io/vega-lite/data/movies.json" []
        , mark Point []
        , enc []
        ]


facet4 :: VegaLite
facet4 =
    let
        des =
            description "Distributions of car engine power for different countries of origin"

        enc =
            encoding
                . position X [ PName "Horsepower", PmType Quantitative, PBin [ MaxBins 15 ] ]
                . position Y [ PmType Quantitative, PAggregate Count ]
                . row [ FName "Origin"
                      , FmType Ordinal
                      , FTitle "Origin facet"
                      ]
    in
    toVegaLite
        [ des
        , dataFromUrl "https://vega.github.io/vega-lite/data/cars.json" []
        , mark Bar []
        , enc []
        ]


facet5 :: VegaLite
facet5 =
    let
        des =
            description "Anscombe's Quartet"

        enc =
            encoding
                . position X [ PName "X", PmType Quantitative, PScale [ SZero False ] ]
                . position Y [ PName "Y", PmType Quantitative, PScale [ SZero False ] ]
                . opacity [ MNumber 1 ]
                . column [ FName "Series", FmType Ordinal ]
    in
    toVegaLite [ des, dataFromUrl "https://vega.github.io/vega-lite/data/anscombe.json" [], mark Circle [], enc [] ]


facet6 :: VegaLite
facet6 =
    let
        des =
            description "The Trellis display by Becker et al. helped establish small multiples as a 'powerful mechanism for understanding interactions in studies of how a response depends on explanatory variables'"

        dvals =
            dataFromUrl "https://vega.github.io/vega-lite/data/barley.json"

        enc =
            encoding
                . position X
                    [ PName "yield"
                    , PmType Quantitative
                    , PAggregate Median
                    , PScale [ SZero False ]
                    ]
                . position Y
                    [ PName "variety"
                    , PmType Ordinal
                    , PSort [ ByChannel ChX, Descending ]
                    ]
                . color [ MName "year", MmType Nominal ]
    in
    toVegaLite
        [ des
        , dvals []
        , columns 2
        , facetFlow
            [ FName "site"
            , FmType Ordinal
            , FSort [ ByFieldOp "yield" Median ]
            , FHeader [ HNoTitle ]
            ]
        , specification (asSpec [ enc [], heightStep 12, mark Point [] ])
        ]


facet7 :: VegaLite
facet7 =
    let
        des =
            description "Stock prices of five large companies as a small multiples of area charts"

        dvals =
            dataFromUrl "https://vega.github.io/vega-lite/data/stocks.csv"

        enc =
            encoding
                . position X
                    [ PName "date"
                    , PmType Temporal
                    , PAxis [ AxFormat "%Y", AxNoTitle, AxGrid False ]
                    ]
                . position Y
                    [ PName "price"
                    , PmType Quantitative
                    , PAxis [ AxNoTitle, AxGrid False ]
                    ]
                . color
                    [ MName "symbol"
                    , MmType Nominal
                    , MLegend []
                    ]
                . row
                    [ FName "symbol"
                    , FmType Nominal
                    , FHeader [ HTitle "Stock\nprice"
                              , HTitleLineHeight 20
                              , HLabelAngle 0
                              -- I don't know why the labels only align
                              -- when AlignLeft is used.
                              , HLabelAlign AlignLeft
                              , HLabelExpr "'{' + datum.label + '}'"
                              , HLabelFontStyle "italic"
                              ]
                    ]

        res =
            resolve
                . resolution (RScale [ ( ChY, Independent ) ])

        cfg =
            configure
                . configuration (ViewStyle [ ViewNoStroke ])
    in
    toVegaLite [ des, width 300, height 50, cfg [], res [], dvals [], mark Area [], enc [] ]


-- https://vega.github.io/vega-lite/examples/trellis_area_seattle.html
--
trellisAreaSeattle :: VegaLite
trellisAreaSeattle =
  let desc = description "Average temps in Seattle, by hour"

      ylabels = "hours(datum.value) == 0 ? 'Midnight' : hours(datum.value) == 12 ? 'Noon' : timeFormat(datum.value, '%I:%M %p')"

      plot = asSpec [ width 800
                    , height 25
                    , viewBackground [VBNoStroke]
                    , mark Area []
                    , encoding
                      . position X [ PName "date"
                                   , PmType Temporal
                                   , PTitle "Month"
                                   , PAxis [AxFormat "%b"]
                                   ]
                      . position Y [ PName "temp"
                                   , PmType Quantitative
                                   , PScale [SZero False]
                                   , PAxis [AxNoTitle, AxLabels False, AxTicks False]
                                   ]
                      $ []
                    ]

  in toVegaLite [ desc
                , title "Seattle Annual Temperatures" []
                , dataFromUrl "https://vega.github.io/vega-lite/data/seattle-temps.csv" []
                , transform
                  (calculateAs "(hours(datum.date) + 18) % 24" "order" [])
                , spacing 1  -- NOTE: can not specify this is just for row
                , configure (configuration (Axis [Grid False, Domain False]) [])
                , facet [ RowBy [ FName "date"
                                , FmType Nominal
                                , FTimeUnit (TU Hours)
                                , FSort [ByFieldOp "order" Max] -- don't want an operation
                                , FHeader [ HLabelAngle 0
                                          , HLabelPadding 2
                                          , HTitlePadding (-4)
                                          , HLabelAlign AlignLeft
                                          , HLabelExpr ylabels
                                          ]
                                ]
                        ]
                , specification plot
                ]


-- https://vega.github.io/vega-lite/examples/facet_grid_bar.html
facetGridBar :: VegaLite
facetGridBar =
  let dvals = dataFromColumns []
              . dataColumn "a" (Strings xa)
              . dataColumn "b" (Strings xb)
              . dataColumn "c" (Strings xc)
              . dataColumn "p" (Strings xp)
              $ []

      xa = [ "a1", "a1", "a1", "a1", "a1", "a1", "a1", "a1", "a1"
           , "a2", "a2", "a2", "a2", "a2", "a2", "a2", "a2", "a2"
           , "a3", "a3", "a3", "a3", "a3", "a3", "a3", "a3", "a3"
           ]
      xb = [ "b1", "b1", "b1", "b2", "b2", "b2", "b3", "b3", "b3"
           , "b1", "b1", "b1", "b2", "b2", "b2", "b3", "b3", "b3"
           , "b1", "b1", "b1", "b2", "b2", "b2", "b3", "b3", "b3"
           ]
      xc = [ "x", "y", "z", "x", "y", "z", "x", "y", "z"
           , "x", "y", "z", "x", "y", "z", "x", "y", "z"
           , "x", "y", "z", "x", "y", "z", "x", "y", "z"
           ]
      xp = [ "0.14", "0.60", "0.03", "0.80", "0.38", "0.55", "0.11", "0.58", "0.79"
           , "0.83", "0.87", "0.67", "0.97", "0.84", "0.90", "0.74", "0.64", "0.19"
           , "0.57", "0.35", "0.49", "0.91", "0.38", "0.91", "0.99", "0.80", "0.37"
           ]
        
      enc = encoding
            . position X [ PName "p"
                         , PmType Quantitative
                         , PAxis [AxFormat "%"]
                         , PNoTitle
                         ]
            . position Y [ PName "c"
                         , PmType Nominal
                         , PAxis []
                         ]
            . color [ MName "c"
                    , MmType Nominal
                    , MLegend [LOrient LOBottom, LTitleOrient SLeft]
                    , MTitle "settings"
                    ]
            . row [ FName "a"
                  , FmType Nominal
                  , FTitle "Factor A"
                  , FHeader [HLabelAngle 0]
                  ]
            . column [ FName "b"
                     , FmType Nominal
                     , FTitle "Factor B"
                     ]

  in toVegaLite [ description "A simple grid of bar charts to compare performance data."
                , dvals
                , width 60
                , heightStep 8
                , spacing 5
                , mark Bar []
                , enc []
                ]


bullets :: Value
bullets =
  let item :: T.Text -> T.Text -> [Double] -> [Double] -> [Double] -> Value
      item ttl subtitle ranges measures markers =
        object [ "title" .= ttl
               , "subtitle" .= subtitle
               , "ranges" .= ranges
               , "measures" .= measures
               , "markers" .= markers
               ]

  in toJSON [ item "Revenue" "US$, in thousands" [150,225,300] [220,270] [250]
            , item "Profit" "%" [20,25,30] [21,23] [26]
            , item "Order Size" "US$, average" [350,500,600] [100,320] [550]
            , item "New Customers" "count" [1400,2000,2500] [1000,1650] [2100]
            , item "Satisfaction" "out of 5" [3.5,4.25,5] [3.2,4.7] [4.4]
            ]


-- https://vega.github.io/vega-lite/examples/facet_bullet.html
facetBullet :: VegaLite
facetBullet =
  let facetOpts = facet [ RowBy [ FName "title"
                                , FmType Ordinal
                                , FHeader [ HLabelAngle 0
                                          , HNoTitle ]
                                ]
                        ]

      plot = asSpec [ encoding
                      (position X [ PmType Quantitative
                                  , PScale [SNice (IsNice False)]
                                  , PNoTitle
                                  ] [])
                    , layer (map asSpec plots)
                    ]

      encX fld = encoding (position X [PName fld] [])

      plots = [ [ mark Bar [MColor "#eee"]
                , encX "ranges[2]" ]
              , [ mark Bar [MColor "#ddd"]
                , encX "ranges[1]" ]
              , [ mark Bar [MColor "#ccc"]
                , encX "ranges[0]" ]
              , [ mark Bar [MColor "lightsteelblue", MSize 10]
                , encX "measures[1]" ]
              , [ mark Bar [MColor "steelblue", MSize 10]
                , encX "measures[0]" ]
              , [ mark Tick [MColor "black"]
                , encX "markers[0]" ]
              ]

      res = resolve . resolution (RScale [(ChX, Independent)])

      cfg = configure . configuration (TickStyle [MThickness 2])

  in toVegaLite [ dataFromJson bullets []
                , facetOpts
                , spacing 10
                , specification plot
                , res []
                , cfg []
                ]