-- | Case Studies table for the different choices available when generating code from Drasil.
-- To be used in the Drasil website.
module Drasil.Website.CaseStudy where

import Language.Drasil hiding (E)
import Language.Drasil.Code
import SysInfo.Drasil
import GOOL.Drasil (CodeType(..))

import Drasil.Website.Example (examples, Example(..))
import qualified Drasil.Projectile.Choices as Projectile (codedDirName)


-- * Case Studies Section

-- | Creates the Case Study Section.
caseStudySec :: Section
caseStudySec :: Section
caseStudySec =
  Sentence -> [Contents] -> [Section] -> Reference -> Section
section (String -> Sentence
S String
caseStudiesTitle) -- Title
  [Sentence -> Contents
mkParagraph (Sentence -> Contents) -> Sentence -> Contents
forall a b. (a -> b) -> a -> b
$ String -> Sentence
S String
caseStudiesDesc, Reference -> RawContent -> Contents
mkFig (String -> Reference
makeTabRef "CaseStudy") RawContent
mkCaseTable,
    Sentence -> Contents
mkParagraph (Sentence -> Contents) -> Sentence -> Contents
forall a b. (a -> b) -> a -> b
$ String -> Sentence
S String
legendIntro, UnlabelledContent -> Contents
UlC (UnlabelledContent -> Contents) -> UnlabelledContent -> Contents
forall a b. (a -> b) -> a -> b
$ RawContent -> UnlabelledContent
ulcc RawContent
caseStudyLegend] -- Contents
  [] (Reference -> Section) -> Reference -> Section
forall a b. (a -> b) -> a -> b
$ String -> Sentence -> Reference
makeSecRef "CaseStudy" (Sentence -> Reference) -> Sentence -> Reference
forall a b. (a -> b) -> a -> b
$ String -> Sentence
S String
caseStudiesTitle -- Section Reference

caseStudiesTitle, caseStudiesDesc, legendIntro :: String
-- | Section title.
caseStudiesTitle :: String
caseStudiesTitle = "Case Studies"
-- | Section description.
caseStudiesDesc :: String
caseStudiesDesc = "Drasil allows some design decisions to be made by the user when generating \
  \code. The table below summarizes the design decisions made for each case \
  \study, followed by a guide giving the meaning of the short-forms used in the \
  \table:"
-- | Introduce the Case Study Table Legend as a list.
legendIntro :: String
legendIntro = "The legend for the Case Studies Table is listed below according to column header:"

-- | Creates the Case Study Table
mkCaseTable :: RawContent
mkCaseTable :: RawContent
mkCaseTable = [Sentence] -> [[Sentence]] -> Sentence -> Bool -> RawContent
Table [Sentence]
headerRow ([CaseStudy] -> [[Sentence]]
tableBody ([CaseStudy] -> [[Sentence]]) -> [CaseStudy] -> [[Sentence]]
forall a b. (a -> b) -> a -> b
$ (Example -> [CaseStudy]) -> [Example] -> [CaseStudy]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap Example -> [CaseStudy]
mkCaseStudy ([Example] -> [CaseStudy]) -> [Example] -> [CaseStudy]
forall a b. (a -> b) -> a -> b
$ String -> String -> [Example]
examples "" "")  Sentence
EmptyS Bool
False

-- * Manipulating info from 'Example' -> 'CaseStudy'
--
-- $ExampleToCaseStudy
--
-- After taking the information about the examples from Example.hs,
-- convert each example into its own case study.

-- | Holds individual case studies. System info may not be needed,
-- but it is still nice to keep around for now.
data CaseStudy = CS {
  -- | Each case study needs a name, so use system information. 
  CaseStudy -> SystemInformation
sysInfoCS :: SystemInformation,
  -- | A case study may have different program names for the same example (ex. Projectile).
  CaseStudy -> Sentence
progName :: Sentence,
  -- | Each case study has code that is generated from a set of choices.
  CaseStudy -> Choices
choicesCS :: Choices}

-- | Converts a list of examples into a list of CaseStudies. 
-- Currently, projectile is the only one that has more than one set of choices,
-- so we take the naming scheme from there.
mkCaseStudy :: Example -> [CaseStudy]
mkCaseStudy :: Example -> [CaseStudy]
mkCaseStudy E{choicesE :: Example -> [Choices]
choicesE = []} = []
mkCaseStudy E{sysInfoE :: Example -> SystemInformation
sysInfoE = si :: SystemInformation
si@SI{_sys :: ()
_sys = a
sys}, choicesE :: Example -> [Choices]
choicesE = [x :: Choices
x]} = [CS :: SystemInformation -> Sentence -> Choices -> CaseStudy
CS{sysInfoCS :: SystemInformation
sysInfoCS = SystemInformation
si, progName :: Sentence
progName = String -> Sentence
S (String -> Sentence) -> String -> Sentence
forall a b. (a -> b) -> a -> b
$ a -> String
forall c. CommonIdea c => c -> String
abrv a
sys, choicesCS :: Choices
choicesCS = Choices
x}]
mkCaseStudy E{sysInfoE :: Example -> SystemInformation
sysInfoE = si :: SystemInformation
si@SI{_sys :: ()
_sys = a
sys}, choicesE :: Example -> [Choices]
choicesE = [Choices]
xs} = (Choices -> CaseStudy) -> [Choices] -> [CaseStudy]
forall a b. (a -> b) -> [a] -> [b]
map (\x :: Choices
x -> CS :: SystemInformation -> Sentence -> Choices -> CaseStudy
CS{sysInfoCS :: SystemInformation
sysInfoCS = SystemInformation
si, progName :: Sentence
progName = String -> Sentence
S (String -> Sentence) -> String -> Sentence
forall a b. (a -> b) -> a -> b
$ String -> Choices -> String
Projectile.codedDirName (a -> String
forall c. CommonIdea c => c -> String
abrv a
sys) Choices
x, choicesCS :: Choices
choicesCS = Choices
x}) [Choices]
xs

-- * Display 'CaseStudy' Information as a Table
--
-- $CaseStudy
--
-- We first need the helper functions to convert 'Choices' into a displayable format (as a 'Sentence').
-- Those are defined in the section below to reduce clutter.
-- Then we make the header row, table body, and helper for the table body functions.

-- | Hardcoded header row for the Case studies table
headerRow :: [Sentence]
headerRow :: [Sentence]
headerRow = (String -> Sentence) -> [String] -> [Sentence]
forall a b. (a -> b) -> [a] -> [b]
map String -> Sentence
S [String
caseStudyTitle, String
modularityTitle, String
implementTypeTitle, String
loggingTitle, String
inStructTitle, String
conStructTitle, String
conRepTitle, String
realNumRepTitle]

-- | Creates the case study table body.
tableBody :: [CaseStudy] -> [[Sentence]]
tableBody :: [CaseStudy] -> [[Sentence]]
tableBody = (CaseStudy -> [Sentence]) -> [CaseStudy] -> [[Sentence]]
forall a b. (a -> b) -> [a] -> [b]
map CaseStudy -> [Sentence]
displayCS

-- | Converts a case study into a table row for easy display.
displayCS :: CaseStudy -> [Sentence]
displayCS :: CaseStudy -> [Sentence]
displayCS CS{progName :: CaseStudy -> Sentence
progName = Sentence
nm,
  choicesCS :: CaseStudy -> Choices
choicesCS = Choices{
    architecture :: Choices -> Architecture
architecture = Architecture
a,
    dataInfo :: Choices -> DataInfo
dataInfo = DataInfo
d,
    maps :: Choices -> Maps
maps = Maps
m,
    optFeats :: Choices -> OptionalFeatures
optFeats = OptionalFeatures
o
    }} = [Sentence
nm, Modularity -> Sentence
getMod (Modularity -> Sentence) -> Modularity -> Sentence
forall a b. (a -> b) -> a -> b
$ Architecture -> Modularity
modularity Architecture
a, ImplementationType -> Sentence
getImp (ImplementationType -> Sentence) -> ImplementationType -> Sentence
forall a b. (a -> b) -> a -> b
$ Architecture -> ImplementationType
impType Architecture
a, [Logging] -> Sentence
getLog ([Logging] -> Sentence) -> [Logging] -> Sentence
forall a b. (a -> b) -> a -> b
$ LogConfig -> [Logging]
logging (LogConfig -> [Logging]) -> LogConfig -> [Logging]
forall a b. (a -> b) -> a -> b
$ OptionalFeatures -> LogConfig
logConfig OptionalFeatures
o,
          Structure -> Sentence
getInstr (Structure -> Sentence) -> Structure -> Sentence
forall a b. (a -> b) -> a -> b
$ DataInfo -> Structure
inputStructure DataInfo
d, ConstantStructure -> Sentence
getConstr (ConstantStructure -> Sentence) -> ConstantStructure -> Sentence
forall a b. (a -> b) -> a -> b
$ DataInfo -> ConstantStructure
constStructure DataInfo
d, ConstantRepr -> Sentence
getConRep (ConstantRepr -> Sentence) -> ConstantRepr -> Sentence
forall a b. (a -> b) -> a -> b
$ DataInfo -> ConstantRepr
constRepr DataInfo
d,
           [CodeType] -> Sentence
getRealNum (Maps -> SpaceMatch
spaceMatch Maps
m Space
Real)]

-- * Case Studies Table Legend
--
-- $CSLegend
--
-- Next, we need the legend to explain the Case Studies Table.
-- These functions are essentially hard-coded and also defined below.

-- | Each entry for the case studies table legend.
-- The title should be the same as the header.
data CSLegend = CSL {
  -- | Legend title.
  CSLegend -> String
ttle :: String, -- String for now, should eventually move to at least a Sentence
  -- | Legend symbols along with their respective definitions.
  CSLegend -> [(String, String)]
symbAndDefs :: [(String, String)]
}

-- | Make the legend for the case study table as a list.
caseStudyLegend :: RawContent
caseStudyLegend :: RawContent
caseStudyLegend = ListType -> RawContent
Enumeration (ListType -> RawContent) -> ListType -> RawContent
forall a b. (a -> b) -> a -> b
$ [(ItemType, Maybe String)] -> ListType
Bullet ([(ItemType, Maybe String)] -> ListType)
-> [(ItemType, Maybe String)] -> ListType
forall a b. (a -> b) -> a -> b
$ [ItemType] -> [Maybe String] -> [(ItemType, Maybe String)]
forall a b. [a] -> [b] -> [(a, b)]
zip ((CSLegend -> ItemType) -> [CSLegend] -> [ItemType]
forall a b. (a -> b) -> [a] -> [b]
map CSLegend -> ItemType
mkLegendListFunc [CSLegend]
legendEntries) ([Maybe String] -> [(ItemType, Maybe String)])
-> [Maybe String] -> [(ItemType, Maybe String)]
forall a b. (a -> b) -> a -> b
$ Maybe String -> [Maybe String]
forall a. a -> [a]
repeat Maybe String
forall a. Maybe a
Nothing

-- | Helper to convert the Case Study legends into list items.
mkLegendListFunc :: CSLegend -> ItemType
mkLegendListFunc :: CSLegend -> ItemType
mkLegendListFunc csleg :: CSLegend
csleg = Sentence -> ListType -> ItemType
Nested (String -> Sentence
S (String -> Sentence) -> String -> Sentence
forall a b. (a -> b) -> a -> b
$ CSLegend -> String
ttle CSLegend
csleg) (ListType -> ItemType) -> ListType -> ItemType
forall a b. (a -> b) -> a -> b
$ [(ItemType, Maybe String)] -> ListType
Bullet ([(ItemType, Maybe String)] -> ListType)
-> [(ItemType, Maybe String)] -> ListType
forall a b. (a -> b) -> a -> b
$ [ItemType] -> [Maybe String] -> [(ItemType, Maybe String)]
forall a b. [a] -> [b] -> [(a, b)]
zip (((String, String) -> ItemType) -> [(String, String)] -> [ItemType]
forall a b. (a -> b) -> [a] -> [b]
map (String, String) -> ItemType
mkTandDSent ([(String, String)] -> [ItemType])
-> [(String, String)] -> [ItemType]
forall a b. (a -> b) -> a -> b
$ CSLegend -> [(String, String)]
symbAndDefs CSLegend
csleg) ([Maybe String] -> [(ItemType, Maybe String)])
-> [Maybe String] -> [(ItemType, Maybe String)]
forall a b. (a -> b) -> a -> b
$ Maybe String -> [Maybe String]
forall a. a -> [a]
repeat Maybe String
forall a. Maybe a
Nothing

-- | Should eventually take Sentences instead of Strings. Converts into the format of "symbol - definition".
mkTandDSent :: (String, String) -> ItemType
mkTandDSent :: (String, String) -> ItemType
mkTandDSent (sym :: String
sym,def :: String
def) = Sentence -> ItemType
Flat (Sentence -> ItemType) -> Sentence -> ItemType
forall a b. (a -> b) -> a -> b
$ String -> Sentence
S String
sym Sentence -> Sentence -> Sentence
+:+ String -> Sentence
S "-" Sentence -> Sentence -> Sentence
+:+ String -> Sentence
S String
def

-- | Case Study Table column headers.
caseStudyTitle, modularityTitle, implementTypeTitle, loggingTitle, inStructTitle, conStructTitle,
  conRepTitle, realNumRepTitle :: String

caseStudyTitle :: String
caseStudyTitle = "Case Study"
modularityTitle :: String
modularityTitle = "Modularity"
implementTypeTitle :: String
implementTypeTitle = "Implementation Type"
loggingTitle :: String
loggingTitle = "Logging"
inStructTitle :: String
inStructTitle = "Input Structure"
conStructTitle :: String
conStructTitle = "Constant Structure"
conRepTitle :: String
conRepTitle = "Constant Representation"
realNumRepTitle :: String
realNumRepTitle = "Real Number Representation"

-- | Case study legend entries.
legendEntries :: [CSLegend]
legendEntries :: [CSLegend]
legendEntries = [CSLegend
modularityLegend, CSLegend
implementationTypeLegend, CSLegend
loggingLegend, CSLegend
inputStrLegend, CSLegend
conStrLegend, CSLegend
conRepLegend, CSLegend
realNumRepLegend]

-- | Modularity or Separation of software.
modularityLegend :: CSLegend
modularityLegend :: CSLegend
modularityLegend = CSL :: String -> [(String, String)] -> CSLegend
CSL{
  ttle :: String
ttle = String
modularityTitle,
  symbAndDefs :: [(String, String)]
symbAndDefs = [ ("U", "Unmodular"),
                  ("C", "Modular with Combined input module"),
                  ("S", "Modular with Separated input module")]
}

-- | Software implementation type.
implementationTypeLegend :: CSLegend
implementationTypeLegend :: CSLegend
implementationTypeLegend = CSL :: String -> [(String, String)] -> CSLegend
CSL {
  ttle :: String
ttle = String
implementTypeTitle,
  symbAndDefs :: [(String, String)]
symbAndDefs = [ ("P", "Program"),
                  ("L", "Library")]
}

-- | Compiler logging statements.
loggingLegend :: CSLegend
loggingLegend :: CSLegend
loggingLegend = CSL :: String -> [(String, String)] -> CSLegend
CSL {
  ttle :: String
ttle = String
loggingTitle,
  symbAndDefs :: [(String, String)]
symbAndDefs = [ ("NoL", "No Logging statements"),
                  ("L", "Logging statements included")]
}

-- | Input value structure.
inputStrLegend :: CSLegend
inputStrLegend :: CSLegend
inputStrLegend = CSL :: String -> [(String, String)] -> CSLegend
CSL {
  ttle :: String
ttle = String
inStructTitle,
  symbAndDefs :: [(String, String)]
symbAndDefs = [ ("B", "Inputs are Bundled in a class"),
                  ("U", "Inputs are Unbundled")]
}

-- | Constant value structure.
conStrLegend :: CSLegend
conStrLegend :: CSLegend
conStrLegend = CSL :: String -> [(String, String)] -> CSLegend
CSL {
  ttle :: String
ttle = String
conStructTitle,
  symbAndDefs :: [(String, String)]
symbAndDefs = [ ("I", "Constant values are Inlined"),
                  ("WI", "Constants are stored With the Inputs"),
                  ("B", "Constants are stored in variables that are Bundled in a class"),
                  ("U", "Constants are stored in variables that are Unbundled")]
}

-- | Constant value representation.
conRepLegend :: CSLegend
conRepLegend :: CSLegend
conRepLegend = CSL :: String -> [(String, String)] -> CSLegend
CSL {
  ttle :: String
ttle = String
conRepTitle,
  symbAndDefs :: [(String, String)]
symbAndDefs = [ ("V", "Constants are stored as Variables"),
                  ("C", "Constants are stored as Constants")]
}

-- | Real number representation.
realNumRepLegend :: CSLegend
realNumRepLegend :: CSLegend
realNumRepLegend = CSL :: String -> [(String, String)] -> CSLegend
CSL {
  ttle :: String
ttle = String
realNumRepTitle,
  symbAndDefs :: [(String, String)]
symbAndDefs = [ ("D", "Real numbers are represented as Doubles"),
                  ("F", "Real numbers are represented as Floats")]
}

-- * Helper functions to create the case study table rows.
--
-- $helpCSRow
--
-- These functions act like a version of 'show' for each
-- different type of 'Choices', but tweaked to fit inside a table.

getMod :: Modularity -> Sentence
getMod :: Modularity -> Sentence
getMod Unmodular = String -> Sentence
S "U"
getMod (Modular Combined) = String -> Sentence
S "C"
getMod (Modular Separated) = String -> Sentence
S "S"

getImp :: ImplementationType -> Sentence
getImp :: ImplementationType -> Sentence
getImp Program = String -> Sentence
S "P"
getImp Library = String -> Sentence
S "L"

getLog :: [Logging] -> Sentence
getLog :: [Logging] -> Sentence
getLog [] = String -> Sentence
S "NoL"
getLog _ = String -> Sentence
S "L"

getInstr :: Structure -> Sentence
getInstr :: Structure -> Sentence
getInstr Bundled = String -> Sentence
S "B"
getInstr Unbundled = String -> Sentence
S "U"

getConstr :: ConstantStructure -> Sentence
getConstr :: ConstantStructure -> Sentence
getConstr Inline = String -> Sentence
S "I"
getConstr WithInputs = String -> Sentence
S "WI"
getConstr (Store Bundled) = String -> Sentence
S "B"
getConstr (Store Unbundled) = String -> Sentence
S "U"

getConRep :: ConstantRepr -> Sentence
getConRep :: ConstantRepr -> Sentence
getConRep Var = String -> Sentence
S "V"
getConRep Const = String -> Sentence
S "C"

getRealNum :: [CodeType] -> Sentence
getRealNum :: [CodeType] -> Sentence
getRealNum (Double:_) = String -> Sentence
S "D"
getRealNum (Float:_) = String -> Sentence
S "F"
getRealNum _ = String -> Sentence
forall a. HasCallStack => String -> a
error "This shouldn't happen. Make sure Real numbers have a preferred type."