{-# LANGUAGE QuasiQuotes #-}
-- | Case study variants.
--
-- Each case study is expected to generate files in a specific pattern that the
-- main `code/Makefile` expects for (a) testing and (b) website deployment.
module Drasil.Generator.CaseStudyVariants
  ( caseStudyMainSRS,
    caseStudyMainSRSWCode,
    caseStudyMainSRSWCodeZooWLsnPlan,
    caseStudyMainDrasilWebsite,
  )
where

import Control.Lens ((^.))
import Data.Char (toLower)
import Data.Maybe (maybeToList)
import GHC.IO.Encoding (setLocaleEncoding, utf8)

import Drasil.FileHandling (FileLayout, OverwritePolicy(..), directory, localPath, ps,
  writeFiles)
import Drasil.LessonPlan (LsnDesc)
import Drasil.SRS (SRSDecl, mkDoc)
import Drasil.System (DrasilWebsite, LessonPlan, SmithEtAlSRS, programName)
import Language.Drasil.Code (Choices)
import qualified Language.Drasil.Sentence.Combinators as S

import Drasil.Generator.ChunkDump (buildDebugData)
import Drasil.Generator.Code (genCode, genCodeZoo)
import Drasil.Generator.LessonPlan (genJupyterLessonPlan)
import Drasil.Generator.SRS (genSmithEtAlSrs)
import Drasil.Generator.SRS.TypeCheck (typeCheckSI)
import Drasil.Generator.Website (genWebsite)

-- | Internal: Set system locale encoding to UTF-8.
setSystemLocale :: IO ()
setSystemLocale :: IO ()
setSystemLocale = TextEncoding -> IO ()
setLocaleEncoding TextEncoding
utf8

-- | Internal: The `build/` subfolder the Makefile expects each case study will
-- build in (other than the website).
caseStudyBuildFolder :: SmithEtAlSRS -> String
caseStudyBuildFolder :: SmithEtAlSRS -> [Char]
caseStudyBuildFolder = (Char -> Char) -> [Char] -> [Char]
forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
toLower ([Char] -> [Char])
-> (SmithEtAlSRS -> [Char]) -> SmithEtAlSRS -> [Char]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (SmithEtAlSRS -> Getting [Char] SmithEtAlSRS [Char] -> [Char]
forall s a. s -> Getting a s a -> a
^. Getting [Char] SmithEtAlSRS [Char]
forall c. HasSmithEtAlSRS c => Lens' c [Char]
Lens' SmithEtAlSRS [Char]
programName)

-- | Internal: Generate documents and construct the SRS directory layout
-- structure (and debug data) for an example.
writeSmithEtAlSrs :: SmithEtAlSRS -> SRSDecl -> String -> IO ([FileLayout], SmithEtAlSRS, String)
writeSmithEtAlSrs :: SmithEtAlSRS
-> SRSDecl -> [Char] -> IO ([FileLayout], SmithEtAlSRS, [Char])
writeSmithEtAlSrs SmithEtAlSRS
syst SRSDecl
srsDecl [Char]
srsFileName = do
  let exampleName :: [Char]
exampleName = SmithEtAlSRS -> [Char]
caseStudyBuildFolder SmithEtAlSRS
syst
      (Document
srs, SmithEtAlSRS
syst') = SmithEtAlSRS
-> SRSDecl -> (CI -> CI -> Sentence) -> (Document, SmithEtAlSRS)
mkDoc SmithEtAlSRS
syst SRSDecl
srsDecl CI -> CI -> Sentence
forall c d. (NamedIdea c, NamedIdea d) => c -> d -> Sentence
S.forT
  Maybe FileLayout
mDbgData <- SmithEtAlSRS -> IO (Maybe FileLayout)
buildDebugData SmithEtAlSRS
syst'
  SmithEtAlSRS -> IO ()
typeCheckSI SmithEtAlSRS
syst' -- FIXME: This should be done on `System` creation *or* chunk creation!
  let dbgData :: [FileLayout]
dbgData = Maybe FileLayout -> [FileLayout]
forall a. Maybe a -> [a]
maybeToList Maybe FileLayout
mDbgData
      layout :: [FileLayout]
layout = [FileLayout]
dbgData [FileLayout] -> [FileLayout] -> [FileLayout]
forall a. [a] -> [a] -> [a]
++ SmithEtAlSRS -> Document -> [Char] -> [FileLayout]
genSmithEtAlSrs SmithEtAlSRS
syst' Document
srs [Char]
srsFileName
  ([FileLayout], SmithEtAlSRS, [Char])
-> IO ([FileLayout], SmithEtAlSRS, [Char])
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ([FileLayout]
layout, SmithEtAlSRS
syst', [Char]
exampleName)

-- | A case study that only outputs an SRS in each of our supported variants.
caseStudyMainSRS :: SmithEtAlSRS -> SRSDecl -> String -> IO ()
caseStudyMainSRS :: SmithEtAlSRS -> SRSDecl -> [Char] -> IO ()
caseStudyMainSRS SmithEtAlSRS
syst SRSDecl
srsDecl [Char]
srsFileName = do
  IO ()
setSystemLocale
  ([FileLayout]
docLayouts, SmithEtAlSRS
_, [Char]
exampleName) <- SmithEtAlSRS
-> SRSDecl -> [Char] -> IO ([FileLayout], SmithEtAlSRS, [Char])
writeSmithEtAlSrs SmithEtAlSRS
syst SRSDecl
srsDecl [Char]
srsFileName
  OverwritePolicy -> OsPath -> FileLayout -> IO ()
writeFiles OverwritePolicy
OverwriteAllowed OsPath
localPath (FileLayout -> IO ()) -> FileLayout -> IO ()
forall a b. (a -> b) -> a -> b
$ PathSegment -> [FileLayout] -> FileLayout
forall (f :: * -> *).
Foldable f =>
PathSegment -> f FileLayout -> FileLayout
directory [ps|{exampleName}|] [FileLayout]
docLayouts

-- | A case study that outputs both an SRS in each of our supported variants as
-- well as a single chosen software artifact in optionally many programming
-- languages.
caseStudyMainSRSWCode :: SmithEtAlSRS -> SRSDecl -> String -> Choices -> IO ()
caseStudyMainSRSWCode :: SmithEtAlSRS -> SRSDecl -> [Char] -> Choices -> IO ()
caseStudyMainSRSWCode SmithEtAlSRS
syst SRSDecl
srsDecl [Char]
srsFileName Choices
choices = do
  IO ()
setSystemLocale
  ([FileLayout]
docLayouts, SmithEtAlSRS
syst', [Char]
exampleName) <- SmithEtAlSRS
-> SRSDecl -> [Char] -> IO ([FileLayout], SmithEtAlSRS, [Char])
writeSmithEtAlSrs SmithEtAlSRS
syst SRSDecl
srsDecl [Char]
srsFileName
  FileLayout
srcLayout <- SmithEtAlSRS -> Choices -> IO FileLayout
genCode SmithEtAlSRS
syst' Choices
choices
  OverwritePolicy -> OsPath -> FileLayout -> IO ()
writeFiles OverwritePolicy
OverwriteAllowed OsPath
localPath (FileLayout -> IO ()) -> FileLayout -> IO ()
forall a b. (a -> b) -> a -> b
$ PathSegment -> [FileLayout] -> FileLayout
forall (f :: * -> *).
Foldable f =>
PathSegment -> f FileLayout -> FileLayout
directory [ps|{exampleName}|] ([FileLayout] -> FileLayout) -> [FileLayout] -> FileLayout
forall a b. (a -> b) -> a -> b
$ FileLayout
srcLayout FileLayout -> [FileLayout] -> [FileLayout]
forall a. a -> [a] -> [a]
: [FileLayout]
docLayouts

-- | The same as 'caseStudyMainSRSWCode', except it also produces a
-- JupyterNotebook-based lesson plan.
caseStudyMainSRSWCodeZooWLsnPlan :: SmithEtAlSRS -> SRSDecl -> String
  -> [Choices] -> LessonPlan -> LsnDesc -> String -> IO ()
caseStudyMainSRSWCodeZooWLsnPlan :: SmithEtAlSRS
-> SRSDecl
-> [Char]
-> [Choices]
-> LessonPlan
-> LsnDesc
-> [Char]
-> IO ()
caseStudyMainSRSWCodeZooWLsnPlan SmithEtAlSRS
syst SRSDecl
srsDecl [Char]
srsFileName [Choices]
choices LessonPlan
plan LsnDesc
nbDecl [Char]
lsnFileName = do
  IO ()
setSystemLocale
  ([FileLayout]
docLayouts, SmithEtAlSRS
syst', [Char]
exampleName) <- SmithEtAlSRS
-> SRSDecl -> [Char] -> IO ([FileLayout], SmithEtAlSRS, [Char])
writeSmithEtAlSrs SmithEtAlSRS
syst SRSDecl
srsDecl [Char]
srsFileName
  [FileLayout]
zooLayouts <- SmithEtAlSRS -> [Choices] -> IO [FileLayout]
genCodeZoo SmithEtAlSRS
syst' [Choices]
choices
  let lessonLayout :: FileLayout
lessonLayout = PathSegment -> [FileLayout] -> FileLayout
forall (f :: * -> *).
Foldable f =>
PathSegment -> f FileLayout -> FileLayout
directory [ps|Lesson|] [LessonPlan -> LsnDesc -> [Char] -> FileLayout
genJupyterLessonPlan LessonPlan
plan LsnDesc
nbDecl [Char]
lsnFileName]
      layout :: FileLayout
layout = PathSegment -> [FileLayout] -> FileLayout
forall (f :: * -> *).
Foldable f =>
PathSegment -> f FileLayout -> FileLayout
directory [ps|{exampleName}|] ([FileLayout] -> FileLayout) -> [FileLayout] -> FileLayout
forall a b. (a -> b) -> a -> b
$ FileLayout
lessonLayout FileLayout -> [FileLayout] -> [FileLayout]
forall a. a -> [a] -> [a]
: [FileLayout]
docLayouts [FileLayout] -> [FileLayout] -> [FileLayout]
forall a. [a] -> [a] -> [a]
++ [FileLayout]
zooLayouts
  OverwritePolicy -> OsPath -> FileLayout -> IO ()
writeFiles OverwritePolicy
OverwriteAllowed OsPath
localPath FileLayout
layout

-- | The Drasil website binary is expected to build a `Website/HTML/` folder
-- containing the actual website artifacts (`index.html` and `index.css`).
caseStudyMainDrasilWebsite :: DrasilWebsite -> IO ()
caseStudyMainDrasilWebsite :: DrasilWebsite -> IO ()
caseStudyMainDrasilWebsite DrasilWebsite
dw = do
  IO ()
setSystemLocale
  OverwritePolicy -> OsPath -> FileLayout -> IO ()
writeFiles OverwritePolicy
OverwriteAllowed OsPath
localPath (FileLayout -> IO ()) -> FileLayout -> IO ()
forall a b. (a -> b) -> a -> b
$
    PathSegment -> [FileLayout] -> FileLayout
forall (f :: * -> *).
Foldable f =>
PathSegment -> f FileLayout -> FileLayout
directory [ps|website|] ([FileLayout] -> FileLayout) -> [FileLayout] -> FileLayout
forall a b. (a -> b) -> a -> b
$ DrasilWebsite -> [FileLayout]
genWebsite DrasilWebsite
dw