packages feed

casa-reoc-0.1.0.0: src/ReOC/Render/TrainingManual/Holes.hs

{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
{-# OPTIONS_GHC -Wall #-}

{- | The holes of the RePL training manual. The holes of its markdown
(@template/repl-training-manual.md@) are 'trainingHoles', for the manual,
and 'courseHoles', for each course; their values are markdown. The holes of
its shell (@template/repl-training-manual.fodt@) are the functions
@hole...@, whose values are XML; the shell is only rendered with RePL
training.
-}
module ReOC.Render.TrainingManual.Holes (
  trainingHoles,
  trainingHoleNames,
  courseHoles,
  courseHoleNames,
  courseProperty,
  offered,
  holeCriName,
  holeLegalName,
  holeOrganisationArn,
  holeOrganisationName,
  holeReviewDate,
  holeVersion,
  holeVersionDate,
) where

import Data.Foldable (toList)
import Data.List (nub)
import Data.Text (Text)
import qualified Data.Text as Text
import ReOC.Aircraft (rpaName)
import ReOC.Amendment (manualDate, manualReviewDate, manualVersion)
import ReOC.Model
import ReOC.Personnel (nominatedCEO, nominatedCRI, nominatedCRP)
import ReOC.Render.Markdown (escapeMarkdown)
import ReOC.Render.Text

nameOf :: Nominee -> Text
nameOf =
  formTextText . get (person . fullName)

-- | The holes of the markdown of the manual, by name: each gives markdown.
trainingHoles :: [(Text, ReOC -> TrainingMaterial -> Text)]
trainingHoles =
  map
    (fmap (\f r t -> escapeMarkdown (f r t)))
    [ ("organisation-name", \r _ -> formTextText (get (operator . company . companyName) r))
    , ("legal-name", \r _ -> legalName (get (operator . company) r))
    , ("organisation-arn", \r _ -> arnText (get (operator . company . arn) r))
    , ("version", \r _ -> versionText (manualVersion (get operationsManual r)))
    , ("version-date", \r _ -> monthText (manualDate (get operationsManual r)))
    , ("review-date", \r _ -> monthText (manualReviewDate (get operationsManual r)))
    , ("cri-name", \r t -> nameOf (nominatedCRI (get (operator . keyPersonnel) r) t))
    , ("cri-arn", \r t -> arnText (get (person . arn) (nominatedCRI (get (operator . keyPersonnel) r) t)))
    , ("crp-name", \r _ -> nameOf (nominatedCRP (get (operator . keyPersonnel) r)))
    , ("ceo-name", \r _ -> nameOf (nominatedCEO (get (operator . keyPersonnel) r)))
    , ("independent-review-years", \r _ -> quantity "year" "years" (get (operationsManual . policies . independentReviewYears) r))
    , ("max-students-per-course", \_ t -> showPositive (get (trainingArrangements . maxStudentsPerCourse) t))
    , ("max-students-per-instructor", \_ t -> showPositive (get (trainingArrangements . maxStudentsPerInstructor) t))
    , ("exam-pass-mark", \_ t -> Text.pack (show (passMarkNatural (get (trainingArrangements . examPassMark) t))))
    , ("simulator", \_ t -> maybe "" text1Text (get (trainingArrangements . simulator) t))
    , ("instructor-takeover-method", \_ t -> takeoverText (get (trainingArrangements . takeover) t))
    , ("theory-delivery", \_ t -> theoryText (get (trainingArrangements . theory) t))
    , ("exam-delivery", \r t -> examText (formTextText (get (operator . company . companyName) r)) (get (trainingArrangements . exam) t))
    , ("flight-test-examiner", \_ t -> examinerText (get (trainingArrangements . examiner) t))
    ]
    <> [("training-location-rows", \_ t -> locationRows t)]
 where
  showPositive =
    Text.pack . show . positiveNatural
  takeoverText = \case
    DualControllerLink -> "a dual-controller (trainer) link, in which the instructor’s controller has priority and the instructor can take control with a single switch"
    SharedController -> "a single shared controller, with the instructor standing beside the student within arm’s reach and able to take the controller immediately"
  theoryText = \case
    ClassroomTheory -> "face-to-face classroom instruction"
    BlendedTheory -> "a combination of self-paced study of Part D and face-to-face classroom sessions"
    OnlineTheory -> "live online video instruction, with face-to-face review before the examination"
  examText o = \case
    PaperExamination -> "in person, on paper, at a " <> o <> " training location"
    ComputerExamination -> "in person, on a computer-based examination system at a " <> o <> " training location"
  examinerText = \case
    CRIConductsFlightTests -> "the CRI"
    IndependentExaminerWhereAvailable -> "an examiner other than the instructor who delivered most of the student’s practical training, where one is available, and otherwise by the CRI"

-- The rows of the table of training locations: each place once, with its use.
locationRows :: TrainingMaterial -> Text
locationRows t =
  let theoryPlaces = map text1Text (toList (get (trainingArrangements . theoryVenues) t))
      practical = map text1Text (toList (get (trainingArrangements . practicalAreas) t))
      row p =
        let use = case (p `elem` theoryPlaces, p `elem` practical) of
              (True, True) -> "Theory and practical"
              (True, False) -> "Theory"
              _ -> "Practical"
            notes = if p `elem` practical then "Site assessment and Flight Record IAW operations manual" else "Supervised examination area"
         in "| " <> escapeMarkdown p <> " | " <> use <> " | " <> notes <> " |"
   in Text.intercalate "\n" (map row (nub (theoryPlaces <> practical)))

-- | The names of the holes of the markdown of the manual.
trainingHoleNames :: [Text]
trainingHoleNames =
  map fst trainingHoles

-- The training RPA of a course.
courseRPA :: TrainingCourse -> RPAType
courseRPA =
  get (trainingRPA . rpaType)

-- The weight class of a course: that of its training RPA.
upTo25kg :: TrainingCourse -> Bool
upTo25kg c =
  grossWeightGrams (get maximumGrossWeight (courseRPA c)) > 7000

courseTypeText :: CourseType -> Text
courseTypeText = \case
  InitialCourse -> "Initial"
  UpgradeSameCategory -> "Upgrade (same category)"
  UpgradeDifferentCategory -> "Upgrade (different category)"

complexityText :: Complexity -> Text
complexityText = \case
  AutomatedAndManual -> "automated and manual"
  AutomatedOnly -> "automated only"

-- | The holes of the markdown of each course, by name: each gives markdown.
courseHoles :: [(Text, TrainingCourse -> Text)]
courseHoles =
  map
    (fmap (escapeMarkdown .))
    [ ("course-title", \c -> courseTypeText (get courseKind c) <> " RePL course – " <> categoryOf c <> " " <> weight c <> " (" <> complexityList c <> ")")
    , ("course-type", courseTypeText . get courseKind)
    , ("course-category", categoryOf)
    , ("course-weight-classes", weight)
    , ("course-training-rpa", rpaName . courseRPA)
    , ("course-complexity", complexityList)
    ]
 where
  categoryOf :: TrainingCourse -> Text
  categoryOf = rpaCategoryText . get category . courseRPA
  weight :: TrainingCourse -> Text
  weight c = if upTo25kg c then "up to 25 kg" else "up to 7 kg"
  complexityList :: TrainingCourse -> Text
  complexityList = listing . map complexityText . nub . toList . get complexities

-- | The names of the holes of the markdown of each course.
courseHoleNames :: [Text]
courseHoleNames =
  map fst courseHoles

-- | The values of a course for a key of a condition (see "ReOC.Render.TrainingManual.Markup").
courseProperty :: Text -> TrainingCourse -> [Text]
courseProperty k c =
  case k of
    "category" ->
      [ case get category (courseRPA c) of
          Multirotor -> "multirotor"
          Helicopter -> "helicopter"
          PoweredLift -> "powered-lift"
          Aeroplane -> "aeroplane"
      ]
    "weight" -> [if upTo25kg c then "up-to-25kg" else "up-to-7kg"]
    "complexity" ->
      [ case x of
        AutomatedAndManual -> "automated-and-manual"
        AutomatedOnly -> "automated-only"
      | x <- toList (get complexities c)
      ]
    "course-type" ->
      [ case get courseKind c of
          InitialCourse -> "initial"
          UpgradeSameCategory -> "upgrade-same-category"
          UpgradeDifferentCategory -> "upgrade-different-category"
      ]
    _ -> []

-- | Whether any course has a value for a key of a condition.
offered :: TrainingMaterial -> Text -> Text -> Bool
offered t k v =
  any (elem v . courseProperty k) (toList (get trainingCourses t))

-- The holes of the shell, which is only rendered with RePL training.
withTraining :: (ReOC -> TrainingMaterial -> Text) -> ReOC -> Text
withTraining f r =
  maybe "" (escapeXml . f r) (get maybeTrainingMaterial r)

holeCriName, holeLegalName, holeOrganisationArn, holeOrganisationName, holeReviewDate, holeVersion, holeVersionDate :: ReOC -> Text
holeCriName = withTraining (\r t -> nameOf (nominatedCRI (get (operator . keyPersonnel) r) t))
holeLegalName = escapeXml . legalName . get (operator . company)
holeOrganisationArn = escapeXml . arnText . get (operator . company . arn)
holeOrganisationName = escapeXml . formTextText . get (operator . company . companyName)
holeReviewDate = escapeXml . monthText . manualReviewDate . get operationsManual
holeVersion = escapeXml . versionText . manualVersion . get operationsManual
holeVersionDate = escapeXml . monthText . manualDate . get operationsManual