-- | Defines helper functions used in printing LaTeX documents.
module Language.Drasil.TeX.Helpers where

import Text.PrettyPrint (text)
import qualified Text.PrettyPrint as TP

import Language.Drasil (MaxWidthPercent)

import Language.Drasil.Config (numberedSections, hyperSettings)
import qualified Language.Drasil.Printing.Helpers as H
import Language.Drasil.TeX.Monad (PrintLaTeX(PL), D, MathContext(Math), ($+$))
import Data.List (isSuffixOf)

--import Language.Drasil.Config (numberedSections, hyperSettings)
--import Language.Drasil.Document (MaxWidthPercent)

-----------------------------------------------------------------------------
-- * LaTeX Commands
--
-- $latexCmd
--
-- Infrastructre for defining commands, environments, etc.
-- Calls to TP should only occur in this section.

-- | Helper for adding fencing symbols.
br, sq, parens, quote :: D -> D
-- | Curly braces.
br :: D -> D
br D
x = D
lb forall a. Semigroup a => a -> a -> a
<> D
x forall a. Semigroup a => a -> a -> a
<> D
rb
  where
  lb :: D
lb = forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ String -> Doc
text String
"{"
  rb :: D
rb = forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ String -> Doc
text String
"}"
-- | Square brackets.
sq :: D -> D
sq D
x = D
ls forall a. Semigroup a => a -> a -> a
<> D
x forall a. Semigroup a => a -> a -> a
<> D
rs
  where
  ls :: D
ls = forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ String -> Doc
text String
"["
  rs :: D
rs = forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ String -> Doc
text String
"]"
-- | Parenthesis.
parens :: D -> D
parens D
x = D
lp forall a. Semigroup a => a -> a -> a
<> D
x forall a. Semigroup a => a -> a -> a
<> D
rp
  where
  lp :: D
lp = forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ String -> Doc
text String
"("
  rp :: D
rp = forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ String -> Doc
text String
")"
-- | Quotes.
quote :: D -> D
quote D
x = D
lq forall a. Semigroup a => a -> a -> a
<> D
x forall a. Semigroup a => a -> a -> a
<> D
rq
  where
  lq :: D
lq = forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ String -> Doc
text String
"``"
  rq :: D
rq = forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ String -> Doc
text String
"''"

-- | 0-argument command.
command0 :: String -> D
command0 :: String -> D
command0 String
s = forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ Doc
H.bslash Doc -> Doc -> Doc
TP.<> String -> Doc
text String
s

-- | Make 1-argument command.
command :: String -> String -> D
command :: String -> String -> D
command String
s String
c = forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ (Doc
H.bslash Doc -> Doc -> Doc
TP.<> String -> Doc
text String
s) Doc -> Doc -> Doc
TP.<> String -> Doc
H.br String
c

-- | Similar to 'command', but uses 'br' for braces.
commandD :: String -> D -> D
commandD :: String -> D -> D
commandD String
s D
c = forall (f :: * -> *) a. Applicative f => a -> f a
pure (Doc
H.bslash Doc -> Doc -> Doc
TP.<> String -> Doc
text String
s) forall a. Semigroup a => a -> a -> a
<> D -> D
br D
c

-- | 1-argument command, with optional argument.
command1o :: String -> Maybe String -> String -> D
command1o :: String -> Maybe String -> String -> D
command1o String
s = forall b a. b -> (a -> b) -> Maybe a -> b
maybe (String -> String -> D
command String
s) (String -> String -> String -> D
command1p String
s)

-- | Similar to 'command1o', but uses 'sq' and 'br' for brackets.
command1oD :: String -> Maybe D -> D -> D
command1oD :: String -> Maybe D -> D -> D
command1oD String
s = forall b a. b -> (a -> b) -> Maybe a -> b
maybe (String -> D -> D
commandD String
s) (String -> D -> D -> D
command1pD String
s)

-- | 1-argument command with parameter in square brackets.
command1p :: String -> String -> String -> D
command1p :: String -> String -> String -> D
command1p String
s String
p String
c = forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ (Doc
H.bslash Doc -> Doc -> Doc
TP.<> String -> Doc
text String
s) Doc -> Doc -> Doc
TP.<> String -> Doc
H.sq String
p Doc -> Doc -> Doc
TP.<> String -> Doc
H.br String
c

-- | Similar to 'command1p', but uses 'sq' and 'br' for brackets.
command1pD :: String -> D -> D -> D
command1pD :: String -> D -> D -> D
command1pD String
s D
p D
c = forall (f :: * -> *) a. Applicative f => a -> f a
pure (Doc
H.bslash Doc -> Doc -> Doc
TP.<> String -> Doc
text String
s) forall a. Semigroup a => a -> a -> a
<> D -> D
sq D
p forall a. Semigroup a => a -> a -> a
<> D -> D
br D
c

-- | Make LaTeX symbol.
texSym :: String -> D
texSym :: String -> D
texSym String
s = forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ Doc
H.bslash Doc -> Doc -> Doc
TP.<> String -> Doc
text String
s

-- | 2-argument command.
command2 :: String -> String -> String -> D
command2 :: String -> String -> String -> D
command2 String
s String
a0 String
a1 = forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ (Doc
H.bslash Doc -> Doc -> Doc
TP.<> String -> Doc
text String
s) Doc -> Doc -> Doc
TP.<> String -> Doc
H.br String
a0 Doc -> Doc -> Doc
TP.<> String -> Doc
H.br String
a1

-- | Similar to 'command2', but uses 'br' for brackets.
command2D :: String -> D -> D -> D
command2D :: String -> D -> D -> D
command2D String
s D
a0 D
a1 = forall (f :: * -> *) a. Applicative f => a -> f a
pure (Doc
H.bslash Doc -> Doc -> Doc
TP.<> String -> Doc
text String
s) forall a. Semigroup a => a -> a -> a
<> D -> D
br D
a0 forall a. Semigroup a => a -> a -> a
<> D -> D
br D
a1

-- | 3-argument command.
command3 :: String -> String -> String -> String -> D
command3 :: String -> String -> String -> String -> D
command3 String
s String
a0 String
a1 String
a2 = forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ (Doc
H.bslash Doc -> Doc -> Doc
TP.<> String -> Doc
text String
s) Doc -> Doc -> Doc
TP.<> String -> Doc
H.br String
a0 Doc -> Doc -> Doc
TP.<> String -> Doc
H.br String
a1 Doc -> Doc -> Doc
TP.<> String -> Doc
H.br String
a2

-- | Encapsulate environments.
mkEnv :: String -> D -> D
mkEnv :: String -> D -> D
mkEnv String
nm D
d =
  forall (f :: * -> *) a. Applicative f => a -> f a
pure (String -> Doc
text (String
"\\begin" forall a. [a] -> [a] -> [a]
++ String -> String
H.brace String
nm)) D -> D -> D
$+$ 
  D
d D -> D -> D
$+$
  forall (f :: * -> *) a. Applicative f => a -> f a
pure (String -> Doc
text (String
"\\end" forall a. [a] -> [a] -> [a]
++ String -> String
H.brace String
nm))

-- | Encapsulate environments with argument with braces.
mkEnvArgBr :: String -> String -> D -> D
mkEnvArgBr :: String -> String -> D -> D
mkEnvArgBr String
nm String
args D
d =
  forall (f :: * -> *) a. Applicative f => a -> f a
pure (String -> Doc
text (String
"\\begin" forall a. [a] -> [a] -> [a]
++ String -> String
H.brace String
nm forall a. [a] -> [a] -> [a]
++ String -> String
H.brace String
args)) D -> D -> D
$+$ 
  D
d D -> D -> D
$+$
  forall (f :: * -> *) a. Applicative f => a -> f a
pure (String -> Doc
text (String
"\\end" forall a. [a] -> [a] -> [a]
++ String -> String
H.brace String
nm))

-- | Encapsulate environments with argument with brackets.
mkEnvArgSq :: String -> String -> D -> D
mkEnvArgSq :: String -> String -> D -> D
mkEnvArgSq String
nm String
args D
d =
  forall (f :: * -> *) a. Applicative f => a -> f a
pure (String -> Doc
text (String
"\\begin" forall a. [a] -> [a] -> [a]
++ String -> String
H.brace String
nm forall a. [a] -> [a] -> [a]
++ String -> String
H.sqbrac String
args)) D -> D -> D
$+$ 
  D
d D -> D -> D
$+$
  forall (f :: * -> *) a. Applicative f => a -> f a
pure (String -> Doc
text (String
"\\end" forall a. [a] -> [a] -> [a]
++ String -> String
H.brace String
nm))

-- | Makes minipage environment.
mkMinipage :: D -> D
mkMinipage :: D -> D
mkMinipage D
d = String -> D
command0 String
"medskip" D -> D -> D
$+$
  String -> D
command0 String
"noindent" D -> D -> D
$+$ String -> String -> D -> D
mkEnvArgBr String
"minipage" String
"\\textwidth" D
d D -> D -> D
$+$ forall (f :: * -> *) a. Applicative f => a -> f a
pure (String -> Doc
text String
"")

-- | For defining (LaTeX) macros.
comm :: String -> String -> Maybe String -> D
comm :: String -> String -> Maybe String -> D
comm String
b1 String
b2 Maybe String
s1 = String -> D
command0 String
"newcommand" forall a. Semigroup a => a -> a -> a
<> forall (f :: * -> *) a. Applicative f => a -> f a
pure (String -> Doc
H.br (String
"\\" forall a. [a] -> [a] -> [a]
++ String
b1) Doc -> Doc -> Doc
TP.<> 
  forall b a. b -> (a -> b) -> Maybe a -> b
maybe Doc
TP.empty String -> Doc
H.sq Maybe String
s1 Doc -> Doc -> Doc
TP.<> String -> Doc
H.br String
b2)

-- this one is special enough, let this sub-optimal implementation stand
-- | Renews given command.
renewcomm :: String -> String -> D
renewcomm :: String -> String -> D
renewcomm String
b1 = String -> String -> String -> D
command2 String
"renewcommand" (String
"\\" forall a. [a] -> [a] -> [a]
++ String
b1)

-- | Useful to have an empty case.
empty :: D
empty :: D
empty = forall (f :: * -> *) a. Applicative f => a -> f a
pure Doc
TP.empty

-- | For sections.
genSec :: Int -> D
genSec :: Int -> D
genSec Int
d
  | Int
d forall a. Ord a => a -> a -> Bool
< Int
0 = forall a. HasCallStack => String -> a
error String
"Cannot have section with negative depth"
  | Int
d forall a. Ord a => a -> a -> Bool
> Int
3 = forall a. HasCallStack => String -> a
error String
"Section depth must be from 0-2"
  | Int
d forall a. Eq a => a -> a -> Bool
== Int
3 = forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ Doc
H.bslash Doc -> Doc -> Doc
TP.<> String -> Doc
text String
"paragraph"
  | Bool
otherwise = forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ 
     Doc
H.bslash Doc -> Doc -> Doc
TP.<> String -> Doc
text (forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat forall a b. (a -> b) -> a -> b
$ forall a. Int -> a -> [a]
replicate Int
d String
"sub") Doc -> Doc -> Doc
TP.<> String -> Doc
text String
"section" 
      Doc -> Doc -> Doc
TP.<> (if Bool -> Bool
not Bool
numberedSections then String -> Doc
text String
"*" else Doc
TP.empty) 

-- | For references.
ref, sref, hyperref, externalref, snref :: String -> D -> D
sref :: String -> D -> D
sref            = if Bool
numberedSections then String -> D -> D
ref else String -> D -> D
hyperref
ref :: String -> D -> D
ref         String
t D
x = forall (f :: * -> *) a. Applicative f => a -> f a
pure (String -> Doc
text forall a b. (a -> b) -> a -> b
$ String
t forall a. [a] -> [a] -> [a]
++ String
"~") forall a. Semigroup a => a -> a -> a
<> String -> D -> D
commandD String
"ref" D
x
hyperref :: String -> D -> D
hyperref    String
t D
x = String -> D -> D -> D
command1pD String
"hyperref" D
x (forall (f :: * -> *) a. Applicative f => a -> f a
pure (String -> Doc
text (String
t forall a. [a] -> [a] -> [a]
++ String
"~")) forall a. Semigroup a => a -> a -> a
<> D
x)
externalref :: String -> D -> D
externalref String
t D
x = String -> D
command0 String
"hyperref" forall a. Semigroup a => a -> a -> a
<> D -> D
br (forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ String -> Doc
text String
t) forall a. Semigroup a => a -> a -> a
<> D -> D
br D
empty forall a. Semigroup a => a -> a -> a
<>
  D -> D
br D
empty forall a. Semigroup a => a -> a -> a
<> D -> D
br D
x
snref :: String -> D -> D
snref       String
r   = String -> D -> D -> D
command1pD String
"hyperref" (forall (f :: * -> *) a. Applicative f => a -> f a
pure (String -> Doc
text String
r))

-- | For references.
href :: String -> String -> D
href :: String -> String -> D
href = String -> String -> String -> D
command2 String
"href"

-- | For citations.
cite :: String -> Maybe D -> D
cite :: String -> Maybe D -> D
cite String
c Maybe D
n = String -> Maybe D -> D -> D
command1oD String
"cite" Maybe D
n (forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ String -> Doc
text String
c) --may need to be changed to allow for shortnames?

-----------------------------------------------------------------------------
-- * Define Common LaTeX Commands

count, mathbb, usepackage :: String -> D
-- | Newcounter command.
count :: String -> D
count      = String -> String -> D
command String
"newcounter"
-- changed to command "newcounter" from command "count" (I assume this was
-- what was intended?)
-- | Mathbb command.
mathbb :: String -> D
mathbb     = String -> String -> D
command String
"mathbb"
-- | Usepackage command.
usepackage :: String -> D
usepackage = String -> String -> D
command String
"usepackage"

-- | Include graphics with a given max width percentage.
includegraphics :: MaxWidthPercent -> String -> D
includegraphics :: MaxWidthPercent -> String -> D
includegraphics MaxWidthPercent
n String
fp 
  | String
".svg" forall a. Eq a => [a] -> [a] -> Bool
`isSuffixOf` String
fp = String -> String -> String -> D
command1p String
"includesvg" (String
"width=" forall a. [a] -> [a] -> [a]
++ forall {a}. (Eq a, Show a, Fractional a) => a -> String
per MaxWidthPercent
n forall a. [a] -> [a] -> [a]
++ String
"\\textwidth, inkscapelatex = false") String
fpNoSvg -- in order to use inkscape to render svgs, there can't be a file type appended
  | Bool
otherwise = String -> String -> String -> D
command1p String
"includegraphics" (String
"width=" forall a. [a] -> [a] -> [a]
++ forall {a}. (Eq a, Show a, Fractional a) => a -> String
per MaxWidthPercent
n forall a. [a] -> [a] -> [a]
++ String
"\\textwidth") String
fp -- still need a case for normal images
  where
    fpNoSvg :: String
fpNoSvg = forall a. Int -> [a] -> [a]
take (forall (t :: * -> *) a. Foldable t => t a -> Int
length String
fp forall a. Num a => a -> a -> a
- Int
4) String
fp
    per :: a -> String
per a
100 = String
""
    per a
wp  = forall a. Show a => a -> String
show (a
wp forall a. Fractional a => a -> a -> a
/ a
100)

-- | Preamble for a LaTeX document.
author, caption, item, label, title, bold :: D -> D
author :: D -> D
author  = String -> D -> D
commandD String
"author"
caption :: D -> D
caption = String -> D -> D
commandD String
"caption"
item :: D -> D
item    = String -> D -> D
commandD String
"item"
label :: D -> D
label   = String -> D -> D
commandD String
"label"
title :: D -> D
title   = String -> D -> D
commandD String
"title"
bold :: D -> D
bold    = String -> D -> D
commandD String
"textbf"

-- | Command for "item".
item' :: D -> D -> D
item' :: D -> D -> D
item' = String -> D -> D -> D
command1pD String
"item"

-- | Formatting options for a LaTeX document.
maketitle, maketoc, newpage, centering :: D
maketitle :: D
maketitle = String -> D
command0 String
"maketitle"
maketoc :: D
maketoc   = String -> D
command0 String
"tableofcontents"
newpage :: D
newpage   = String -> D
command0 String
"newpage"
centering :: D
centering = String -> D
command0 String
"centering"

-- | Common commands and formatting options for a LaTeX document.
code, itemize, enumerate, description, figure, center, document, 
  equation, symbDescription :: D -> D
code :: D -> D
code        = String -> D -> D
mkEnv String
"lstlisting"
itemize :: D -> D
itemize     = String -> D -> D
mkEnv String
"itemize"
enumerate :: D -> D
enumerate   = String -> D -> D
mkEnv String
"enumerate"
description :: D -> D
description = String -> D -> D
mkEnv String
"description"
figure :: D -> D
figure      = String -> D -> D
mkEnv String
"figure"
center :: D -> D
center      = String -> D -> D
mkEnv String
"center"
document :: D -> D
document    = String -> D -> D
mkEnv String
"document"
equation :: D -> D
equation    = String -> D -> D
mkEnv String
"displaymath" --displays math
symbDescription :: D -> D
symbDescription = String -> D -> D
mkEnv String
"symbDescription"

-- | Command for the document class.
docclass :: String -> String -> D
docclass :: String -> String -> D
docclass = String -> String -> String -> D
command1p String
"documentclass"

-- | General section function.
sec :: Int -> D -> D
sec :: Int -> D -> D
sec Int
d D
b1 = Int -> D
genSec Int
d forall a. Semigroup a => a -> a -> a
<> D -> D
br D
b1

subscript, superscript :: D -> D -> D
-- | Makes second argument a subscript of the first argument.
subscript :: D -> D -> D
subscript   D
a D
b = D
a forall a. Semigroup a => a -> a -> a
<> forall (f :: * -> *) a. Applicative f => a -> f a
pure Doc
H.unders forall a. Semigroup a => a -> a -> a
<> D -> D
br D
b
-- | Makes second argument a superscript of the first argument.
superscript :: D -> D -> D
superscript D
a D
b = D
a forall a. Semigroup a => a -> a -> a
<> forall (f :: * -> *) a. Applicative f => a -> f a
pure Doc
H.hat    forall a. Semigroup a => a -> a -> a
<> D -> D
br D
b

-- grave, acute :: Char -> D
-- grave c = (pure $ text "\\`{") <> pure (TP.char c) <> (pure $ text "}")
-- acute c = (pure $ text "\\'{") <> pure (TP.char c) <> (pure $ text "}")

-- Macro / Command def'n --
--TeX--
-- | Macro/Command definitions.
bullet, counter, ddefnum, ddref, colAw, colBw, arrayS, modcounter, modnum :: D

counter :: D
counter    = String -> D
count String
"datadefnum"
modcounter :: D
modcounter = String -> D
count String
"modnum"

bullet :: D
bullet  = String -> String -> Maybe String -> D
comm String
"blt"             String
"- "                forall a. Maybe a
Nothing
ddefnum :: D
ddefnum = String -> String -> Maybe String -> D
comm String
"ddthedatadefnum" String
"MG\\thedatadefnum" forall a. Maybe a
Nothing
ddref :: D
ddref   = String -> String -> Maybe String -> D
comm String
"ddref"           String
"MG\\ref{#1}"       (forall a. a -> Maybe a
Just String
"1")
colAw :: D
colAw   = String -> String -> Maybe String -> D
comm String
"colAwidth"       String
"0.2\\textwidth"    forall a. Maybe a
Nothing
colBw :: D
colBw   = String -> String -> Maybe String -> D
comm String
"colBwidth"       String
"0.73\\textwidth"   forall a. Maybe a
Nothing
modnum :: D
modnum  = String -> String -> Maybe String -> D
comm String
"mthemodnum"      String
"M\\themodnum"      forall a. Maybe a
Nothing

arrayS :: D
arrayS  = String -> String -> D
renewcomm String
"arraystretch" String
"1.2"

-- | Add newline.
newline :: D -> D
newline :: D -> D
newline D
s = D
s D -> D -> D
$+$ forall (f :: * -> *) a. Applicative f => a -> f a
pure (String -> Doc
text String
"")

-- | Create a fraction.
fraction :: D -> D -> D
fraction :: D -> D -> D
fraction = String -> D -> D -> D
command2D String
"frac"

-- | Configuration settings.
hyperConfig :: D
hyperConfig :: D
hyperConfig = String -> String -> D
command String
"hypersetup" String
hyperSettings

-- | Uses luatex85 tex packages.
useTikz :: D
useTikz :: D
useTikz = String -> D
usepackage String
"luatex85" D -> D -> D
$+$ String -> D
command0 String
"def" forall a. Semigroup a => a -> a -> a
<>
  String -> String -> D
command String
"pgfsysdriver" String
"pgfsys-pdftex.def" D -> D -> D
$+$
  -- the above is a workaround..  temporary until TeX packages have been fixed
  String -> D
usepackage String
"tikz" D -> D -> D
$+$ String -> String -> D
command String
"usetikzlibrary" String
"arrows.meta" D -> D -> D
$+$
  String -> String -> D
command String
"usetikzlibrary" String
"graphs" D -> D -> D
$+$ String -> String -> D
command String
"usetikzlibrary" String
"graphdrawing" D -> D -> D
$+$
  String -> String -> D
command String
"usegdlibrary" String
"layered"
  
-- * Helpers

-----------------------------------------------------------------------------
-- This 'belongs' in Monad, but it would make Monad depend on Helpers, which depends
-- on Monad...

-- | toEqn is special; it switches to 'Math', but inserts an equation environment.
toEqn :: D -> D
toEqn :: D -> D
toEqn (PL MathContext -> Doc
g) = D -> D
equation forall a b. (a -> b) -> a -> b
$ forall a. (MathContext -> a) -> PrintLaTeX a
PL (\MathContext
_ -> MathContext -> Doc
g MathContext
Math)

-----------------------------------------------------------------------------
-- | Helper(s) for String-Printing in TeX where it varies from HTML/Plaintext.
paren, sqbrac :: String -> String
-- | Wrap with parenthesis.
paren :: String -> String
paren String
x = String
"\\left(" forall a. [a] -> [a] -> [a]
++ String
x forall a. [a] -> [a] -> [a]
++ String
"\\right)"
-- | Wrap with square brackets.
sqbrac :: String -> String
sqbrac String
x = String
"\\left[" forall a. [a] -> [a] -> [a]
++ String
x forall a. [a] -> [a] -> [a]
++ String
"\\right]"