{-
This controls gnuplot variables for a plot.
We use a separate data type for that purpose
in order to be able to share a set of options between different plots.
(If we would only allow to set options of a frame,
e.g. border :: Bool -> Frame -> Frame,
we could of course still build
an options setting function of type Frame -> Frame
from smaller option setters.)
-}
module Graphics.Gnuplot.Private.FrameOptionSet where

import qualified Graphics.Gnuplot.Private.FrameOption as Option
import Graphics.Gnuplot.Utility (formatBool, )

import qualified Data.Map as Map

import Data.Maybe.HT (toMaybe, )
import Data.Maybe (mapMaybe, )


type Plain = Map.Map Option.T [String]

newtype T graph =
   Cons {T graph -> Plain
decons :: Plain}


{- |
The default options contain what we expect as default value in gnuplot.
We need an entry for every option that cannot be reset by @unset@.
-}
deflt :: Plain
deflt :: Plain
deflt =
   [(T, [[Char]])] -> Plain
forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList ([(T, [[Char]])] -> Plain) -> [(T, [[Char]])] -> Plain
forall a b. (a -> b) -> a -> b
$
   (T
Option.keyShow, []) (T, [[Char]]) -> [(T, [[Char]])] -> [(T, [[Char]])]
forall a. a -> [a] -> [a]
:
--   (Option.border, []) :
   (T
Option.sizeRatio, [[Char]
"noratio"]) (T, [[Char]]) -> [(T, [[Char]])] -> [(T, [[Char]])]
forall a. a -> [a] -> [a]
:
   (T
Option.xLabelText, []) (T, [[Char]]) -> [(T, [[Char]])] -> [(T, [[Char]])]
forall a. a -> [a] -> [a]
:
   (T
Option.yLabelText, []) (T, [[Char]]) -> [(T, [[Char]])] -> [(T, [[Char]])]
forall a. a -> [a] -> [a]
:
   (T
Option.zLabelText, []) (T, [[Char]]) -> [(T, [[Char]])] -> [(T, [[Char]])]
forall a. a -> [a] -> [a]
:
   (T
Option.xRangeBounds, [[Char]
"[*:*]"]) (T, [[Char]]) -> [(T, [[Char]])] -> [(T, [[Char]])]
forall a. a -> [a] -> [a]
:
   (T
Option.yRangeBounds, [[Char]
"[*:*]"]) (T, [[Char]]) -> [(T, [[Char]])] -> [(T, [[Char]])]
forall a. a -> [a] -> [a]
:
   (T
Option.zRangeBounds, [[Char]
"[*:*]"]) (T, [[Char]]) -> [(T, [[Char]])] -> [(T, [[Char]])]
forall a. a -> [a] -> [a]
:
   (T
Option.xFormat, []) (T, [[Char]]) -> [(T, [[Char]])] -> [(T, [[Char]])]
forall a. a -> [a] -> [a]
:
   (T
Option.yFormat, []) (T, [[Char]]) -> [(T, [[Char]])] -> [(T, [[Char]])]
forall a. a -> [a] -> [a]
:
   (T
Option.zFormat, []) (T, [[Char]]) -> [(T, [[Char]])] -> [(T, [[Char]])]
forall a. a -> [a] -> [a]
:
   (T
Option.xTickLabels, []) (T, [[Char]]) -> [(T, [[Char]])] -> [(T, [[Char]])]
forall a. a -> [a] -> [a]
:
   (T
Option.yTickLabels, []) (T, [[Char]]) -> [(T, [[Char]])] -> [(T, [[Char]])]
forall a. a -> [a] -> [a]
:
   (T
Option.zTickLabels, []) (T, [[Char]]) -> [(T, [[Char]])] -> [(T, [[Char]])]
forall a. a -> [a] -> [a]
:
   (T
Option.gridXTicks, [[Char]
"noxtics"]) (T, [[Char]]) -> [(T, [[Char]])] -> [(T, [[Char]])]
forall a. a -> [a] -> [a]
:
   (T
Option.gridYTicks, [[Char]
"noytics"]) (T, [[Char]]) -> [(T, [[Char]])] -> [(T, [[Char]])]
forall a. a -> [a] -> [a]
:
   (T
Option.gridZTicks, [[Char]
"noztics"]) (T, [[Char]]) -> [(T, [[Char]])] -> [(T, [[Char]])]
forall a. a -> [a] -> [a]
:
   (T
Option.styleFillSolid, [[Char]
"0"]) (T, [[Char]]) -> [(T, [[Char]])] -> [(T, [[Char]])]
forall a. a -> [a] -> [a]
:
   (T
Option.styleFillBorder, []) (T, [[Char]]) -> [(T, [[Char]])] -> [(T, [[Char]])]
forall a. a -> [a] -> [a]
:
   (T
Option.styleHistogram, [[Char]
"clustered"]) (T, [[Char]]) -> [(T, [[Char]])] -> [(T, [[Char]])]
forall a. a -> [a] -> [a]
:
--   (Option.timeFmt, [quote "%s"]) :
   (T
Option.boxwidth, []) (T, [[Char]]) -> [(T, [[Char]])] -> [(T, [[Char]])]
forall a. a -> [a] -> [a]
:
   []

initial :: Plain
initial :: Plain
initial =
   (Plain -> Plain -> Plain) -> Plain -> Plain -> Plain
forall a b c. (a -> b -> c) -> b -> a -> c
flip Plain -> Plain -> Plain
forall k a. Ord k => Map k a -> Map k a -> Map k a
Map.union Plain
deflt (Plain -> Plain) -> Plain -> Plain
forall a b. (a -> b) -> a -> b
$
   [(T, [[Char]])] -> Plain
forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList ([(T, [[Char]])] -> Plain) -> [(T, [[Char]])] -> Plain
forall a b. (a -> b) -> a -> b
$
   (T
Option.xData, []) (T, [[Char]]) -> [(T, [[Char]])] -> [(T, [[Char]])]
forall a. a -> [a] -> [a]
:
   (T
Option.yData, []) (T, [[Char]]) -> [(T, [[Char]])] -> [(T, [[Char]])]
forall a. a -> [a] -> [a]
:
   (T
Option.zData, []) (T, [[Char]]) -> [(T, [[Char]])] -> [(T, [[Char]])]
forall a. a -> [a] -> [a]
:
--   (Option.timeFmt, []) :
   []

{- |
Add (set) an option with arguments as plain strings.

This is very flexible, but not very safe.
Use it only as fall-back,
if there is no specific setter function in "Graphics.Gnuplot.Frame.OptionSet".
-}
add :: Option.T -> [String] -> T graph -> T graph
add :: T -> [[Char]] -> T graph -> T graph
add T
opt [[Char]]
args (Cons Plain
m) =
   Plain -> T graph
forall graph. Plain -> T graph
Cons (T -> [[Char]] -> Plain -> Plain
forall k a. Ord k => k -> a -> Map k a -> Map k a
Map.insert T
opt [[Char]]
args Plain
m)

{- |
Remove (unset) an option.

This is very flexible, but not very safe.
Use it only as fall-back,
if there is no specific setter function in "Graphics.Gnuplot.Frame.OptionSet".
-}
remove :: Option.T -> T graph -> T graph
remove :: T -> T graph -> T graph
remove T
opt (Cons Plain
m) =
   Plain -> T graph
forall graph. Plain -> T graph
Cons (T -> Plain -> Plain
forall k a. Ord k => k -> Map k a -> Map k a
Map.delete T
opt Plain
m)

{- |
Convert the difference between the first and the second option set
into a sequence of 'set' and 'unset' commands.
-}
diffToString :: Plain -> Plain -> [String]
diffToString :: Plain -> Plain -> [[Char]]
diffToString Plain
m0 Plain
m1 =
   ((T, (Maybe [[Char]], Maybe [[Char]])) -> Maybe [Char])
-> [(T, (Maybe [[Char]], Maybe [[Char]]))] -> [[Char]]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe
      (\(Option.Cons [Char]
opt [Char]
_, (Maybe [[Char]]
old,Maybe [[Char]]
new)) ->
         Bool -> [Char] -> Maybe [Char]
forall a. Bool -> a -> Maybe a
toMaybe (Maybe [[Char]]
oldMaybe [[Char]] -> Maybe [[Char]] -> Bool
forall a. Eq a => a -> a -> Bool
/=Maybe [[Char]]
new) ([Char] -> Maybe [Char]) -> [Char] -> Maybe [Char]
forall a b. (a -> b) -> a -> b
$
         [Char] -> ([[Char]] -> [Char]) -> Maybe [[Char]] -> [Char]
forall b a. b -> (a -> b) -> Maybe a -> b
maybe
            ([Char]
"unset " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
opt)
            (\[[Char]]
args -> [Char]
"set " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
opt [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ ([Char] -> [Char]) -> [[Char]] -> [Char]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap (Char
' 'Char -> [Char] -> [Char]
forall a. a -> [a] -> [a]
:) [[Char]]
args)
            Maybe [[Char]]
new) ([(T, (Maybe [[Char]], Maybe [[Char]]))] -> [[Char]])
-> [(T, (Maybe [[Char]], Maybe [[Char]]))] -> [[Char]]
forall a b. (a -> b) -> a -> b
$
   Map T (Maybe [[Char]], Maybe [[Char]])
-> [(T, (Maybe [[Char]], Maybe [[Char]]))]
forall k a. Map k a -> [(k, a)]
Map.toList (Map T (Maybe [[Char]], Maybe [[Char]])
 -> [(T, (Maybe [[Char]], Maybe [[Char]]))])
-> Map T (Maybe [[Char]], Maybe [[Char]])
-> [(T, (Maybe [[Char]], Maybe [[Char]]))]
forall a b. (a -> b) -> a -> b
$
   ((Maybe [[Char]], Maybe [[Char]])
 -> (Maybe [[Char]], Maybe [[Char]])
 -> (Maybe [[Char]], Maybe [[Char]]))
-> Map T (Maybe [[Char]], Maybe [[Char]])
-> Map T (Maybe [[Char]], Maybe [[Char]])
-> Map T (Maybe [[Char]], Maybe [[Char]])
forall k a. Ord k => (a -> a -> a) -> Map k a -> Map k a -> Map k a
Map.unionWith
      (\(Maybe [[Char]]
old,Maybe [[Char]]
_) (Maybe [[Char]]
_,Maybe [[Char]]
new) -> (Maybe [[Char]]
old,Maybe [[Char]]
new))
      (([[Char]] -> (Maybe [[Char]], Maybe [[Char]]))
-> Plain -> Map T (Maybe [[Char]], Maybe [[Char]])
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\[[Char]]
x -> ([[Char]] -> Maybe [[Char]]
forall a. a -> Maybe a
Just [[Char]]
x, Maybe [[Char]]
forall a. Maybe a
Nothing)) Plain
m0)
      (([[Char]] -> (Maybe [[Char]], Maybe [[Char]]))
-> Plain -> Map T (Maybe [[Char]], Maybe [[Char]])
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\[[Char]]
x -> (Maybe [[Char]]
forall a. Maybe a
Nothing, [[Char]] -> Maybe [[Char]]
forall a. a -> Maybe a
Just [[Char]]
x)) Plain
m1)

{- |
Set or unset option according to a 'Bool'.
This is for switches that can be disabled using @unset@.

This is very flexible, but not very safe.
Use it only as fall-back,
if there is no specific setter function in "Graphics.Gnuplot.Frame.OptionSet".

See also: 'addBool', 'add', 'remove'.
-}
boolean :: Option.T -> Bool -> T graph -> T graph
boolean :: T -> Bool -> T graph -> T graph
boolean T
opt Bool
on =
   if Bool
on
     then T -> [[Char]] -> T graph -> T graph
forall graph. T -> [[Char]] -> T graph -> T graph
add T
opt []
     else T -> T graph -> T graph
forall graph. T -> T graph -> T graph
remove T
opt

{- |
Add an option with boolean value
that is formatted like @set style fill border@ and @set style fill noborder@.
The name of the internal state (i.e. @border@)
must be stored in the second field of the option.

This is very flexible, but not very safe.
Use it only as fall-back,
if there is no specific setter function in "Graphics.Gnuplot.Frame.OptionSet".

See also 'boolean'.
-}
addBool :: Option.T -> Bool -> T graph -> T graph
addBool :: T -> Bool -> T graph -> T graph
addBool opt :: T
opt@(Option.Cons [Char]
_ [Char]
state) Bool
arg =
   T -> [[Char]] -> T graph -> T graph
forall graph. T -> [[Char]] -> T graph -> T graph
add T
opt [[Char] -> Bool -> [Char]
formatBool [Char]
state Bool
arg]