{-# LANGUAGE ScopedTypeVariables, TemplateHaskell, TypeSynonymInstances, FlexibleInstances #-}
----------------------------------------------------------------------------
-- |
-- Module      :  Graphics.Rendering.Chart.Easy
-- Copyright   :  (c) Tim Docker 2014
-- License     :  BSD-style (see chart/COPYRIGHT)
--
-- A high level API for generating a plot quickly.
-- 
-- Importing the Easy module brings into scope all core functions and types required
-- for working with the chart library. This includes key external dependencies such as
-- Control.Lens and Data.Colour. The module also provides several helper functions for
-- quickly generating common plots. Note that chart backends must still be explicitly
-- imported, as some backends cannot be built on all platforms.
--
-- Example usage:
--
-- > import Graphics.Rendering.Chart.Easy
-- > import Graphics.Rendering.Chart.Backend.Cairo
-- > 
-- > signal :: [Double] -> [(Double,Double)]
-- > signal xs = [ (x,(sin (x*3.14159/45) + 1) / 2 * (sin (x*3.14159/5))) | x <- xs ]
-- > 
-- > main = toFile def "example.png" $ do
-- >     layout_title .= "Amplitude Modulation"
-- >     plot (line "am" [signal [0,(0.5)..400]])
-- >     plot (points "am points" (signal [0,7..400]))
--
-- More examples can be found on the <https://github.com/timbod7/haskell-chart/wiki library's wiki>

module Graphics.Rendering.Chart.Easy(

  module Control.Lens,
  module Data.Default.Class,
  module Data.Colour,
  module Data.Colour.Names,

  module Graphics.Rendering.Chart,
  module Graphics.Rendering.Chart.State,

  line,
  points,
  bars,
  setColors,
  setShapes
  ) where

import Control.Lens
import Control.Monad(when)
import Data.Default.Class
import Data.Colour hiding (over) -- overlaps with lens over function
import Data.Colour.Names
import Graphics.Rendering.Chart
import Graphics.Rendering.Chart.State

-- | Set the contents of the colour source, for
-- subsequent plots
setColors :: [AlphaColour Double] -> EC l ()
setColors cs = liftCState $ colors .= cycle cs

-- | Set the contents of the shape source, for
-- subsequent plots
setShapes :: [PointShape] -> EC l ()
setShapes ps = liftCState $ shapes .= cycle ps

-- | Constuct a line plot with the given title and
-- data, using the next available color.
line :: String -> [[(x,y)]]  -> EC l (PlotLines x y)
line title values = liftEC $ do
    color <- takeColor
    plot_lines_title .= title
    plot_lines_values .= values
    plot_lines_style . line_color .= color

-- | Construct a scatter plot with the given title and data, using the
-- next available color and point shape.
points :: String -> [(x,y)]  -> EC l (PlotPoints x y)
points title values = liftEC $ do
    color <- takeColor
    shape <- takeShape
    plot_points_values .= values
    plot_points_title .= title
    plot_points_style . point_color .= color
    plot_points_style . point_shape .= shape
    plot_points_style . point_radius .= 2
    
    -- Show borders for unfilled shapes
    when (not (isFilled shape)) $ do
        plot_points_style . point_border_color .= color
        plot_points_style . point_border_width .= 1

isFilled :: PointShape -> Bool
isFilled PointShapeCircle = True
isFilled PointShapePolygon{} = True
isFilled _ = False
    
-- | Construct a bar chart with the given titles and data, using the
-- next available colors    
bars :: (PlotValue x, BarsPlotValue y) => [String] -> [(x,[y])] -> EC l (PlotBars x y)
bars titles vals = liftEC $ do
    styles <- sequence [fmap mkStyle takeColor | _ <- titles]
    plot_bars_titles .= titles
    plot_bars_values .= vals
    plot_bars_style .= BarsClustered
    plot_bars_spacing .= BarsFixGap 30 5
    plot_bars_item_styles .= styles
  where
    mkStyle c = (solidFillStyle c, Just (solidLine 1.0 $ opaque black))
