{-# Language TemplateHaskell #-}
-- | Document Description Language.
module Language.Drasil.Document where

import Language.Drasil.ShortName (HasShortName(..), ShortName, shortname')
import Language.Drasil.Document.Core (UnlabelledContent(UnlblC),
  LabelledContent(LblC), HasCaption(..), RawContent(Figure, Paragraph),
  Contents(..), Lbl, Filepath, Author, Title, MaxWidthPercent )
import Language.Drasil.Label.Type (getAdd, prepend, LblType(..),
  Referable(..), HasRefAddress(..) )
import Language.Drasil.Misc (repUnd)
import Language.Drasil.Reference (Reference(Reference))
import Language.Drasil.Sentence (Sentence(..))
import Language.Drasil.UID (UID, HasUID(..), (+++.), mkUid, nsUid)

import Control.Lens ((^.), makeLenses, view)

-- * Section Types

-- | Section Contents are split into subsections or contents, where contents
-- are standard layout objects (see 'Contents').
data SecCons = Sub Section
             | Con Contents

data Partition = Sections
                | Part
                | Chapter

-- | Sections have a title ('Sentence'), a list of contents ('SecCons')
-- and a shortname ('Reference').
data Section = Section
             { Section -> Title
tle  :: Title
             , Section -> [SecCons]
cons :: [SecCons]
             , Section -> Reference
_lab :: Reference
             }
makeLenses ''Section

{-
data Section = Section
             { depth  :: Depth
             , header :: SecHeader 
             , cons   :: Content
             }

data SecHeader = SecHeader Title Reference
data Content   = Content   Contents
-}
-- | Finds the 'UID' of a 'Section'.
instance HasUID        Section where uid :: Getter Section UID
uid = (Reference -> f Reference) -> Section -> f Section
Lens' Section Reference
lab ((Reference -> f Reference) -> Section -> f Section)
-> ((UID -> f UID) -> Reference -> f Reference)
-> (UID -> f UID)
-> Section
-> f Section
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (UID -> f UID) -> Reference -> f Reference
forall c. HasUID c => Getter c UID
Getter Reference UID
uid
-- | 'Section's are equal if 'UID's are equal.
instance Eq Section where Section
a == :: Section -> Section -> Bool
== Section
b = (Section
a Section -> Getting UID Section UID -> UID
forall s a. s -> Getting a s a -> a
^. Getting UID Section UID
forall c. HasUID c => Getter c UID
Getter Section UID
uid) UID -> UID -> Bool
forall a. Eq a => a -> a -> Bool
== (Section
b Section -> Getting UID Section UID -> UID
forall s a. s -> Getting a s a -> a
^. Getting UID Section UID
forall c. HasUID c => Getter c UID
Getter Section UID
uid)
-- | Finds the short name of a 'Section'.
instance HasShortName  Section where shortname :: Section -> ShortName
shortname = Reference -> ShortName
forall s. HasShortName s => s -> ShortName
shortname (Reference -> ShortName)
-> (Section -> Reference) -> Section -> ShortName
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Getting Reference Section Reference -> Section -> Reference
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting Reference Section Reference
Lens' Section Reference
lab
-- | Finds the reference information of a 'Section'.
instance Referable Section where
  refAdd :: Section -> String
refAdd     = LblType -> String
getAdd (LblType -> String) -> (Section -> LblType) -> Section -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Reference -> LblType
forall b. HasRefAddress b => b -> LblType
getRefAdd (Reference -> LblType)
-> (Section -> Reference) -> Section -> LblType
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Getting Reference Section Reference -> Section -> Reference
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting Reference Section Reference
Lens' Section Reference
lab
  renderRef :: Section -> LblType
renderRef (Section Title
_ [SecCons]
_ Reference
lb)  = IRefProg -> String -> LblType
RP (String -> IRefProg
prepend String
"Sec") (LblType -> String
getAdd (LblType -> String) -> LblType -> String
forall a b. (a -> b) -> a -> b
$ Reference -> LblType
forall b. HasRefAddress b => b -> LblType
getRefAdd Reference
lb)
-- | Finds the reference address of a 'Section'.
instance HasRefAddress Section where getRefAdd :: Section -> LblType
getRefAdd (Section Title
_ [SecCons]
_ Reference
lb) = IRefProg -> String -> LblType
RP (String -> IRefProg
prepend String
"Sec") (LblType -> String
getAdd (LblType -> String) -> LblType -> String
forall a b. (a -> b) -> a -> b
$ Reference -> LblType
forall b. HasRefAddress b => b -> LblType
getRefAdd Reference
lb)

-- | A Document has a Title ('Sentence'), Author(s) ('Sentence'), and 'Section's
-- which hold the contents of the document.
data Document = Document Title Author ShowTableOfContents [Section]
              | Notebook Title Author [Section]

-- Temporarily data type for 'notebook' document, might be extended or use 'Document' instead
--data Notebook = Notebook Title Author [Section]

-- | Determines whether or not the table of contents appears on the generated artifacts.
data ShowTableOfContents = ToC | NoToC

-- Medium hack for now. This function is unable to tell if the section
-- is for a table of contents, as that doesn't appear until docLang.
-- This function is needed by the TeX printer, as TeX carries its own form of creating
-- a table of contents. However, the printer package is compiled before the docLang one.
-- | Manually removes the first section of a document (table of contents section).
-- temp fix for Notebook (see if we need this in notebook later)
checkToC :: Document -> Document
checkToC :: Document -> Document
checkToC (Document Title
t Title
a ShowTableOfContents
toC [Section]
sc) =
  case ShowTableOfContents
toC of
    ShowTableOfContents
ToC -> Title -> Title -> ShowTableOfContents -> [Section] -> Document
Document Title
t Title
a ShowTableOfContents
toC ([Section] -> Document) -> [Section] -> Document
forall a b. (a -> b) -> a -> b
$ Int -> [Section] -> [Section]
forall a. Int -> [a] -> [a]
drop Int
1 [Section]
sc
    ShowTableOfContents
_   -> Title -> Title -> ShowTableOfContents -> [Section] -> Document
Document Title
t Title
a ShowTableOfContents
toC [Section]
sc
checkToC (Notebook Title
t Title
a [Section]
sc) = Title -> Title -> [Section] -> Document
Notebook Title
t Title
a [Section]
sc

-- * Content Constructors

-- | Smart constructor for labelled content chunks.
llcc :: Reference -> RawContent -> LabelledContent
llcc :: Reference -> RawContent -> LabelledContent
llcc = Reference -> RawContent -> LabelledContent
LblC

-- | Smart constructor for unlabelled content chunks (no 'Reference').
ulcc :: RawContent -> UnlabelledContent
ulcc :: RawContent -> UnlabelledContent
ulcc = RawContent -> UnlabelledContent
UnlblC

---------------------------------------------------------------------------
-- | Smart constructor that wraps 'UnlabelledContent' into 'Contents'.
mkParagraph :: Sentence -> Contents
mkParagraph :: Title -> Contents
mkParagraph Title
x = UnlabelledContent -> Contents
UlC (UnlabelledContent -> Contents) -> UnlabelledContent -> Contents
forall a b. (a -> b) -> a -> b
$ RawContent -> UnlabelledContent
ulcc (RawContent -> UnlabelledContent)
-> RawContent -> UnlabelledContent
forall a b. (a -> b) -> a -> b
$ Title -> RawContent
Paragraph Title
x

-- | Smart constructor that wraps 'LabelledContent' into 'Contents'.
mkFig :: Reference -> RawContent -> Contents
mkFig :: Reference -> RawContent -> Contents
mkFig Reference
x RawContent
y = LabelledContent -> Contents
LlC (LabelledContent -> Contents) -> LabelledContent -> Contents
forall a b. (a -> b) -> a -> b
$ Reference -> RawContent -> LabelledContent
llcc Reference
x RawContent
y

--Fixme: use mkRawLc or llcc?
-- | Smart constructor similar to 'llcc', but takes in 'RawContent' first.
mkRawLC :: RawContent -> Reference -> LabelledContent
mkRawLC :: RawContent -> Reference -> LabelledContent
mkRawLC RawContent
x Reference
lb = Reference -> RawContent -> LabelledContent
llcc Reference
lb RawContent
x

---------------------------------------------------------------------------
-- * Section Constructors

-- smart constructors and combinators for making instances of the above
-- data types. Over time, the types should no longer be exported, and
-- only these used.

-- | Smart constructor for creating 'Section's with a title ('Sentence'), introductory contents
-- (ie. paragraphs, tables, etc.), a list of subsections, and a shortname ('Reference').
section :: Sentence -> [Contents] -> [Section] -> Reference -> Section
section :: Title -> [Contents] -> [Section] -> Reference -> Section
section Title
title [Contents]
intro [Section]
secs = Title -> [SecCons] -> Reference -> Section
Section Title
title ((Contents -> SecCons) -> [Contents] -> [SecCons]
forall a b. (a -> b) -> [a] -> [b]
map Contents -> SecCons
Con [Contents]
intro [SecCons] -> [SecCons] -> [SecCons]
forall a. [a] -> [a] -> [a]
++ (Section -> SecCons) -> [Section] -> [SecCons]
forall a b. (a -> b) -> [a] -> [b]
map Section -> SecCons
Sub [Section]
secs)

-- | Smart constructor for retrieving the contents ('Section's) from a 'Document'.
extractSection :: Document -> [Section]
extractSection :: Document -> [Section]
extractSection (Document Title
_ Title
_ ShowTableOfContents
_ [Section]
sec) = (Section -> [Section]) -> [Section] -> [Section]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap Section -> [Section]
getSec [Section]
sec
extractSection (Notebook Title
_ Title
_ [Section]
sec)   = (Section -> [Section]) -> [Section] -> [Section]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap Section -> [Section]
getSec [Section]
sec

-- | Smart constructor for retrieving the subsections ('Section's) within a 'Section'.
getSec :: Section -> [Section]
getSec :: Section -> [Section]
getSec t :: Section
t@(Section Title
_ [SecCons]
sc Reference
_) = Section
t Section -> [Section] -> [Section]
forall a. a -> [a] -> [a]
: (SecCons -> [Section]) -> [SecCons] -> [Section]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap SecCons -> [Section]
getSecCons [SecCons]
sc

-- | Helper to retrieve subsections ('Section's) from section contents ('SecCons').
getSecCons :: SecCons -> [Section]
getSecCons :: SecCons -> [Section]
getSecCons (Sub Section
sec) = Section -> [Section]
getSec Section
sec
getSecCons (Con Contents
_)   = []

-- | 'Figure' smart constructor with a 'Lbl' and a 'Filepath'. Assumes 100% of page width as max width. Defaults to 'WithCaption'.
fig :: Lbl -> Filepath -> RawContent
fig :: Title -> String -> RawContent
fig Title
l String
f = Title -> String -> MaxWidthPercent -> HasCaption -> RawContent
Figure Title
l String
f MaxWidthPercent
100 HasCaption
WithCaption

-- | 'Figure' smart constructor without a caption.
figNoCap :: Lbl -> Filepath -> RawContent
figNoCap :: Title -> String -> RawContent
figNoCap Title
l String
f = Title -> String -> MaxWidthPercent -> HasCaption -> RawContent
Figure Title
l String
f MaxWidthPercent
100 HasCaption
NoCaption

-- | 'Figure' smart constructor that allows for customized max widths. Defaults to 'WithCaption'.
figWithWidth :: Lbl -> Filepath -> MaxWidthPercent -> RawContent
figWithWidth :: Title -> String -> MaxWidthPercent -> RawContent
figWithWidth Title
l String
f MaxWidthPercent
wp = Title -> String -> MaxWidthPercent -> HasCaption -> RawContent
Figure Title
l String
f MaxWidthPercent
wp HasCaption
WithCaption

-- | 'Figure' smart constructor with customized max widths and no caption.
figNoCapWithWidth :: Lbl -> Filepath -> MaxWidthPercent -> RawContent
figNoCapWithWidth :: Title -> String -> MaxWidthPercent -> RawContent
figNoCapWithWidth Title
l String
f MaxWidthPercent
wp = Title -> String -> MaxWidthPercent -> HasCaption -> RawContent
Figure Title
l String
f MaxWidthPercent
wp HasCaption
NoCaption

---------------------------------------------------------------------------
-- * Reference Constructors

docNs :: UID -> UID
docNs :: UID -> UID
docNs = String -> UID -> UID
nsUid String
"doc"

docUid :: String -> UID
docUid :: String -> UID
docUid = UID -> UID
docNs (UID -> UID) -> (String -> UID) -> String -> UID
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> UID
mkUid

-- FIXME: horrible hacks.
-- FIXME: May need UID checker function here.
-- These should eventually either disappear, or at least move out to docLang
-- | Create a reference for a table. Takes in the name of a table (which will also be used for its shortname).
makeTabRef :: String -> Reference
makeTabRef :: String -> Reference
makeTabRef String
rs = UID -> LblType -> ShortName -> Reference
Reference (String -> UID
docUid String
rs) (IRefProg -> String -> LblType
RP (String -> IRefProg
prepend String
"Tab") (String
"Table:" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String -> String
repUnd String
rs)) (Title -> ShortName
shortname' (String -> Title
S String
rs))

-- | Create a reference for a figure. Takes in the name of a figure (which will also be used for its shortname).
makeFigRef :: String -> Reference
makeFigRef :: String -> Reference
makeFigRef String
rs = UID -> LblType -> ShortName -> Reference
Reference (String -> UID
docUid String
rs) (IRefProg -> String -> LblType
RP (String -> IRefProg
prepend String
"Fig") (String
"Figure:" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String -> String
repUnd String
rs)) (Title -> ShortName
shortname' (String -> Title
S String
rs))

-- | Create a reference for a section. Takes in the name of a section and a shortname for the section.
makeSecRef :: String -> Sentence -> Reference
makeSecRef :: String -> Title -> Reference
makeSecRef String
r Title
s = UID -> LblType -> ShortName -> Reference
Reference (String -> UID
mkUid (String -> UID) -> String -> UID
forall a b. (a -> b) -> a -> b
$ String
r String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"Label") (IRefProg -> String -> LblType
RP (String -> IRefProg
prepend String
"Sec") (String
"Sec:" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String -> String
repUnd String
r))
  (Title -> ShortName
shortname' Title
s)

-- | Create a reference for a equation. Takes in the name of the equation (which will also be used for its shortname).
makeEqnRef :: String -> Reference
makeEqnRef :: String -> Reference
makeEqnRef String
rs = UID -> LblType -> ShortName -> Reference
Reference (String -> UID
docUid String
rs) (IRefProg -> String -> LblType
RP (String -> IRefProg
prepend String
"Eqn") (String
"Equation:" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String -> String
repUnd String
rs)) (Title -> ShortName
shortname' (String -> Title
S String
rs))

-- | Create a reference for a 'URI'. Takes in a 'UID' (as a 'String'), a reference address, and a shortname.
makeURI :: String -> String -> ShortName -> Reference
makeURI :: String -> String -> ShortName -> Reference
makeURI String
u String
r = UID -> LblType -> ShortName -> Reference
Reference (String -> UID
mkUid String
u) (String -> LblType
URI String
r)

-- | Variants of 'makeTabRef' that takes a 'UID' instead of a 'String'.
makeTabRef' :: UID -> Reference
makeTabRef' :: UID -> Reference
makeTabRef' UID
rs = UID -> LblType -> ShortName -> Reference
Reference (UID -> UID
docNs UID
rs) (IRefProg -> String -> LblType
RP (String -> IRefProg
prepend String
"Tab") (String
"Table:" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String -> String
repUnd (UID -> String
forall a. Show a => a -> String
show UID
rs))) (Title -> ShortName
shortname' (String -> Title
S (String -> Title) -> String -> Title
forall a b. (a -> b) -> a -> b
$ UID -> String
forall a. Show a => a -> String
show UID
rs))

-- | Variants of 'makeFigRef' that takes a 'UID' instead of a 'String'.
makeFigRef' :: UID -> Reference
makeFigRef' :: UID -> Reference
makeFigRef' UID
rs = UID -> LblType -> ShortName -> Reference
Reference (UID -> UID
docNs UID
rs) (IRefProg -> String -> LblType
RP (String -> IRefProg
prepend String
"Fig") (String
"Figure:" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String -> String
repUnd (UID -> String
forall a. Show a => a -> String
show UID
rs))) (Title -> ShortName
shortname' (String -> Title
S (String -> Title) -> String -> Title
forall a b. (a -> b) -> a -> b
$ UID -> String
forall a. Show a => a -> String
show UID
rs))

-- | Variants of 'makeSecRef' that takes a 'UID' instead of a 'String'.
makeSecRef' :: UID -> Sentence -> Reference
makeSecRef' :: UID -> Title -> Reference
makeSecRef' UID
r Title
s = UID -> LblType -> ShortName -> Reference
Reference (UID
r UID -> String -> UID
+++. String
"Label") (IRefProg -> String -> LblType
RP (String -> IRefProg
prepend String
"Sec") (String
"Sec:" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String -> String
repUnd (UID -> String
forall a. Show a => a -> String
show UID
r)))
  (Title -> ShortName
shortname' Title
s)

-- | Variants of 'makeEqnRef' that takes a 'UID' instead of a 'String'.
makeEqnRef' :: UID -> Reference
makeEqnRef' :: UID -> Reference
makeEqnRef' UID
rs = UID -> LblType -> ShortName -> Reference
Reference (UID -> UID
docNs UID
rs) (IRefProg -> String -> LblType
RP (String -> IRefProg
prepend String
"Eqn") (String
"Equation:" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String -> String
repUnd (UID -> String
forall a. Show a => a -> String
show UID
rs))) (Title -> ShortName
shortname' (String -> Title
S (String -> Title) -> String -> Title
forall a b. (a -> b) -> a -> b
$ UID -> String
forall a. Show a => a -> String
show UID
rs))

-- | Variants of 'makeURI' that takes a 'UID' instead of a 'String'.
makeURI' :: UID -> String -> ShortName -> Reference
makeURI' :: UID -> String -> ShortName -> Reference
makeURI' UID
u String
r = UID -> LblType -> ShortName -> Reference
Reference UID
u (String -> LblType
URI String
r)