-- | Defines types and functions to help generate common LaTeX preamble.
module Language.Drasil.TeX.Preamble (genPreamble) where

import Data.List (nub)

import Language.Drasil.Printing.LayoutObj (LayoutObj(..))
import Language.Drasil.TeX.Monad (D, vcat, (%%))
import Language.Drasil.TeX.Helpers (docclass, command, command0, command1o, command2, command3, 
  usepackage)

import Language.Drasil.Config (hyperSettings, fontSize, bibFname)

-- FIXME: this really shouldn't be in code, it should be data!
-- | LaTeX packages.
data Package = AMSMath      -- ^ Improves information structure for mathematical formulas.
             | BookTabs     -- ^ Enhances quality of tables in the document.
             | Caption      -- ^ Customize the captions in floating environments.
             | FullPage     -- ^ Sets margins and page style.
             | Graphics     -- ^ Manipulate graphical elements.
             | HyperRef     -- ^ Handles cross-referencing within the document.
             | Listings     -- ^ Source code printer for LaTeX.
             | LongTable    -- ^ Allow tables to overflow page boundaries.
             | Tikz         -- ^ Create graphical elements.
             | Dot2Tex      -- ^ Create better graphs.
             | AdjustBox    -- ^ Adjustable boxed content.
             | AMSsymb      -- ^ Displays bold math sets (reals, naturals, etc.).
--           | Breqn --line breaks long equations automatically
             | FileContents -- ^ Creates .bib file within .tex file.
             | BibLaTeX     -- ^ Reimplementation of bibliography elements.
             | Tabu         -- ^ Adds auto column width feature for tables.
             | Mathtools    -- ^ Line breaks for long fractions and cases.
             | URL          -- ^ Allows for hyperlinks.
             | FontSpec     -- ^ For utf-8 encoding in lualatex.
             | Unicode      -- ^ For unicode-math in lualatex.
             | EnumItem     -- ^ Contol basic list environments.
             | SVG          -- ^ For rendering svg diagrams.
             deriving Package -> Package -> Bool
(Package -> Package -> Bool)
-> (Package -> Package -> Bool) -> Eq Package
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Package -> Package -> Bool
$c/= :: Package -> Package -> Bool
== :: Package -> Package -> Bool
$c== :: Package -> Package -> Bool
Eq

-- | Adds a 'Package' to the LaTeX document.
addPackage :: Package -> D
addPackage :: Package -> D
addPackage AMSMath   = String -> D
usepackage "amsmath"
addPackage BookTabs  = String -> D
usepackage "booktabs"
addPackage Caption   = String -> D
usepackage "caption"
addPackage FullPage  = String -> D
usepackage "fullpage"
addPackage Graphics  = String -> D
usepackage "graphics"
addPackage HyperRef  = String -> D
usepackage "hyperref" D -> D -> D
%%
                       String -> String -> D
command "hypersetup" String
hyperSettings
addPackage Listings  = String -> D
usepackage "listings"
addPackage LongTable = String -> D
usepackage "longtable"
addPackage Tikz      = String -> D
usepackage "tikz" D -> D -> D
%%
                       String -> String -> D
command "usetikzlibrary" "arrows.meta, shapes"
addPackage Dot2Tex   = String -> D
usepackage "dot2texi"
addPackage AdjustBox = String -> D
usepackage "adjustbox"
addPackage AMSsymb   = String -> D
usepackage "amssymb"
--addPackage Breqn     = usepackage "breqn"
addPackage FileContents = String -> D
usepackage "filecontents"
addPackage BibLaTeX  = String -> Maybe String -> String -> D
command1o "usepackage" (String -> Maybe String
forall a. a -> Maybe a
Just "backend=bibtex") "biblatex"
addPackage Tabu      = String -> D
usepackage "tabu"
addPackage Mathtools = String -> D
usepackage "mathtools"
addPackage URL       = String -> D
usepackage "url"
-- Discussed in issue #1819
-- Because we are using LuaLatex, we use fontspec here instead of fontenc
addPackage FontSpec  = String -> D
usepackage "fontspec"
addPackage Unicode   = String -> D
usepackage "unicode-math"
addPackage EnumItem  = String -> D
usepackage "enumitem"
addPackage SVG       = String -> D
usepackage "svg"

-- | Common LaTeX commands.
data Def = Bibliography
         | TabuLine
         | GreaterThan
         | LessThan
         | SetMathFont
         | SymbDescriptionP1
         | SymbDescriptionP2
         deriving Def -> Def -> Bool
(Def -> Def -> Bool) -> (Def -> Def -> Bool) -> Eq Def
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Def -> Def -> Bool
$c/= :: Def -> Def -> Bool
== :: Def -> Def -> Bool
$c== :: Def -> Def -> Bool
Eq

-- | Define common LaTeX commands.
addDef :: Def -> D
addDef :: Def -> D
addDef Bibliography  = String -> String -> D
command "bibliography" String
bibFname
addDef GreaterThan   = String -> String -> String -> D
command2 "newcommand" "\\gt" "\\ensuremath >"
addDef LessThan      = String -> String -> String -> D
command2 "newcommand" "\\lt" "\\ensuremath <"
addDef TabuLine      = String -> D
command0 "global\\tabulinesep=1mm"
addDef SetMathFont   = String -> String -> D
command "setmathfont" "Latin Modern Math"
addDef SymbDescriptionP1 = String -> String -> String -> String -> D
command3 "newlist" "symbDescription" "description" "1"
addDef SymbDescriptionP2 = String -> Maybe String -> String -> D
command1o "setlist" (String -> Maybe String
forall a. a -> Maybe a
Just "symbDescription") "noitemsep, topsep=0pt, parsep=0pt, partopsep=0pt"

-- | Generates LaTeX document preamble.
genPreamble :: [LayoutObj] -> D
genPreamble :: [LayoutObj] -> D
genPreamble los :: [LayoutObj]
los = let (pkgs :: [Package]
pkgs, defs :: [Def]
defs) = [LayoutObj] -> ([Package], [Def])
parseDoc [LayoutObj]
los
  in String -> String -> D
docclass (Int -> String
forall a. Show a => a -> String
show Int
fontSize String -> String -> String
forall a. [a] -> [a] -> [a]
++ "pt") "article" D -> D -> D
%%
     [D] -> D
vcat ((Package -> D) -> [Package] -> [D]
forall a b. (a -> b) -> [a] -> [b]
map Package -> D
addPackage [Package]
pkgs) D -> D -> D
%% [D] -> D
vcat ((Def -> D) -> [Def] -> [D]
forall a b. (a -> b) -> [a] -> [b]
map Def -> D
addDef [Def]
defs)

-- | Helper to gather all preamble information.
parseDoc :: [LayoutObj] -> ([Package], [Def])
parseDoc :: [LayoutObj] -> ([Package], [Def])
parseDoc los' :: [LayoutObj]
los' = 
  ([Package
FontSpec, Package
FullPage, Package
HyperRef, Package
AMSMath, Package
AMSsymb, Package
Mathtools, Package
Unicode] [Package] -> [Package] -> [Package]
forall a. [a] -> [a] -> [a]
++ 
   [Package] -> [Package]
forall a. Eq a => [a] -> [a]
nub ((([Package], [Def]) -> [Package])
-> [([Package], [Def])] -> [Package]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap ([Package], [Def]) -> [Package]
forall a b. (a, b) -> a
fst [([Package], [Def])]
res)
  , [Def
SetMathFont, Def
GreaterThan, Def
LessThan] [Def] -> [Def] -> [Def]
forall a. [a] -> [a] -> [a]
++ [Def] -> [Def]
forall a. Eq a => [a] -> [a]
nub ((([Package], [Def]) -> [Def]) -> [([Package], [Def])] -> [Def]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap ([Package], [Def]) -> [Def]
forall a b. (a, b) -> b
snd [([Package], [Def])]
res))
  where 
    res :: [([Package], [Def])]
res = (LayoutObj -> ([Package], [Def]))
-> [LayoutObj] -> [([Package], [Def])]
forall a b. (a -> b) -> [a] -> [b]
map LayoutObj -> ([Package], [Def])
parseDoc' [LayoutObj]
los'
    parseDoc' :: LayoutObj -> ([Package], [Def])
    parseDoc' :: LayoutObj -> ([Package], [Def])
parseDoc' Table{} = ([Package
Tabu,Package
LongTable,Package
BookTabs,Package
Caption], [Def
TabuLine])
    parseDoc' (HDiv _ slos :: [LayoutObj]
slos _) = 
      let res1 :: [([Package], [Def])]
res1 = (LayoutObj -> ([Package], [Def]))
-> [LayoutObj] -> [([Package], [Def])]
forall a b. (a -> b) -> [a] -> [b]
map LayoutObj -> ([Package], [Def])
parseDoc' [LayoutObj]
slos in
      let pp :: [Package]
pp = (([Package], [Def]) -> [Package])
-> [([Package], [Def])] -> [Package]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap ([Package], [Def]) -> [Package]
forall a b. (a, b) -> a
fst [([Package], [Def])]
res1 in
      let dd :: [Def]
dd = (([Package], [Def]) -> [Def]) -> [([Package], [Def])] -> [Def]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap ([Package], [Def]) -> [Def]
forall a b. (a, b) -> b
snd [([Package], [Def])]
res1 in
      ([Package]
pp, [Def]
dd)
    parseDoc' (Definition _ ps :: [(String, [LayoutObj])]
ps _) =
      let res1 :: [([Package], [Def])]
res1 = ((String, [LayoutObj]) -> [([Package], [Def])])
-> [(String, [LayoutObj])] -> [([Package], [Def])]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap ((LayoutObj -> ([Package], [Def]))
-> [LayoutObj] -> [([Package], [Def])]
forall a b. (a -> b) -> [a] -> [b]
map LayoutObj -> ([Package], [Def])
parseDoc' ([LayoutObj] -> [([Package], [Def])])
-> ((String, [LayoutObj]) -> [LayoutObj])
-> (String, [LayoutObj])
-> [([Package], [Def])]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String, [LayoutObj]) -> [LayoutObj]
forall a b. (a, b) -> b
snd) [(String, [LayoutObj])]
ps in
      let pp :: [Package]
pp = (([Package], [Def]) -> [Package])
-> [([Package], [Def])] -> [Package]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap ([Package], [Def]) -> [Package]
forall a b. (a, b) -> a
fst [([Package], [Def])]
res1 in
      let dd :: [Def]
dd = (([Package], [Def]) -> [Def]) -> [([Package], [Def])] -> [Def]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap ([Package], [Def]) -> [Def]
forall a b. (a, b) -> b
snd [([Package], [Def])]
res1 in
      (Package
TabuPackage -> [Package] -> [Package]
forall a. a -> [a] -> [a]
:Package
LongTablePackage -> [Package] -> [Package]
forall a. a -> [a] -> [a]
:Package
BookTabsPackage -> [Package] -> [Package]
forall a. a -> [a] -> [a]
:[Package]
pp,Def
SymbDescriptionP1Def -> [Def] -> [Def]
forall a. a -> [a] -> [a]
:Def
SymbDescriptionP2Def -> [Def] -> [Def]
forall a. a -> [a] -> [a]
:Def
TabuLineDef -> [Def] -> [Def]
forall a. a -> [a] -> [a]
:[Def]
dd)
    parseDoc' Figure{}     = ([Package
Graphics,Package
Caption, Package
SVG],[])
    parseDoc' Graph{}      = ([Package
Caption,Package
Tikz,Package
Dot2Tex,Package
AdjustBox],[])
    parseDoc' Bib{}        = ([Package
FileContents,Package
BibLaTeX,Package
URL],[Def
Bibliography])
    parseDoc' Header{}     = ([], [])
    parseDoc' Paragraph{}  = ([], [])
    parseDoc' List{}       = ([Package
EnumItem], [])
    parseDoc' EqnBlock{}   = ([], [])
    parseDoc' Cell{}       = ([], [])