{-# Language TemplateHaskell #-}
-- | Document Description Language.
module Language.Drasil.Document.Sections (
  section, fig, figNoCap, figWithWidth, figNoCapWithWidth, Section(..),
  SecCons(..) , llcc, llccFig, llccTab, llccEqn, llccFig', llccTab', llccEqn',
  ulcc, Document(..), mkParagraph, mkFig, mkRawLC, ShowTableOfContents(..),
  checkToC, makeTabRef, makeFigRef, makeSecRef, makeEqnRef, makeURI,
  makeTabRef', makeFigRef', makeSecRef', makeEqnRef', makeURI'
) where

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

import Drasil.Database (UID, HasUID(..), (+++.), mkUid, nsUid, HasChunkRefs(..))
import Utils.Drasil (repUnd)
import qualified Data.Set as Set

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.Document.Reference (Reference(Reference))
import Language.Drasil.Sentence (Sentence(..))

-- * Section Types

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

-- | 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

-- | 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

instance HasChunkRefs Section where
  chunkRefs :: Section -> Set UID
chunkRefs Section
sec = [Set UID] -> Set UID
forall (f :: * -> *) a. (Foldable f, Ord a) => f (Set a) -> Set a
Set.unions
    [ Title -> Set UID
forall a. HasChunkRefs a => a -> Set UID
chunkRefs (Section -> Title
tle Section
sec)
    , Reference -> Set UID
forall a. HasChunkRefs a => a -> Set UID
chunkRefs (Section
sec Section -> Getting Reference Section Reference -> Reference
forall s a. s -> Getting a s a -> a
^. Getting Reference Section Reference
Lens' Section Reference
lab)
    ]
  {-# INLINABLE chunkRefs #-}
-- | '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.
-- Now builds a Reference using the provided UID instead of extracting it from the Reference.
llcc :: UID -> LblType -> ShortName -> RawContent -> LabelledContent
llcc :: UID -> LblType -> ShortName -> RawContent -> LabelledContent
llcc UID
u LblType
lbl ShortName
sn = UID -> Reference -> RawContent -> LabelledContent
LblC UID
u (UID -> LblType -> ShortName -> Reference
Reference UID
u LblType
lbl ShortName
sn)

-- | Helper for creating labelled content with a figure reference.
llccFig :: String -> RawContent -> LabelledContent
llccFig :: String -> RawContent -> LabelledContent
llccFig String
rs = UID -> LblType -> ShortName -> RawContent -> LabelledContent
llcc (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))

-- | Helper for creating labelled content with a table reference.
llccTab :: String -> RawContent -> LabelledContent
llccTab :: String -> RawContent -> LabelledContent
llccTab String
rs = UID -> LblType -> ShortName -> RawContent -> LabelledContent
llcc (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))

-- | Helper for creating labelled content with an equation reference.
llccEqn :: String -> RawContent -> LabelledContent
llccEqn :: String -> RawContent -> LabelledContent
llccEqn String
rs = UID -> LblType -> ShortName -> RawContent -> LabelledContent
llcc (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))

-- | Helper for creating labelled content with a UID-based figure reference.
llccFig' :: UID -> RawContent -> LabelledContent
llccFig' :: UID -> RawContent -> LabelledContent
llccFig' UID
rs = UID -> LblType -> ShortName -> RawContent -> LabelledContent
llcc (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))

-- | Helper for creating labelled content with a UID-based table reference.
llccTab' :: UID -> RawContent -> LabelledContent
llccTab' :: UID -> RawContent -> LabelledContent
llccTab' UID
rs = UID -> LblType -> ShortName -> RawContent -> LabelledContent
llcc (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))

-- | Helper for creating labelled content with a UID-based equation reference.
llccEqn' :: UID -> RawContent -> LabelledContent
llccEqn' :: UID -> RawContent -> LabelledContent
llccEqn' UID
rs = UID -> LblType -> ShortName -> RawContent -> LabelledContent
llcc (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))

-- | 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'.
-- Takes a Reference to extract UID, LblType, and ShortName for the labelled content.
mkFig :: Reference -> RawContent -> Contents
mkFig :: Reference -> RawContent -> Contents
mkFig Reference
r RawContent
rc = LabelledContent -> Contents
LlC (LabelledContent -> Contents) -> LabelledContent -> Contents
forall a b. (a -> b) -> a -> b
$ UID -> LblType -> ShortName -> RawContent -> LabelledContent
llcc (Reference
r Reference -> Getting UID Reference UID -> UID
forall s a. s -> Getting a s a -> a
^. Getting UID Reference UID
forall c. HasUID c => Getter c UID
Getter Reference UID
uid) (Reference -> LblType
forall b. HasRefAddress b => b -> LblType
getRefAdd Reference
r) (Reference -> ShortName
forall s. HasShortName s => s -> ShortName
shortname Reference
r) RawContent
rc

--Fixme: use mkRawLc or llcc?
-- | Smart constructor similar to 'llcc', but takes in 'RawContent' first.
-- Takes a Reference to extract UID, LblType, and ShortName for the labelled content.
mkRawLC :: RawContent -> Reference -> LabelledContent
mkRawLC :: RawContent -> Reference -> LabelledContent
mkRawLC RawContent
rc Reference
r = UID -> LblType -> ShortName -> RawContent -> LabelledContent
llcc (Reference
r Reference -> Getting UID Reference UID -> UID
forall s a. s -> Getting a s a -> a
^. Getting UID Reference UID
forall c. HasUID c => Getter c UID
Getter Reference UID
uid) (Reference -> LblType
forall b. HasRefAddress b => b -> LblType
getRefAdd Reference
r) (Reference -> ShortName
forall s. HasShortName s => s -> ShortName
shortname Reference
r) RawContent
rc

---------------------------------------------------------------------------
-- * 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)

-- | '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)