{-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE OverloadedStrings #-}

-- | module that serves as an edsl to be used to write latex code. only that
--     the code is first transformed into the intermediate structure PreLaTeX.
--     provides all necessary functions and can be extended if needed.
module Language.Ltml.ToLaTeX.PreLaTeXType
    ( PreLaTeX (..)
    {- styling -}
    , text
    , bold
    , italic
    , underline
    , large
    , small
    {- references -}
    , footnote
    , hypertarget
    , hyperlink
    , label
    , footref
    {- commands to structure the text -}
    , medskip
    , hrule
    , hline
    , linebreak
    , newpage
    {- setup and metadata -}
    , setpdftitle
    , usepackage
    , documentclass
    , fancyhead
    , fancyfoot
    , resetfootnote
    {- environments -}
    , enumerate
    , itemize
    , center
    , flushleft
    , flushright
    , minipage
    , document
    {- tabular -}
    , tabular
    , cline
    , cellcolor
    , multirow
    , multicolumn
    , makecell
    {- other -}
    , setindent
    , setlistdepth
    , renewlist
    , setfontArabic
    , enumStyle
    ) where

import qualified Data.Text as T
import Language.Ltml.AST.Label (Label (Label))

data PreLaTeX
    = IText T.Text
    | -- | raw unescaped PreLaTeX
      IRaw T.Text
    | -- | \command
      ICommandS T.Text
    | -- | \command[opts]{args}
      ICommand T.Text [T.Text] [PreLaTeX]
    | -- | \begin{env}[opts] ... \end{env}
      IEnvironment T.Text [T.Text] [PreLaTeX]
    | -- | used for wrapping in braces
      IBraced PreLaTeX
    | -- | concatenation
      ISequence [PreLaTeX]
    | -- | the reason why we introduced this intermediate data type
      MissingRef Label
    deriving (Int -> PreLaTeX -> ShowS
[PreLaTeX] -> ShowS
PreLaTeX -> String
(Int -> PreLaTeX -> ShowS)
-> (PreLaTeX -> String) -> ([PreLaTeX] -> ShowS) -> Show PreLaTeX
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> PreLaTeX -> ShowS
showsPrec :: Int -> PreLaTeX -> ShowS
$cshow :: PreLaTeX -> String
show :: PreLaTeX -> String
$cshowList :: [PreLaTeX] -> ShowS
showList :: [PreLaTeX] -> ShowS
Show, PreLaTeX -> PreLaTeX -> Bool
(PreLaTeX -> PreLaTeX -> Bool)
-> (PreLaTeX -> PreLaTeX -> Bool) -> Eq PreLaTeX
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: PreLaTeX -> PreLaTeX -> Bool
== :: PreLaTeX -> PreLaTeX -> Bool
$c/= :: PreLaTeX -> PreLaTeX -> Bool
/= :: PreLaTeX -> PreLaTeX -> Bool
Eq)

-- | We want to be able to connect PreLaTeX structures and avoid deeply rooted sequences.
--   Here we are using a monoid to be able to concat PreLaTeX structures while flattening sequences.
instance Semigroup PreLaTeX where
    PreLaTeX
a <> :: PreLaTeX -> PreLaTeX -> PreLaTeX
<> PreLaTeX
b = [PreLaTeX] -> PreLaTeX
sequence' [PreLaTeX
a, PreLaTeX
b]
      where
        sequence' :: [PreLaTeX] -> PreLaTeX
        sequence' :: [PreLaTeX] -> PreLaTeX
sequence' [PreLaTeX]
xs = case [PreLaTeX] -> [PreLaTeX]
flatten [PreLaTeX]
xs of
            [PreLaTeX
x] -> PreLaTeX
x
            [PreLaTeX]
ys -> [PreLaTeX] -> PreLaTeX
ISequence [PreLaTeX]
ys

        -- \| Flatten nested Sequences as we build them
        flatten :: [PreLaTeX] -> [PreLaTeX]
        flatten :: [PreLaTeX] -> [PreLaTeX]
flatten = (PreLaTeX -> [PreLaTeX]) -> [PreLaTeX] -> [PreLaTeX]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap PreLaTeX -> [PreLaTeX]
go
          where
            go :: PreLaTeX -> [PreLaTeX]
go (ISequence [PreLaTeX]
ys) = [PreLaTeX] -> [PreLaTeX]
flatten [PreLaTeX]
ys
            go PreLaTeX
x = [PreLaTeX
x]

instance Monoid PreLaTeX where
    mempty :: PreLaTeX
mempty = [PreLaTeX] -> PreLaTeX
ISequence []

-------------------------------------------------------------------------------
{-                                styling                                   -}

text :: T.Text -> PreLaTeX
text :: Text -> PreLaTeX
text = Text -> PreLaTeX
IText

bold :: PreLaTeX -> PreLaTeX
bold :: PreLaTeX -> PreLaTeX
bold = Text -> [Text] -> [PreLaTeX] -> PreLaTeX
ICommand Text
"textbf" [] ([PreLaTeX] -> PreLaTeX)
-> (PreLaTeX -> [PreLaTeX]) -> PreLaTeX -> PreLaTeX
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (PreLaTeX -> [PreLaTeX] -> [PreLaTeX]
forall a. a -> [a] -> [a]
: [])

italic :: PreLaTeX -> PreLaTeX
italic :: PreLaTeX -> PreLaTeX
italic = Text -> [Text] -> [PreLaTeX] -> PreLaTeX
ICommand Text
"emph" [] ([PreLaTeX] -> PreLaTeX)
-> (PreLaTeX -> [PreLaTeX]) -> PreLaTeX -> PreLaTeX
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (PreLaTeX -> [PreLaTeX] -> [PreLaTeX]
forall a. a -> [a] -> [a]
: [])

underline :: PreLaTeX -> PreLaTeX
underline :: PreLaTeX -> PreLaTeX
underline = Text -> [Text] -> [PreLaTeX] -> PreLaTeX
ICommand Text
"underline" [] ([PreLaTeX] -> PreLaTeX)
-> (PreLaTeX -> [PreLaTeX]) -> PreLaTeX -> PreLaTeX
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (PreLaTeX -> [PreLaTeX] -> [PreLaTeX]
forall a. a -> [a] -> [a]
: [])

large :: PreLaTeX -> PreLaTeX
large :: PreLaTeX -> PreLaTeX
large PreLaTeX
content = PreLaTeX -> PreLaTeX
IBraced (PreLaTeX -> PreLaTeX) -> PreLaTeX -> PreLaTeX
forall a b. (a -> b) -> a -> b
$ Text -> [Text] -> [PreLaTeX] -> PreLaTeX
ICommand Text
"large" [] [PreLaTeX
content]

small :: PreLaTeX -> PreLaTeX
small :: PreLaTeX -> PreLaTeX
small PreLaTeX
content = PreLaTeX -> PreLaTeX
IBraced (PreLaTeX -> PreLaTeX) -> PreLaTeX -> PreLaTeX
forall a b. (a -> b) -> a -> b
$ Text -> [Text] -> [PreLaTeX] -> PreLaTeX
ICommand Text
"small" [] [PreLaTeX
content]

-------------------------------------------------------------------------------
{-                             referencing                                -}

footnote :: PreLaTeX -> PreLaTeX
footnote :: PreLaTeX -> PreLaTeX
footnote = Text -> [Text] -> [PreLaTeX] -> PreLaTeX
ICommand Text
"footnote" [] ([PreLaTeX] -> PreLaTeX)
-> (PreLaTeX -> [PreLaTeX]) -> PreLaTeX -> PreLaTeX
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (PreLaTeX -> [PreLaTeX] -> [PreLaTeX]
forall a. a -> [a] -> [a]
: [])

hypertarget :: Label -> PreLaTeX -> PreLaTeX
hypertarget :: Label -> PreLaTeX -> PreLaTeX
hypertarget (Label Text
l) PreLaTeX
latex = Text -> [Text] -> [PreLaTeX] -> PreLaTeX
ICommand Text
"hypertarget" [] [Text -> PreLaTeX
IRaw Text
l, PreLaTeX
latex]

hyperlink :: Label -> PreLaTeX -> PreLaTeX
hyperlink :: Label -> PreLaTeX -> PreLaTeX
hyperlink (Label Text
l) PreLaTeX
latex = Text -> [Text] -> [PreLaTeX] -> PreLaTeX
ICommand Text
"hyperlink" [] [Text -> PreLaTeX
IRaw Text
l, PreLaTeX
latex]

label :: T.Text -> PreLaTeX
label :: Text -> PreLaTeX
label Text
l = Text -> [Text] -> [PreLaTeX] -> PreLaTeX
ICommand Text
"label" [] [Text -> PreLaTeX
IRaw Text
l]

footref :: T.Text -> PreLaTeX
footref :: Text -> PreLaTeX
footref Text
r = Text -> [Text] -> [PreLaTeX] -> PreLaTeX
ICommand Text
"footref" [] [Text -> PreLaTeX
IRaw Text
r]

-------------------------------------------------------------------------------
{-                             setup and metadata                             -}

usepackage :: [T.Text] -> T.Text -> PreLaTeX
usepackage :: [Text] -> Text -> PreLaTeX
usepackage [Text]
opts Text
package = Text -> [Text] -> [PreLaTeX] -> PreLaTeX
ICommand Text
"usepackage" [Text]
opts [Text -> PreLaTeX
IText Text
package]

documentclass :: [T.Text] -> T.Text -> PreLaTeX
documentclass :: [Text] -> Text -> PreLaTeX
documentclass [Text]
opts Text
name = Text -> [Text] -> [PreLaTeX] -> PreLaTeX
ICommand Text
"documentclass" [Text]
opts [Text -> PreLaTeX
IText Text
name]

fancyhead :: [T.Text] -> PreLaTeX -> PreLaTeX
fancyhead :: [Text] -> PreLaTeX -> PreLaTeX
fancyhead [Text]
opts PreLaTeX
content = Text -> [Text] -> [PreLaTeX] -> PreLaTeX
ICommand Text
"fancyhead" [Text]
opts [PreLaTeX
content]

fancyfoot :: [T.Text] -> PreLaTeX -> PreLaTeX
fancyfoot :: [Text] -> PreLaTeX -> PreLaTeX
fancyfoot [Text]
opts PreLaTeX
content = Text -> [Text] -> [PreLaTeX] -> PreLaTeX
ICommand Text
"fancyfoot" [Text]
opts [PreLaTeX
content]

resetfootnote :: PreLaTeX
resetfootnote :: PreLaTeX
resetfootnote = Text -> [Text] -> [PreLaTeX] -> PreLaTeX
ICommand Text
"setcounter" [] [Text -> PreLaTeX
IText Text
"footnote", Text -> PreLaTeX
IText Text
"0"]

setpdftitle :: T.Text -> PreLaTeX
setpdftitle :: Text -> PreLaTeX
setpdftitle Text
title = Text -> [Text] -> [PreLaTeX] -> PreLaTeX
ICommand Text
"hypersetup" [] [Text -> PreLaTeX
IText (Text -> PreLaTeX) -> Text -> PreLaTeX
forall a b. (a -> b) -> a -> b
$ Text
"pdftitle={" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
title Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"}"]

-------------------------------------------------------------------------------
{-                              text structure                              -}

linebreak :: PreLaTeX
linebreak :: PreLaTeX
linebreak = Text -> PreLaTeX
IRaw Text
"\\\\"

newpage :: PreLaTeX
newpage :: PreLaTeX
newpage = Text -> PreLaTeX
ICommandS Text
"newpage"

medskip :: PreLaTeX
medskip :: PreLaTeX
medskip = Text -> PreLaTeX
IText Text
"\n" PreLaTeX -> PreLaTeX -> PreLaTeX
forall a. Semigroup a => a -> a -> a
<> Text -> PreLaTeX
ICommandS Text
"medskip" PreLaTeX -> PreLaTeX -> PreLaTeX
forall a. Semigroup a => a -> a -> a
<> Text -> PreLaTeX
IRaw Text
"\n"

hrule :: PreLaTeX
hrule :: PreLaTeX
hrule = Text -> PreLaTeX
ICommandS Text
"hrule"

hline :: PreLaTeX
hline :: PreLaTeX
hline = Text -> PreLaTeX
ICommandS Text
"hline"

-------------------------------------------------------------------------------
{-                              environments                                 -}

enumerate :: [T.Text] -> [PreLaTeX] -> PreLaTeX
enumerate :: [Text] -> [PreLaTeX] -> PreLaTeX
enumerate [Text]
opts [PreLaTeX]
items = Text -> [Text] -> [PreLaTeX] -> PreLaTeX
IEnvironment Text
"enumerate" [Text]
opts ((PreLaTeX -> PreLaTeX) -> [PreLaTeX] -> [PreLaTeX]
forall a b. (a -> b) -> [a] -> [b]
map (\PreLaTeX
i -> Text -> [Text] -> [PreLaTeX] -> PreLaTeX
ICommand Text
"item" [] [PreLaTeX
i]) [PreLaTeX]
items)

itemize :: [PreLaTeX] -> PreLaTeX
itemize :: [PreLaTeX] -> PreLaTeX
itemize [PreLaTeX]
items = Text -> [Text] -> [PreLaTeX] -> PreLaTeX
IEnvironment Text
"itemize" [] ((PreLaTeX -> PreLaTeX) -> [PreLaTeX] -> [PreLaTeX]
forall a b. (a -> b) -> [a] -> [b]
map (\PreLaTeX
i -> Text -> [Text] -> [PreLaTeX] -> PreLaTeX
ICommand Text
"item" [] [PreLaTeX
i]) [PreLaTeX]
items)

center :: [PreLaTeX] -> PreLaTeX
center :: [PreLaTeX] -> PreLaTeX
center = Text -> [Text] -> [PreLaTeX] -> PreLaTeX
IEnvironment Text
"center" []

flushleft :: [PreLaTeX] -> PreLaTeX
flushleft :: [PreLaTeX] -> PreLaTeX
flushleft = Text -> [Text] -> [PreLaTeX] -> PreLaTeX
IEnvironment Text
"flushleft" []

flushright :: [PreLaTeX] -> PreLaTeX
flushright :: [PreLaTeX] -> PreLaTeX
flushright = Text -> [Text] -> [PreLaTeX] -> PreLaTeX
IEnvironment Text
"flushright" []

minipage :: [T.Text] -> [PreLaTeX] -> PreLaTeX
minipage :: [Text] -> [PreLaTeX] -> PreLaTeX
minipage = Text -> [Text] -> [PreLaTeX] -> PreLaTeX
IEnvironment Text
"minipage"

document :: PreLaTeX -> PreLaTeX
document :: PreLaTeX -> PreLaTeX
document PreLaTeX
content = Text -> [Text] -> [PreLaTeX] -> PreLaTeX
IEnvironment Text
"document" [] [PreLaTeX
content]

tabular :: T.Text -> PreLaTeX -> PreLaTeX
tabular :: Text -> PreLaTeX -> PreLaTeX
tabular Text
cols PreLaTeX
content =
    Text -> [Text] -> [PreLaTeX] -> PreLaTeX
IEnvironment
        Text
"longtable"
        []
        [PreLaTeX -> PreLaTeX
IBraced (PreLaTeX -> PreLaTeX) -> PreLaTeX -> PreLaTeX
forall a b. (a -> b) -> a -> b
$ Text -> PreLaTeX
IRaw Text
cols, PreLaTeX
content]

------------------- tabular commands ------------------------

cline :: Int -> Int -> PreLaTeX
cline :: Int -> Int -> PreLaTeX
cline Int
start Int
end = Text -> [Text] -> [PreLaTeX] -> PreLaTeX
ICommand Text
"cline" [] [Text -> PreLaTeX
IRaw (String -> Text
T.pack (Int -> String
forall a. Show a => a -> String
show Int
start) Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"-" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> String -> Text
T.pack (Int -> String
forall a. Show a => a -> String
show Int
end))]

cellcolor :: T.Text -> PreLaTeX
cellcolor :: Text -> PreLaTeX
cellcolor Text
color = Text -> [Text] -> [PreLaTeX] -> PreLaTeX
ICommand Text
"cellcolor" [] [Text -> PreLaTeX
IText Text
color]

multirow :: Int -> PreLaTeX -> PreLaTeX
multirow :: Int -> PreLaTeX -> PreLaTeX
multirow Int
n PreLaTeX
content = Text -> [Text] -> [PreLaTeX] -> PreLaTeX
ICommand Text
"multirow" [] [Text -> PreLaTeX
IText (String -> Text
T.pack (Int -> String
forall a. Show a => a -> String
show Int
n)), Text -> PreLaTeX
IRaw Text
"=", PreLaTeX
content]

multicolumn :: Int -> T.Text -> PreLaTeX -> PreLaTeX
multicolumn :: Int -> Text -> PreLaTeX -> PreLaTeX
multicolumn Int
n Text
cols PreLaTeX
content = Text -> [Text] -> [PreLaTeX] -> PreLaTeX
ICommand Text
"multicolumn" [] [Text -> PreLaTeX
IText (String -> Text
T.pack (Int -> String
forall a. Show a => a -> String
show Int
n)), Text -> PreLaTeX
IText Text
cols, PreLaTeX
content]

makecell :: PreLaTeX -> PreLaTeX
makecell :: PreLaTeX -> PreLaTeX
makecell PreLaTeX
content = Text -> [Text] -> [PreLaTeX] -> PreLaTeX
ICommand Text
"makecell" [Text
"l"] [PreLaTeX
content]

-------------------------------------------------------------------------------
{-                              other                                        -}

setindent :: PreLaTeX
setindent :: PreLaTeX
setindent = Text -> PreLaTeX
IRaw Text
"\\setlength{\\parindent}{0pt}"

setlistdepth :: PreLaTeX
setlistdepth :: PreLaTeX
setlistdepth = Text -> PreLaTeX
IRaw Text
"\\setlistdepth{9}"

renewlist :: PreLaTeX
renewlist :: PreLaTeX
renewlist = Text -> PreLaTeX
IRaw Text
"\\renewlist{enumerate}{enumerate}{9}"

setfontArabic :: PreLaTeX
setfontArabic :: PreLaTeX
setfontArabic =
    [PreLaTeX] -> PreLaTeX
ISequence
        [ [Text] -> Text -> PreLaTeX
usepackage [] Text
"helvet"
        , Text -> PreLaTeX
IRaw Text
"\\renewcommand{\\familydefault}{\\sfdefault}"
        ]

enumStyle :: PreLaTeX
enumStyle :: PreLaTeX
enumStyle =
    Text -> PreLaTeX
IRaw Text
"\\setlist[enumerate,1]{label=\\arabic*., left=0pt}"
        PreLaTeX -> PreLaTeX -> PreLaTeX
forall a. Semigroup a => a -> a -> a
<> Text -> PreLaTeX
IRaw Text
"\\setlist[enumerate,2]{label=\\alph*., left=0.5em}"
        PreLaTeX -> PreLaTeX -> PreLaTeX
forall a. Semigroup a => a -> a -> a
<> Text -> PreLaTeX
IRaw Text
"\\setlist[enumerate,3]{label=\\alph*\\alph*., left=1em}"
        PreLaTeX -> PreLaTeX -> PreLaTeX
forall a. Semigroup a => a -> a -> a
<> Text -> PreLaTeX
IRaw Text
"\\setlist[enumerate,4]{label=-, left=1.5em}"
        PreLaTeX -> PreLaTeX -> PreLaTeX
forall a. Semigroup a => a -> a -> a
<> Text -> PreLaTeX
IRaw Text
"\\setlist{nosep}"