-- | Defines helper functions for creating Markdown files.
module Language.Drasil.Markdown.Helpers where

import Prelude hiding ((<>), lookup)
import System.FilePath (takeFileName)
import Text.PrettyPrint (Doc, text, empty, (<>), (<+>), hcat,
  brackets, parens, braces)
import Data.Map (lookup)
import Language.Drasil.Printing.Helpers (ast, ($^$), vsep)
import Language.Drasil.Printing.LayoutObj (RefMap)
import Language.Drasil.HTML.Helpers (wrap', wrapGen', Variation(Id, Align),
  wrapInside, tagR)

-- | Angled brackets
ang :: Doc -> Doc
ang :: Doc -> Doc
ang Doc
t = String -> Doc
text String
"<" Doc -> Doc -> Doc
<> Doc
t Doc -> Doc -> Doc
<> String -> Doc
text String
">"

-- | Bold text
bold :: Doc -> Doc
bold :: Doc -> Doc
bold Doc
t = Doc
ast Doc -> Doc -> Doc
<> Doc
ast Doc -> Doc -> Doc
<> Doc
t Doc -> Doc -> Doc
<> Doc
ast Doc -> Doc -> Doc
<> Doc
ast

-- | Italicized text
em :: Doc -> Doc
em :: Doc -> Doc
em Doc
t = Doc
ast Doc -> Doc -> Doc
<> Doc
t Doc -> Doc -> Doc
<> Doc
ast

li, ul :: Doc -> Doc
-- | List tag wrapper
li :: Doc -> Doc
li = String -> [String] -> Doc -> Doc
wrap' String
"li" []
-- | Unordered list tag wrapper.
ul :: Doc -> Doc
ul = String -> [String] -> Doc -> Doc
wrap' String
"ul" []

-- | Helper for setting up section div
divTag :: Doc -> Doc
divTag :: Doc -> Doc
divTag Doc
l = ([Doc] -> Doc)
-> Variation -> String -> Doc -> [String] -> Doc -> Doc
wrapGen' [Doc] -> Doc
hcat Variation
Id String
"div" Doc
l [String
""] Doc
empty

-- | Helper for setting up centered div tags
centeredDiv :: Doc -> Doc
centeredDiv :: Doc -> Doc
centeredDiv = ([Doc] -> Doc)
-> Variation -> String -> Doc -> [String] -> Doc -> Doc
wrapGen' [Doc] -> Doc
vsep Variation
Align String
"div" (String -> Doc
text String
"center") [String
""]

-- | Helper for setting up centered div tags with an Id
centeredDivId :: Doc -> Doc -> Doc
centeredDivId :: Doc -> Doc -> Doc
centeredDivId Doc
l Doc
con = [Doc] -> Doc
vsep [String -> [(String, Doc)] -> Doc
wrapInside String
"div" [(String, Doc)]
atrs, Doc
con, String -> Doc
tagR String
"div"]
  where
    atrs :: [(String, Doc)]
atrs = [(Variation -> String
forall a. Show a => a -> String
show Variation
Id, Doc
l), (Variation -> String
forall a. Show a => a -> String
show Variation
Align, String -> Doc
text String
"center")]

-- | Helper for setting up links to references
reflink :: RefMap -> String -> Doc -> Doc
reflink :: RefMap -> String -> Doc -> Doc
reflink RefMap
rm String
ref Doc
txt = Doc -> Doc
brackets Doc
txt Doc -> Doc -> Doc
<> Doc -> Doc
parens Doc
rp
  where
    fn :: Doc
fn = Doc -> (String -> Doc) -> Maybe String -> Doc
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Doc
empty String -> Doc
fp (String -> RefMap -> Maybe String
forall k a. Ord k => k -> Map k a -> Maybe a
lookup String
ref RefMap
rm)
    fp :: String -> Doc
fp String
s = String -> Doc
text (String -> Doc) -> String -> Doc
forall a b. (a -> b) -> a -> b
$ String
"./" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
s String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
".md"
    rp :: Doc
rp = Doc
fn Doc -> Doc -> Doc
<> String -> Doc
text (String
"#" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
ref)

-- | Helper for setting up links to references with additional information.
reflinkInfo :: RefMap -> String -> Doc -> Doc -> Doc
reflinkInfo :: RefMap -> String -> Doc -> Doc -> Doc
reflinkInfo RefMap
rm String
rf Doc
txt Doc
info = RefMap -> String -> Doc -> Doc
reflink RefMap
rm String
rf Doc
txt Doc -> Doc -> Doc
<+> Doc
info

-- | Helper for setting up links to external URIs
reflinkURI :: Doc -> Doc -> Doc
reflinkURI :: Doc -> Doc -> Doc
reflinkURI Doc
ref Doc
txt = if Doc
ref Doc -> Doc -> Bool
forall a. Eq a => a -> a -> Bool
== Doc
txt then Doc -> Doc
ang Doc
ref
  else Doc -> Doc
brackets Doc
txt Doc -> Doc -> Doc
<> Doc -> Doc
parens Doc
ref

-- | Helper for setting up figures
image :: Doc -> Maybe Doc -> Doc
image :: Doc -> Maybe Doc -> Doc
image Doc
f Maybe Doc
Nothing = String -> Doc
text String
"!" Doc -> Doc -> Doc
<> Doc -> Doc -> Doc
reflinkURI (String -> Doc
text (String -> Doc) -> String -> Doc
forall a b. (a -> b) -> a -> b
$ String
"./assets/" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String -> String
takeFileName (Doc -> String
forall a. Show a => a -> String
show Doc
f)) (String -> Doc
text String
"")
image Doc
f (Just Doc
c) = String -> Doc
text String
"!" Doc -> Doc -> Doc
<> Doc -> Doc -> Doc
reflinkURI (String -> Doc
text (String -> Doc) -> String -> Doc
forall a b. (a -> b) -> a -> b
$ String
"./assets/" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String -> String
takeFileName (Doc -> String
forall a. Show a => a -> String
show Doc
f)) Doc
c Doc -> Doc -> Doc
$^$ Doc -> Doc
bold (String -> Doc
text String
"Figure: " Doc -> Doc -> Doc
<> Doc
c)

-- | Helper for setting up captions
caption :: Doc -> Doc
caption :: Doc -> Doc
caption = ([Doc] -> Doc)
-> Variation -> String -> Doc -> [String] -> Doc -> Doc
wrapGen' [Doc] -> Doc
hcat Variation
Align String
"p" (String -> Doc
text String
"center") [String
""]

-- | Helper for setting up headings with an id attribute.
-- id attribute will only work for mdBook.
heading ::  Doc -> Doc -> Doc
heading :: Doc -> Doc -> Doc
heading Doc
t Doc
l = Doc
t Doc -> Doc -> Doc
<+> Doc -> Doc
braces (String -> Doc
text String
"#" Doc -> Doc -> Doc
<> Doc
l)

-- | Helper for setting up heading weights in mdBook.
h :: Int -> Doc
h :: Int -> Doc
h Int
n
  | Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
1     = String -> Doc
forall a. HasCallStack => String -> a
error String
"Illegal header (header weight must be > 0)."
  | Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
7     = String -> Doc
forall a. HasCallStack => String -> a
error String
"Illegal header (header weight must be < 8)"
  | Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
4     = Int -> Doc
h' Int
1
  | Bool
otherwise = Int -> Doc
h' Int
n

-- | Helper for setting up heading weights in normal Markdown.
h' :: Int -> Doc
h' :: Int -> Doc
h' Int
n
  | Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
1 = String -> Doc
forall a. HasCallStack => String -> a
error String
"Illegal header (header weight must be > 0)."
  | Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
7 = String -> Doc
forall a. HasCallStack => String -> a
error String
"Illegal header (header weight must be < 8)."
  | Bool
otherwise = String -> Doc
text (String -> Doc) -> String -> Doc
forall a b. (a -> b) -> a -> b
$ Int -> Char -> String
forall a. Int -> a -> [a]
replicate Int
n Char
'#'

-- | Helper for getting length of a Doc
docLength :: Doc -> Int
docLength :: Doc -> Int
docLength Doc
d = String -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length (String -> Int) -> String -> Int
forall a b. (a -> b) -> a -> b
$ Doc -> String
forall a. Show a => a -> String
show Doc
d