{-# LANGUAGE OverloadedStrings,TypeSynonymInstances,NoMonomorphismRestriction #-} 

module Text.LaTeX.Packages
    ( -- * Package ms
      Package
    , PackageOption
      -- * List of Package ms
      -- ** @doc@
    , doc
      -- ** @exscale@
    , exscale
      -- ** @ifthen@
    , ifthen
      -- ** @msym@
    , msym
      -- ** @makeidx@
    , makeidx
      -- ** @fontenc@
    , fontenc
    , oT1 , t1
    , t2A, t2B
    , t2C, x2
    , lgr
      -- ** @syntonly@
    , syntonly
    , syntaxonly
      -- ** @inputenc@
    , inputenc
    , applemac
    , macukr
    , latin1
    , koi8_ru
    , ansinew
    , cp1251
    , cp850
    , cp866nav
      -- ** @ucs@
    , ucs
    , utf8x
      -- ** @textcomp@
    , textcomp
    , textdegree
    , textcelsius
    , texteuro
      -- ** @eurosym@
    , eurosym
    , euro
      -- ** @babel@
    , babel
    , selectlanguage
      -- ** @hyperref@
    , hyperref
    , pdftex
    , href
      -- ** @color@
    , colorpkg
    , monochrome
    , dvipsnames
    , nodvipsnames
    , usenames
    , rgb
    , pagecolor
    , color
    , normalcolor
      -- * AMS-LaTeX
    , MathTerm
      -- ** @amsmath@
    , amsmath
    , math
    , equation
    , equation_
    , smash
    , lim , (->>)
    , sums , sums_ , summ
    , sqroot
    , cdot , cdots , vdots , ddots
    , overline
    , overbrace, underbrace
      -- *** Operators
    , (==:) , (/=:)
    , (<=:) , (>=:)
    , (===)
    , (~~) , (~=)
    , (<@) , (>@) , (<=@) , (>=@)
    , (-|) , (|-) , (-/)
    , (/@)
    , (|.|)
    , (+-) , (-+)
    , (<*>)
    , (*:) , (^:) , (!:)
      -- *** Math Mode Accents
    , hat , widehat
    , tilde , widetilde
    , grave , bar
    , acute , mathring
    , check , dot
    , vec , breve
    , ddot
      -- *** Greek Alphabet
    , alpha
    , beta
    , gamma , gamma_
    , delta , delta_
    , epsilon , varepsilon
    , zeta
    , eta
    , theta , vartheta , theta_
    , iota
    , kappa
    , lambda , lambda_
    , mu
    , nu
    , xi , xi_
    , varpi , pi_
    , rho , varrho
    , sigma , varsigma , sigma_
    , tau
    , upsilon, upsilon_
    , phi , varphi, phi_
    , chi
    , psi, psi_
    , omega, omega_
    -- *** Mathematical Functions
    -- *** Symbols
    , dagger , ddagger
    , forall
    -- *** Others
    , binom
    , proof
    ) where

import Data.List (intersperse)
import Data.Monoid

import Data.String.Combinators (braces,fromShow,between)

import Text.LaTeX.Monad
import Text.LaTeX.Define
import Text.LaTeX.Arguments
import Text.LaTeX.Result

type Package m = LaTeX m

type PackageOption m = LaTeX m

doc :: Monad m => Package m
doc = "doc"

exscale :: Monad m => Package m
exscale = "exscale"

ifthen :: Monad m => Package m
ifthen = "ifthen"

msym :: Monad m => Package m
msym = "LaTeX msym"

makeidx :: Monad m => Package m
makeidx = "makeidx"

fontenc :: Monad m => Package m
fontenc = "fontenc"

oT1 :: Monad m => Encoding m
oT1 = "0T1"

t1 :: Monad m => Encoding m
t1 = "T1"

t2A :: Monad m => Encoding m
t2A = "T2A"

t2B :: Monad m => Encoding m
t2B = "T2B"

t2C :: Monad m => Encoding m
t2C = "T2C"

x2 :: Monad m => Encoding m
x2 = "X2"

lgr :: Monad m => Encoding m
lgr = "LGR"

syntonly :: Monad m => Package m
syntonly = "syntonly"

syntaxonly :: Monad m => LaTeX m
syntaxonly = comm0 "syntaxonly"

inputenc :: Monad m => Package m
inputenc = "inputenc"

applemac :: Monad m => Encoding m
applemac = "applemac"

macukr :: Monad m => Encoding m
macukr = "macukr"

latin1 :: Monad m => Encoding m
latin1 = "latin1"

koi8_ru :: Monad m => Encoding m
koi8_ru = "koi8-ru"

ansinew :: Monad m => Encoding m
ansinew = "ansinew"

cp1251 :: Monad m => Encoding m
cp1251 = "cp1251"

cp850 :: Monad m => Encoding m
cp850 = "cp850"

cp866nav :: Monad m => Encoding m
cp866nav = "cp866nav"

ucs :: Monad m => Package m
ucs = "ucs"

utf8x :: Monad m => Encoding m
utf8x = "utf8x"

textcomp :: Monad m => Package m
textcomp = "textcomp"

textdegree :: Monad m => LaTeX m
textdegree = comm0 "textdegree"

textcelsius :: Monad m => LaTeX m
textcelsius = comm0 "textcelsius"

texteuro :: Monad m => LaTeX m
texteuro = comm0 "texteuro"

eurosym :: Monad m => Package m
eurosym = "eurosym"

euro :: Monad m => LaTeX m
euro = comm0 "euro"

babel :: Monad m => Package m
babel = "babel"

selectlanguage :: Monad m => Language m -> LaTeX m
selectlanguage = comm1 "selectlanguage"

hyperref :: Monad m => Package m
hyperref = "hyperref"

pdftex :: Monad m => PackageOption m
pdftex = "pdftex"

href :: Monad m => URL m -> Text m -> LaTeX m
href = comm5 "href"

colorpkg :: Monad m => Package m
colorpkg = "color"

monochrome :: Monad m => PackageOption m
monochrome = "monochrome"

dvipsnames :: Monad m => PackageOption m
dvipsnames = "dvipsnames"

nodvipsnames :: Monad m => PackageOption m
nodvipsnames = "nodvipsnames"

usenames :: Monad m => PackageOption m
usenames = "usenames"

-- | 'Color' from RGB components.
rgb :: Monad m => Float -> Float -> Float -> Color m
rgb r g b = do "[rgb]"
               braces . lx . mconcat . intersperse (toResult ",") $ map fromShow [r,g,b]

-- | Set page color. 'pagecolor' in header defines the default page color of the document.
pagecolor :: Monad m => Color m -> LaTeX m
pagecolor = (comm0_ "pagecolor" >>)

-- | Set font color from current position. 'color' in header defines the default font color of the document.
color :: Monad m => Color m -> LaTeX m
color = (comm0_ "color" >>)

-- | Restore font color from current position.
normalcolor :: Monad m => LaTeX m
normalcolor = comm0 "normalcolor"

----------------------------------
---------- AMS-LaTeX m -------------

-- LaTeXT numeric instances.

inOp :: Monad m => LaTeXT m a -> (LaTeXT m a -> LaTeXT m a -> LaTeXT m a)
inOp op x y = do x ; op ; y

inOpCom :: Monad m => LaTeX m -> (MathTerm m -> MathTerm m -> MathTerm m)
inOpCom = inOp . comm0

genOp :: Monad m => (LaTeX m -> LaTeX m -> LaTeX m) -> (LaTeXT m a -> LaTeXT m a -> LaTeXT m a)
genOp op x y = genlx $ op (ungenlx x) (ungenlx y)

(==:) = inOp "="
(/=:) = inOpCom "neq"
(<=:) = inOpCom "leq"
(>=:) = inOpCom "geq"
(===) = inOpCom "equiv"
(~~)  = inOpCom "sim"
(~=)  = inOpCom "simeq"

(<@)  = inOpCom "subset"
(>@)  = inOpCom "supset"
(<=@) = inOpCom "subseteq"
(>=@) = inOpCom "supseteq"
(-|)  = inOpCom "in"
(|-)  = inOpCom "ni"
(-/)  = inOpCom "notin"
(/@)  = inOpCom "setminus"

(|.|) = inOpCom "parallel"

(+-)  = inOpCom "pm"
(-+)  = inOpCom "mp"

(<*>) = inOpCom "star"

instance (Monad m) => Num (LaTeXT m a) where
 (+) = inOp "+"
 (-) = inOp "-"
 (*) = (>>)
 negate = (comm0 "not" >>)
 fromInteger = lxanyw

(*:) :: Monad m => MathTerm m -> MathTerm m -> MathTerm m
(*:) = inOp cdot

instance (Monad m) => Fractional (LaTeXT m a) where
 (/) = genOp $ comm5 "frac"
 fromRational = lxanyw . (fromRational :: Rational -> Float)

instance (Monad m) => Floating (LaTeXT m a) where
 pi = genlx $ comm0 "pi"
 exp = (comm0 "exp" >>)
 log = (comm0 "log" >>)
 sqrt = genlx . sqroot [] . ungenlx
 (**) = genOp (^:)
 sin = (comm0 "sin" >>)
 cos = (comm0 "cos" >>)
 tan = (comm0 "tan" >>)
 asin = (comm0 "arcsin" >>)
 acos = (comm0 "arccos" >>)
 atan = (comm0 "arctan" >>)
 sinh = (comm0 "sinh" >>)
 cosh = (comm0 "cosh" >>)
 tanh = (comm0 "tanh" >>)

-- AMS-Math

type MathTerm m = LaTeX m

-- | AMS-Math package. It allows you to write mathematical expressions.
amsmath :: Monad m => Package m
amsmath = "amsmath"

-- | Write a mathematical expression inline.
math :: Monad m => MathTerm m -> LaTeX m
math = between "$" "$"

-- | Mathematical expressions environment.
equation :: Monad m => MathTerm m -> LaTeX m
equation = env "equation"

-- | Like 'equation', but expressions are not numbered.
equation_ :: Monad m => MathTerm m -> LaTeX m
equation_ = env "equation*"

smash :: Monad m => LaTeX m -> LaTeX m
smash = comm1 "smash"

text :: Monad m => LaTeX m -> LaTeX m
text = comm1 "text"

-- | Superscript.
(^:) :: Monad m => MathTerm m -> MathTerm m -> MathTerm m
x ^: y = do x ; "^" ; braces y

-- | Subscript.
(!:) :: Monad m => MathTerm m -> MathTerm m -> MathTerm m
x !: y = do x ; "_" ; braces y

lim :: Monad m => MathTerm m
lim = comm0 "lim"

(->>) :: Monad m => MathTerm m -> MathTerm m -> MathTerm m
x ->> y = do x ; comm0 "to" ; y

sums :: Monad m => MathTerm m
sums = comm0 "sum"

sums_ :: Monad m => MathTerm m
sums_ = comm0_ "sum"

summ :: Monad m => MathTerm m -> MathTerm m -> MathTerm m
summ x y = sums_ !: x ^: y

sqroot :: Monad m => [MathTerm m] -> MathTerm m -> MathTerm m
sqroot = comm4 "sqrt"

cdot :: Monad m => MathTerm m
cdot = comm0 "cdot"

cdots :: Monad m => MathTerm m
cdots = comm0 "cdots"

vdots :: Monad m => MathTerm m
vdots = comm0 "vdots"

ddots :: Monad m => MathTerm m
ddots = comm0 "ddots"

overline :: Monad m => MathTerm m -> MathTerm m
overline = comm1 "overline"

overbrace :: Monad m => MathTerm m -> MathTerm m
overbrace = comm1 "overbrace"

underbrace :: Monad m => MathTerm m -> MathTerm m
underbrace = comm1 "underbrace"

-- Math Mode Accents

hat       = comm1 "hat"
grave     = comm1 "grave"
bar       = comm1 "bar"
acute     = comm1 "acute"
mathring  = comm1 "mathring"
check     = comm1 "check"
dot       = comm1 "dot"
vec       = comm1 "vec"
breve     = comm1 "breve"
tilde     = comm1 "tilde"
ddot      = comm1 "ddot"
widehat   = comm1 "widehat"
widetilde = comm1 "widetilde"

-- Greek Alphabet

alpha = comm0 "alpha"
beta = comm0 "beta"
gamma = comm0 "gamma"
gamma_ = comm0 "Gamma"
delta = comm0 "delta"
delta_ = comm0 "Delta"
epsilon = comm0 "epsilon"
varepsilon = comm0 "varepsilon"
zeta = comm0 "zeta"
eta = comm0 "eta"
theta = comm0 "theta"
vartheta = comm0 "vartheta"
theta_ = comm0 "Theta"
iota = comm0 "iota"
kappa = comm0 "kappa"
lambda = comm0 "lambda"
lambda_ = comm0 "Lambda"
mu = comm0 "mu"
nu = comm0 "nu"
xi = comm0 "xi"
xi_ = comm0 "Xi"
pi = comm0 "pi"
varpi = comm0 "varpi"
pi_ = comm0 "Pi"
rho = comm0 "rho"
varrho = comm0 "varrho"
sigma = comm0 "sigma"
varsigma = comm0 "varsigma"
sigma_ = comm0 "Sigma"
tau = comm0 "tau"
upsilon = comm0 "upsilon"
upsilon_ = comm0 "Upsilon"
phi = comm0 "phi"
varphi = comm0 "varphi"
phi_ = comm0 "Phi"
chi = comm0 "chi"
psi = comm0 "psi"
psi_ = comm0 "Psi"
omega = comm0 "omega"
omega_ = comm0 "Omega"

-- Some mathematical functions

-- Symbols

dagger :: Monad m => LaTeX m
dagger = comm0 "dag"

ddagger :: Monad m => LaTeX m
ddagger = comm0 "ddag"

-- | \"For all\" symbol.
forall :: Monad m => LaTeX m
forall = comm0 "forall"

-- Others

binom :: Monad m => MathTerm m -> MathTerm m -> MathTerm m
binom = comm5 "binom"

-- | Environment for a proof.
proof :: Monad m => LaTeX m -> LaTeX m
proof = env "proof"