{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE RecordWildCards #-}
-- | Document language for lesson plan notebooks.
module Drasil.LessonPlan.JupyterGenerator (
  JupyterGenOptions(..)
) where

import Control.Lens ((^.))

import Drasil.Database (ChunkDB)
import Drasil.FileHandling
import Language.Drasil hiding (Options)
import Language.Drasil.Document (Section, Document(Notebook), Contents(UlC),
  ulcc, RawContent(Bib), section, makeSecRef)
import Drasil.System (HasSystemMeta(..), ToFiles(..))
import Drasil.Metadata.Documentation (notebook)
import qualified Drasil.Metadata.Documentation as Doc (caseProb, introduction,
  learnObj, review, summary, example, appendix, reference)

import Drasil.LessonPlan.Core (LessonPlan)
import Drasil.LessonPlan.Document (LsnDesc, LsnChapter(..))
import Drasil.LessonPlan.ExtractBib (extractBib)
import Language.Drasil.Printers

-- | Single-file-generating Jupyter notebook rendering options.
data JupyterGenOptions = JupyterGenOptions {
  -- | Describe the organization of the final lesson plan.
  JupyterGenOptions -> LsnDesc
lsnDesc :: LsnDesc,
  -- | A title combinator that mixes 'Notebook' (passed as the first argument)
  -- with the title of the 'LessonPlan'. To be used as the /actual title/ used
  -- in the final generated document.
  JupyterGenOptions -> CI -> CI -> Sentence
titleComb :: CI -> CI -> Sentence,
  -- | The name of the file to be outputted (no extension, @.ipynb@ is added
  -- later).
  JupyterGenOptions -> String
fileName :: String
}

instance ToFiles LessonPlan JupyterGenOptions where
  -- | Realize a 'LessonPlan' as a single Jupyter notebook file.
  toFiles :: LessonPlan -> JupyterGenOptions -> [FileLayout]
toFiles LessonPlan
plan JupyterGenOptions{String
LsnDesc
CI -> CI -> Sentence
lsnDesc :: JupyterGenOptions -> LsnDesc
titleComb :: JupyterGenOptions -> CI -> CI -> Sentence
fileName :: JupyterGenOptions -> String
lsnDesc :: LsnDesc
titleComb :: CI -> CI -> Sentence
fileName :: String
..} = [FileLayout]
files
    where
      -- Steps:

      -- 1. Transform `LessonPlan` into SDL (Semantic Document language).
      nm :: Sentence
nm = CI
notebook CI -> CI -> Sentence
`titleComb` (LessonPlan
plan LessonPlan -> Getting CI LessonPlan CI -> CI
forall s a. s -> Getting a s a -> a
^. Getting CI LessonPlan CI
forall c. HasSystemMeta c => Lens' c CI
Lens' LessonPlan CI
sysName)
      as :: Sentence
as = SepType -> FoldType -> [Sentence] -> Sentence
foldlList SepType
Comma FoldType
List ([Sentence] -> Sentence) -> [Sentence] -> Sentence
forall a b. (a -> b) -> a -> b
$ (Person -> Sentence) -> [Person] -> [Sentence]
forall a b. (a -> b) -> [a] -> [b]
map (String -> Sentence
S (String -> Sentence) -> (Person -> String) -> Person -> Sentence
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Person -> String
forall n. HasName n => n -> String
fullName) ([Person] -> [Sentence]) -> [Person] -> [Sentence]
forall a b. (a -> b) -> a -> b
$ LessonPlan
plan LessonPlan -> Getting [Person] LessonPlan [Person] -> [Person]
forall s a. s -> Getting a s a -> a
^. Getting [Person] LessonPlan [Person]
forall c. HasSystemMeta c => Lens' c [Person]
Lens' LessonPlan [Person]
authors
      -- FIXME: These sections should be inserted into the ChunkDB but doing so
      -- (currently) creates a "duplicate chunk insertion" error /because/ the
      -- lesson plan is often initialized with `withCommonKnowledge` (from
      -- `drasil-gen`), which by default loads the sections presumed existent in
      -- an SRS. The `Section` duplicate: References.
      nb :: Document
nb = Sentence -> Sentence -> [Section] -> Document
Notebook Sentence
nm Sentence
as ([Section] -> Document) -> [Section] -> Document
forall a b. (a -> b) -> a -> b
$ ChunkDB -> LsnDesc -> [Section]
mkSections (LessonPlan
plan LessonPlan -> Getting ChunkDB LessonPlan ChunkDB -> ChunkDB
forall s a. s -> Getting a s a -> a
^. Getting ChunkDB LessonPlan ChunkDB
forall c. HasSystemMeta c => Lens' c ChunkDB
Lens' LessonPlan ChunkDB
systemdb) LsnDesc
lsnDesc

      -- 2. Transform SDL into TDL (Typesetting Document Language).
      printSetting :: PrintingInformation
printSetting = ChunkDB -> Stage -> Notation -> PrintingInformation
piSys (LessonPlan
plan LessonPlan -> Getting ChunkDB LessonPlan ChunkDB -> ChunkDB
forall s a. s -> Getting a s a -> a
^. Getting ChunkDB LessonPlan ChunkDB
forall c. HasSystemMeta c => Lens' c ChunkDB
Lens' LessonPlan ChunkDB
systemdb) Stage
Equational Notation
Engineering
      pd :: Document
pd = PrintingInformation -> Document -> Document
makeDocument PrintingInformation
printSetting Document
nb

      -- 3. Transform TDL into `Prettyprinter.Doc`.
      doc :: Doc ann
doc = Document -> Doc ann
forall ann. Document -> Doc ann
genJupyterLessonPlan Document
pd

      -- 4. Produce final files (with `Prettyprinter.Doc` body).
      files :: [FileLayout]
files = [PathSegment -> Doc Any -> FileLayout
forall doc. Writeable doc => PathSegment -> doc -> FileLayout
file [ps|{fileName}.ipynb|] Doc Any
forall {ann}. Doc ann
doc]

-- | Helper for creating the notebook sections.
mkSections :: ChunkDB -> LsnDesc -> [Section]
mkSections :: ChunkDB -> LsnDesc -> [Section]
mkSections ChunkDB
db LsnDesc
dd = (LsnChapter -> Section) -> LsnDesc -> [Section]
forall a b. (a -> b) -> [a] -> [b]
map LsnChapter -> Section
doit LsnDesc
dd
  where
    bib :: [Contents]
bib = [UnlabelledContent -> Contents
UlC (UnlabelledContent -> Contents) -> UnlabelledContent -> Contents
forall a b. (a -> b) -> a -> b
$ RawContent -> UnlabelledContent
ulcc (BibRef -> RawContent
Bib (BibRef -> RawContent) -> BibRef -> RawContent
forall a b. (a -> b) -> a -> b
$ ChunkDB -> LsnDesc -> BibRef
extractBib ChunkDB
db LsnDesc
dd)]
    doit :: LsnChapter -> Section
    doit :: LsnChapter -> Section
doit (Intro [Contents]
i)        = String -> IdeaDict -> [Contents] -> [Section] -> Section
forall c.
Idea c =>
String -> c -> [Contents] -> [Section] -> Section
mkLsnSec  String
"Intro"      IdeaDict
Doc.introduction [Contents]
i   []
    doit (LearnObj [Contents]
lo)    = String -> CI -> [Contents] -> [Section] -> Section
forall c.
Idea c =>
String -> c -> [Contents] -> [Section] -> Section
mkLsnSec' String
"LearnObj"   CI
Doc.learnObj     [Contents]
lo  []
    doit (Review [Contents]
r [Section]
ss)    = String -> IdeaDict -> [Contents] -> [Section] -> Section
forall c.
Idea c =>
String -> c -> [Contents] -> [Section] -> Section
mkLsnSec  String
"Review"     IdeaDict
Doc.review       [Contents]
r   [Section]
ss
    doit (CaseProb [Contents]
cp [Section]
ss) = String -> IdeaDict -> [Contents] -> [Section] -> Section
forall c.
Idea c =>
String -> c -> [Contents] -> [Section] -> Section
mkLsnSec  String
"CaseProb"   IdeaDict
Doc.caseProb     [Contents]
cp  [Section]
ss
    doit (Example [Contents]
e)      = String -> IdeaDict -> [Contents] -> [Section] -> Section
forall c.
Idea c =>
String -> c -> [Contents] -> [Section] -> Section
mkLsnSec  String
"Example"    IdeaDict
Doc.example      [Contents]
e   []
    doit (Smmry [Contents]
s)        = String -> IdeaDict -> [Contents] -> [Section] -> Section
forall c.
Idea c =>
String -> c -> [Contents] -> [Section] -> Section
mkLsnSec  String
"Summary"    IdeaDict
Doc.summary      [Contents]
s   []
    doit LsnChapter
BibSec           = String -> IdeaDict -> [Contents] -> [Section] -> Section
forall c.
Idea c =>
String -> c -> [Contents] -> [Section] -> Section
mkLsnSec' String
"References" IdeaDict
Doc.reference    [Contents]
bib []
    doit (Apndx [Contents]
a)        = String -> IdeaDict -> [Contents] -> [Section] -> Section
forall c.
Idea c =>
String -> c -> [Contents] -> [Section] -> Section
mkLsnSec  String
"Appendix"   IdeaDict
Doc.appendix     [Contents]
a   []

-- | Internal: Create a section of the lesson plan. Title is singular.
mkLsnSec :: Idea c => String -> c -> [Contents] -> [Section] -> Section
mkLsnSec :: forall c.
Idea c =>
String -> c -> [Contents] -> [Section] -> Section
mkLsnSec String
r c
c [Contents]
cs [Section]
ss = Sentence -> [Contents] -> [Section] -> Reference -> Section
section Sentence
t [Contents]
cs [Section]
ss (String -> Sentence -> Reference
makeSecRef String
r Sentence
t)
  where t :: Sentence
t = c -> Sentence
forall n. NamedIdea n => n -> Sentence
titleize c
c

-- | Internal: Create a section of the lesson plan. Title is made plural.
mkLsnSec' :: Idea c => String -> c -> [Contents] -> [Section] -> Section
mkLsnSec' :: forall c.
Idea c =>
String -> c -> [Contents] -> [Section] -> Section
mkLsnSec' String
r c
c [Contents]
cs [Section]
ss = Sentence -> [Contents] -> [Section] -> Reference -> Section
section Sentence
t [Contents]
cs [Section]
ss (String -> Sentence -> Reference
makeSecRef String
r Sentence
t)
  where t :: Sentence
t = c -> Sentence
forall n. NamedIdea n => n -> Sentence
titleize' c
c