{-# LANGUAGE QuasiQuotes #-}
module Drasil.Generator.SRS (
  -- * SRS Generator
  genSmithEtAlSrs
) where

import Prelude hiding (id)
import Control.Lens ((^.))

import Drasil.SRS (mkGraphInfo)
import Drasil.FileHandling (FileLayout, directory, file, ps)
import Language.Drasil (Stage(Equational))
import Language.Drasil.Document (Document(..), checkToC)
import Language.Drasil.Printers (genericCSS, genHTML, genTeX,
  genMDBook, Notation(Engineering), piSys, PrintingInformation,
  genJupyterSRS)
import Drasil.Makefile ((+:+), makeS, mkCheckedCommand, mkCommand,
  mkFreeVar, mkFile, mkRule, mkMakefile, printMakefile)
import Drasil.Metadata (watermark)
import Language.Drasil.Printing.Import (makeDocument, makeProject)
import Drasil.System (SmithEtAlSRS, refTable, systemdb)

import Drasil.Generator.Formats (Filename, Format(..))
import Drasil.Generator.SRS.TraceabilityGraphs (outputDot)

-- | Generate Drasil's SRS (in HTML, TeX, Jupyter, and MDBook formats).
genSmithEtAlSrs :: SmithEtAlSRS -> Document -> String -> [FileLayout]
genSmithEtAlSrs :: SmithEtAlSRS -> Document -> String -> [FileLayout]
genSmithEtAlSrs SmithEtAlSRS
syst Document
doc String
srsFileName =
  [ FileLayout
srsLayout,
    FileLayout
traceyLayout
  ]
  where
    pinfo :: PrintingInformation
pinfo = ChunkDB
-> Map UID Reference -> Stage -> Notation -> PrintingInformation
piSys (SmithEtAlSRS
syst SmithEtAlSRS -> Getting ChunkDB SmithEtAlSRS ChunkDB -> ChunkDB
forall s a. s -> Getting a s a -> a
^. Getting ChunkDB SmithEtAlSRS ChunkDB
forall c. HasSystemMeta c => Lens' c ChunkDB
Lens' SmithEtAlSRS ChunkDB
systemdb) (SmithEtAlSRS
syst SmithEtAlSRS
-> Getting (Map UID Reference) SmithEtAlSRS (Map UID Reference)
-> Map UID Reference
forall s a. s -> Getting a s a -> a
^. Getting (Map UID Reference) SmithEtAlSRS (Map UID Reference)
forall c. HasSmithEtAlSRS c => Lens' c (Map UID Reference)
Lens' SmithEtAlSRS (Map UID Reference)
refTable) Stage
Equational Notation
Engineering
    srsLayout :: FileLayout
srsLayout =
      PathSegment -> [FileLayout] -> FileLayout
forall (f :: * -> *).
Foldable f =>
PathSegment -> f FileLayout -> FileLayout
directory [ps|SRS|] ([FileLayout] -> FileLayout) -> [FileLayout] -> FileLayout
forall a b. (a -> b) -> a -> b
$
        (Format -> FileLayout) -> [Format] -> [FileLayout]
forall a b. (a -> b) -> [a] -> [b]
map
          ( \Format
x ->
              let x' :: String
x' = Format -> String
forall a. Show a => a -> String
show Format
x
              in PathSegment -> [FileLayout] -> FileLayout
forall (f :: * -> *).
Foldable f =>
PathSegment -> f FileLayout -> FileLayout
directory [ps|{x'}|] ([FileLayout] -> FileLayout) -> [FileLayout] -> FileLayout
forall a b. (a -> b) -> a -> b
$
                    Document -> PrintingInformation -> String -> Format -> [FileLayout]
prntDoc Document
doc PrintingInformation
pinfo String
srsFileName Format
x
          )
          [Format
HTML, Format
TeX, Format
Jupyter, Format
MDBook]
    traceyLayout :: FileLayout
traceyLayout = GraphInfo -> FileLayout
outputDot (SmithEtAlSRS -> GraphInfo
mkGraphInfo SmithEtAlSRS
syst)

-- | Internal: Render an SRS in a specified 'Format' and lay out artifacts into
-- a `[FileLayout]`.
prntDoc :: Document -> PrintingInformation -> String -> Format -> [FileLayout]
prntDoc :: Document -> PrintingInformation -> String -> Format -> [FileLayout]
prntDoc Document
d PrintingInformation
pinfo String
_ Format
MDBook =
  FileLayout
mdBookMakefile FileLayout -> [FileLayout] -> [FileLayout]
forall a. a -> [a] -> [a]
: Project -> [FileLayout]
genMDBook (PrintingInformation -> Document -> Project
makeProject PrintingInformation
pinfo Document
d)
prntDoc Document
d PrintingInformation
pinfo String
fn Format
Jupyter =
  [PathSegment -> Doc -> FileLayout
forall doc. Writeable doc => PathSegment -> doc -> FileLayout
file [ps|{fn}.ipynb|] (Doc -> FileLayout) -> Doc -> FileLayout
forall a b. (a -> b) -> a -> b
$ Document -> Doc
genJupyterSRS (Document -> Doc) -> Document -> Doc
forall a b. (a -> b) -> a -> b
$ PrintingInformation -> Document -> Document
makeDocument PrintingInformation
pinfo Document
d]
prntDoc Document
d PrintingInformation
pinfo String
fn Format
HTML =
  [ PathSegment -> Doc -> FileLayout
forall doc. Writeable doc => PathSegment -> doc -> FileLayout
file [ps|{fn}.html|] (Doc -> FileLayout) -> Doc -> FileLayout
forall a b. (a -> b) -> a -> b
$ String -> Document -> Doc
genHTML String
fn (Document -> Doc) -> Document -> Doc
forall a b. (a -> b) -> a -> b
$ PrintingInformation -> Document -> Document
makeDocument PrintingInformation
pinfo Document
d,
    PathSegment -> Doc -> FileLayout
forall doc. Writeable doc => PathSegment -> doc -> FileLayout
file [ps|{fn}.css|] Doc
genericCSS
  ]
prntDoc d :: Document
d@(Document Title
_ Title
_ ShowTableOfContents
st [Section]
_) PrintingInformation
pinfo String
fn Format
TeX =
  [ PathSegment -> Doc -> FileLayout
forall doc. Writeable doc => PathSegment -> doc -> FileLayout
file [ps|{fn}.tex|] (Doc -> FileLayout) -> Doc -> FileLayout
forall a b. (a -> b) -> a -> b
$ Document -> ShowTableOfContents -> PrintingInformation -> Doc
genTeX (PrintingInformation -> Document -> Document
makeDocument PrintingInformation
pinfo (Document -> Document) -> Document -> Document
forall a b. (a -> b) -> a -> b
$ Document -> Document
checkToC Document
d) ShowTableOfContents
st PrintingInformation
pinfo,
    String -> FileLayout
teXMakefile String
fn
  ]
prntDoc Notebook {} PrintingInformation
_ String
_ Format
TeX = String -> [FileLayout]
forall a. HasCallStack => String -> a
error String
"cannot render notebooks into LaTeX"

-- | Internal: Basic Makefile suitable for building TeX projects.
teXMakefile :: Filename -> FileLayout
teXMakefile :: String -> FileLayout
teXMakefile String
fn = PathSegment -> Doc -> FileLayout
forall doc. Writeable doc => PathSegment -> doc -> FileLayout
file [ps|Makefile|] (Doc -> FileLayout) -> Doc -> FileLayout
forall a b. (a -> b) -> a -> b
$ Makefile -> Doc
printMakefile (Makefile -> Doc) -> Makefile -> Doc
forall a b. (a -> b) -> a -> b
$ [Rule] -> Makefile
mkMakefile [
  [String] -> Target -> Dependencies -> [Command] -> Rule
mkRule [String
watermark] (String -> Target
makeS String
"srs") [Target
pdfName] [],
  [String] -> Target -> Dependencies -> [Command] -> Rule
mkFile [] Target
pdfName [Target
texFile] [Command
lualatex, Command
bibtex, Command
lualatex, Command
lualatex]]
  where
    lualatex :: Command
lualatex = Target -> Command
mkCheckedCommand (Target -> Command) -> Target -> Command
forall a b. (a -> b) -> a -> b
$ String -> Target
makeS String
"lualatex" Target -> Target -> Target
+:+ String -> Target
mkFreeVar String
"TEXFLAGS"    Target -> Target -> Target
+:+ String -> Target
makeS String
fn
    bibtex :: Command
bibtex   = Target -> Command
mkCommand        (Target -> Command) -> Target -> Command
forall a b. (a -> b) -> a -> b
$ String -> Target
makeS String
"bibtex"   Target -> Target -> Target
+:+ String -> Target
mkFreeVar String
"BIBTEXFLAGS" Target -> Target -> Target
+:+ String -> Target
makeS String
fn
    pdfName :: Target
pdfName  = String -> Target
makeS (String -> Target) -> String -> Target
forall a b. (a -> b) -> a -> b
$ String
fn String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
".pdf"
    texFile :: Target
texFile  = String -> Target
makeS (String -> Target) -> String -> Target
forall a b. (a -> b) -> a -> b
$ String
fn String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
".tex"

-- | Internal: Basic Makefile suitable for building mdBook projects.
mdBookMakefile :: FileLayout
mdBookMakefile :: FileLayout
mdBookMakefile = PathSegment -> Doc -> FileLayout
forall doc. Writeable doc => PathSegment -> doc -> FileLayout
file [ps|Makefile|] (Doc -> FileLayout) -> Doc -> FileLayout
forall a b. (a -> b) -> a -> b
$ Makefile -> Doc
printMakefile (Makefile -> Doc) -> Makefile -> Doc
forall a b. (a -> b) -> a -> b
$ [Rule] -> Makefile
mkMakefile [
  [String] -> Target -> Dependencies -> [Command] -> Rule
mkRule [String
watermark] (String -> Target
makeS String
"build")  [] [Target -> Command
mkCheckedCommand (Target -> Command) -> Target -> Command
forall a b. (a -> b) -> a -> b
$ String -> Target
makeS String
"mdbook build"],
  [String] -> Target -> Dependencies -> [Command] -> Rule
mkRule []          (String -> Target
makeS String
"server") [] [Target -> Command
mkCheckedCommand (Target -> Command) -> Target -> Command
forall a b. (a -> b) -> a -> b
$ String -> Target
makeS String
"mdbook serve --open"]]