{-# 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), 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)

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 :: (UID -> f UID) -> Section -> f Section
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 => Lens' c UID
uid
-- | 'Section's are equal if 'UID's are equal.
instance Eq Section where a :: Section
a == :: Section -> Section -> Bool
== b :: 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 => Lens' c 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 => Lens' c 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 _ _ lb :: Reference
lb)  = IRefProg -> String -> LblType
RP (String -> IRefProg
prepend "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 _ _ lb :: Reference
lb) = IRefProg -> String -> LblType
RP (String -> IRefProg
prepend "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 t :: Title
t a :: Title
a toC :: ShowTableOfContents
toC sc :: [Section]
sc) =
  case ShowTableOfContents
toC of
    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 1 [Section]
sc
    _   -> Title -> Title -> ShowTableOfContents -> [Section] -> Document
Document Title
t Title
a ShowTableOfContents
toC [Section]
sc
checkToC (Notebook t :: Title
t a :: Title
a sc :: [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 x :: 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 x :: Reference
x y :: 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 x :: RawContent
x lb :: 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
title intro :: [Contents]
intro secs :: [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 _ _ _ sec :: [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 _ _ sec :: [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 _ sc :: [SecCons]
sc _) = 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 sec :: Section
sec) = Section -> [Section]
getSec Section
sec
getSecCons (Con _)   = []

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

-- | 'Figure' smart constructor that allows for customized max widths.
figWithWidth :: Lbl -> Filepath -> MaxWidthPercent -> RawContent
figWithWidth :: Title -> String -> MaxWidthPercent -> RawContent
figWithWidth = Title -> String -> MaxWidthPercent -> RawContent
Figure

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

-- 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 rs :: String
rs = UID -> LblType -> ShortName -> Reference
Reference (String -> UID
mkUid String
rs) (IRefProg -> String -> LblType
RP (String -> IRefProg
prepend "Tab") ("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 rs :: String
rs = UID -> LblType -> ShortName -> Reference
Reference (String -> UID
mkUid String
rs) (IRefProg -> String -> LblType
RP (String -> IRefProg
prepend "Fig") ("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 r :: String
r s :: 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]
++ "Label") (IRefProg -> String -> LblType
RP (String -> IRefProg
prepend "Sec") ("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 rs :: String
rs = UID -> LblType -> ShortName -> Reference
Reference (String -> UID
mkUid String
rs) (IRefProg -> String -> LblType
RP (String -> IRefProg
prepend "Eqn") ("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 u :: String
u r :: 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' rs :: UID
rs = UID -> LblType -> ShortName -> Reference
Reference UID
rs (IRefProg -> String -> LblType
RP (String -> IRefProg
prepend "Tab") ("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' rs :: UID
rs = UID -> LblType -> ShortName -> Reference
Reference UID
rs (IRefProg -> String -> LblType
RP (String -> IRefProg
prepend "Fig") ("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' r :: UID
r s :: Title
s = UID -> LblType -> ShortName -> Reference
Reference (UID
r UID -> String -> UID
+++. "Label") (IRefProg -> String -> LblType
RP (String -> IRefProg
prepend "Sec") ("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' rs :: UID
rs = UID -> LblType -> ShortName -> Reference
Reference UID
rs (IRefProg -> String -> LblType
RP (String -> IRefProg
prepend "Eqn") ("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' u :: UID
u r :: String
r = UID -> LblType -> ShortName -> Reference
Reference UID
u (String -> LblType
URI String
r)