-- | 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, (%%), nest)
import Language.Drasil.TeX.Helpers (docclass, command, command1o, command2, command3,
  usepackage, lbrace, rbrace)
import Language.Drasil.Printing.Helpers (sq)

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.
             | 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.
             | Tabularray   -- ^ Adds auto column width feature for tables.
             | TabularX     -- ^ Adds \arraybackslash
             | 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.
             | Float        -- ^ For enhanced control over placement of figures and tables.
             deriving Package -> Package -> Bool
(Package -> Package -> Bool)
-> (Package -> Package -> Bool) -> Eq Package
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Package -> Package -> Bool
== :: Package -> Package -> Bool
$c/= :: Package -> Package -> Bool
/= :: Package -> Package -> Bool
Eq

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

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

-- | Define common LaTeX commands.
addDef :: Def -> D
addDef :: Def -> D
addDef Def
Bibliography  = String -> String -> D
command String
"bibliography" String
bibFname
addDef Def
GreaterThan   = String -> String -> String -> D
command2 String
"newcommand" String
"\\gt" String
"\\ensuremath >"
addDef Def
LessThan      = String -> String -> String -> D
command2 String
"newcommand" String
"\\lt" String
"\\ensuremath <"
addDef Def
SetMathFont   = String -> String -> D
command String
"setmathfont" String
"Latin Modern Math"
addDef Def
SymbDescriptionP1 = String -> String -> String -> String -> D
command3 String
"newlist" String
"symbDescription" String
"description" String
"1"
addDef Def
SymbDescriptionP2 = String -> Maybe String -> String -> D
command1o String
"setlist" (String -> Maybe String
forall a. a -> Maybe a
Just String
"symbDescription") String
"noitemsep, topsep=0pt, parsep=0pt, partopsep=0pt"
addDef Def
ResizeExpr = [D] -> D
vcat [
    String -> String -> D
command String
"newcommand" String
"\\resizeExpression" D -> D -> D
forall a. Semigroup a => a -> a -> a
<> Doc -> D
forall a. a -> PrintLaTeX a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (String -> Doc
sq String
"1") D -> D -> D
forall a. Semigroup a => a -> a -> a
<> D
lbrace,
    Int -> D -> D
nest Int
2 (D -> D) -> D -> D
forall a b. (a -> b) -> a -> b
$ String -> String -> String -> D
command2 String
"adjustbox" String
"max width=\\linewidth" String
"$#1$",
    D
rbrace
  ]

-- | Generates LaTeX document preamble.
genPreamble :: [LayoutObj] -> D
genPreamble :: [LayoutObj] -> D
genPreamble [LayoutObj]
los = let ([Package]
pkgs, [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]
++ String
"pt") String
"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 [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
Tabularray,Package
TabularX,Package
BookTabs,Package
Caption], [])
    parseDoc' (HDiv Tags
_ [LayoutObj]
slos Label
_) = 
      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 DType
_ [(String, [LayoutObj])]
ps Label
_) =
      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
TabularrayPackage -> [Package] -> [Package]
forall a. a -> [a] -> [a]
:Package
TabularXPackage -> [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]
dd)
    parseDoc' Figure{}     = ([Package
Graphics,Package
Caption, Package
SVG, Package
Float],[])
    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{}   = ([Package
AdjustBox], [Def
ResizeExpr])
    parseDoc' Cell{}       = ([], [])
    parseDoc' CodeBlock{}  = ([], [])