-- | Defines functions used in the Requirements section.
module Drasil.Sections.Requirements (
  -- * Requirements
  reqF, reqInputsRef,
  -- * Functional Requirements
  fReqF,
  -- ** Input Requirements
  fullReqs, fullTables, inReq, inTable,
  mkInputPropsTable, mkQRTuple, mkQRTupleRef, mkValsSourceTable,
  -- * Non-functional Requirements
  nfReqF
  ) where

import Language.Drasil
import Language.Drasil.Chunk.Concept.NamedCombinators
import qualified Language.Drasil.Sentence.Combinators as S

import Data.Drasil.Concepts.Documentation (description, funcReqDom,
  functionalRequirement, input_, nonfunctionalRequirement, {-output_,-} section_,
  software, symbol_, value, reqInput)
import Data.Drasil.Concepts.Math (unit_)

import qualified Drasil.DocLang.SRS as SRS
import Drasil.DocumentLanguage.Units (toSentence)
import Data.List (nub)

import Control.Lens ((^.))
import Data.Bifunctor (bimap)

-- | Wrapper for 'reqIntro'.
reqF :: [Section] -> Section
reqF :: [Section] -> Section
reqF = [Contents] -> [Section] -> Section
SRS.require [Contents
reqIntro]

-- | Prepends a 'ConceptInstance' referencing an input-value table to a list of other 'ConceptInstance's.
-- For listing input requirements.
fullReqs :: (Quantity i, MayHaveUnit i) => [i] -> Sentence -> [ConceptInstance] -> [ConceptInstance]
fullReqs :: [i] -> Sentence -> [ConceptInstance] -> [ConceptInstance]
fullReqs i :: [i]
i d :: Sentence
d r :: [ConceptInstance]
r = [ConceptInstance] -> [ConceptInstance]
forall a. Eq a => [a] -> [a]
nub ([ConceptInstance] -> [ConceptInstance])
-> [ConceptInstance] -> [ConceptInstance]
forall a b. (a -> b) -> a -> b
$ Sentence -> ConceptInstance
inReq (LabelledContent -> Sentence -> Sentence
forall r.
(HasShortName r, Referable r) =>
r -> Sentence -> Sentence
inReqDesc ([i] -> LabelledContent
forall i. (Quantity i, MayHaveUnit i) => [i] -> LabelledContent
inTable [i]
i) Sentence
d) ConceptInstance -> [ConceptInstance] -> [ConceptInstance]
forall a. a -> [a] -> [a]
: [ConceptInstance]
r-- ++ [outReq (outReqDesc outTable)]

-- | Prepends given LabelledContent to an input-value table.
fullTables :: (Quantity i, MayHaveUnit i) => [i] -> [LabelledContent] -> [LabelledContent]
fullTables :: [i] -> [LabelledContent] -> [LabelledContent]
fullTables i :: [i]
i t :: [LabelledContent]
t = [i] -> LabelledContent
forall i. (Quantity i, MayHaveUnit i) => [i] -> LabelledContent
inTable [i]
i LabelledContent -> [LabelledContent] -> [LabelledContent]
forall a. a -> [a] -> [a]
: [LabelledContent]
t

-- | Creates a generalized input-value table for the Requirements section.
inTable :: (Quantity i, MayHaveUnit i) => [i] -> LabelledContent
inTable :: [i] -> LabelledContent
inTable i :: [i]
i = [i] -> ConceptInstance -> LabelledContent
forall i r.
(Quantity i, MayHaveUnit i, HasShortName r, Referable r) =>
[i] -> r -> LabelledContent
mkInputPropsTable [i]
i (Sentence -> ConceptInstance
inReq Sentence
EmptyS) -- passes empty Sentence to make stub of inReq
--outTable    = mkValsSourceTable o "ReqOutputs" (S "Required" +:+ titleize' output_ `follows` (outReq EmptyS))
                                                -- passes empty Sentence to make stub of outReq

-- | Creates a Sentence from a Referable and possible description. Output is of the form
-- "Inputs the values from @reference@, which define @description@". If no description is given,
-- there will be nothing after the word "@reference@".
inReqDesc :: (HasShortName r, Referable r) => r -> Sentence -> Sentence 
inReqDesc :: r -> Sentence -> Sentence
inReqDesc  t :: r
t desc :: Sentence
desc = [Sentence] -> Sentence
foldlSent [NamedChunk -> Sentence
forall n. NamedIdea n => n -> Sentence
atStart NamedChunk
input_,  String -> Sentence
S "the", NamedChunk -> Sentence
forall n. (HasUID n, NamedIdea n) => n -> Sentence
plural NamedChunk
value, String -> Sentence
S "from", Sentence
end]
  where end :: Sentence
end = case Sentence
desc of EmptyS -> r -> Sentence
forall r.
(HasUID r, HasRefAddress r, HasShortName r) =>
r -> Sentence
refS r
t
                           sent :: Sentence
sent   -> r -> Sentence
forall r.
(HasUID r, HasRefAddress r, HasShortName r) =>
r -> Sentence
refS r
t Sentence -> Sentence -> Sentence
`sC` String -> Sentence
S "which define" Sentence -> Sentence -> Sentence
+:+ Sentence
sent
--outReqDesc t = foldlSent [atStart output_, S "the", plural value, S "from", refS t]

-- | Creates a 'ConceptInstance' of input values.
inReq :: Sentence -> ConceptInstance
inReq :: Sentence -> ConceptInstance
inReq  s :: Sentence
s = String -> Sentence -> String -> ConceptChunk -> ConceptInstance
forall c.
Concept c =>
String -> Sentence -> String -> c -> ConceptInstance
cic "inputValues"  Sentence
s "Input-Values"  ConceptChunk
funcReqDom
--outReq s = cic "inputValues" s "Output-Values" funcReqDom

-- | Adds a generalized introduction for a Non-Fucntional Requirements section. Takes in the contents of that section.
fReqF :: [Contents] -> Section
fReqF :: [Contents] -> Section
fReqF listOfFReqs :: [Contents]
listOfFReqs = [Contents] -> [Section] -> Section
SRS.funcReq (Contents
fReqIntro Contents -> [Contents] -> [Contents]
forall a. a -> [a] -> [a]
: [Contents]
listOfFReqs) []

-- | Adds a generalized introduction for a Non-Fucntional Requirements section. Takes in the contents of that section.
nfReqF :: [Contents] -> Section
nfReqF :: [Contents] -> Section
nfReqF nfrs :: [Contents]
nfrs = [Contents] -> [Section] -> Section
SRS.nonfuncReq (Contents
nfReqIntro Contents -> [Contents] -> [Contents]
forall a. a -> [a] -> [a]
: [Contents]
nfrs) []

-- | General 'Sentence' for use in the Requirements section introduction.
reqIntroStart :: Sentence
reqIntroStart :: Sentence
reqIntroStart = [Sentence] -> Sentence
foldlSent_ [String -> Sentence
S "This", NamedChunk -> Sentence
forall n. (HasUID n, NamedIdea n) => n -> Sentence
phrase NamedChunk
section_, String -> Sentence
S "provides"]

-- | General 'Sentence' for use in the Functional Requirements subsection introduction.
frReqIntroBody :: Sentence
frReqIntroBody :: Sentence
frReqIntroBody = [Sentence] -> Sentence
foldlSent_ [NP -> Sentence
forall n. NounPhrase n => n -> Sentence
pluralNP (NamedChunk -> NP
forall t. NamedIdea t => t -> NP
the NamedChunk
functionalRequirement) Sentence -> Sentence -> Sentence
`sC`
  String -> Sentence
S "the tasks and behaviours that the", NamedChunk -> Sentence
forall n. (HasUID n, NamedIdea n) => n -> Sentence
phrase NamedChunk
software, String -> Sentence
S "is expected to complete"]

-- | General 'Sentence' for use in the Non-Functional Requirements subsection introduction.
nfrReqIntroBody :: Sentence
nfrReqIntroBody :: Sentence
nfrReqIntroBody = [Sentence] -> Sentence
foldlSent_ [NP -> Sentence
forall n. NounPhrase n => n -> Sentence
pluralNP (NamedChunk -> NP
forall t. NamedIdea t => t -> NP
the NamedChunk
nonfunctionalRequirement) Sentence -> Sentence -> Sentence
`sC`
  String -> Sentence
S "the qualities that the", NamedChunk -> Sentence
forall n. (HasUID n, NamedIdea n) => n -> Sentence
phrase NamedChunk
software, String -> Sentence
S "is expected to exhibit"]

-- | Generalized Requirements section introduction.
reqIntro :: Contents
reqIntro :: Contents
reqIntro = Sentence -> Contents
mkParagraph (Sentence -> Contents) -> Sentence -> Contents
forall a b. (a -> b) -> a -> b
$ Sentence
reqIntroStart Sentence -> Sentence -> Sentence
+:+. (Sentence
frReqIntroBody Sentence -> Sentence -> Sentence
`sC` Sentence
EmptyS Sentence -> Sentence -> Sentence
`S.and_` Sentence
nfrReqIntroBody)

-- | Generalized Functional Requirements subsection introduction.
fReqIntro :: Contents
fReqIntro :: Contents
fReqIntro = Sentence -> Contents
mkParagraph (Sentence -> Contents) -> Sentence -> Contents
forall a b. (a -> b) -> a -> b
$ Sentence
reqIntroStart Sentence -> Sentence -> Sentence
+:+. Sentence
frReqIntroBody

-- | Generalized Non-Functional Requirements subsection introduction.
nfReqIntro :: Contents
nfReqIntro :: Contents
nfReqIntro = Sentence -> Contents
mkParagraph (Sentence -> Contents) -> Sentence -> Contents
forall a b. (a -> b) -> a -> b
$ Sentence
reqIntroStart Sentence -> Sentence -> Sentence
+:+. Sentence
nfrReqIntroBody

-- | Creates an Input Data Table for use in the Functional Requirments section. Takes a list of wrapped variables and something that is 'Referable'.
mkInputPropsTable :: (Quantity i, MayHaveUnit i, HasShortName r, Referable r) => 
                          [i] -> r -> LabelledContent
mkInputPropsTable :: [i] -> r -> LabelledContent
mkInputPropsTable reqInputs :: [i]
reqInputs req :: r
req = Reference -> RawContent -> LabelledContent
llcc Reference
reqInputsRef (RawContent -> LabelledContent) -> RawContent -> LabelledContent
forall a b. (a -> b) -> a -> b
$ 
  [Sentence] -> [[Sentence]] -> Sentence -> Bool -> RawContent
Table [NamedChunk -> Sentence
forall n. NamedIdea n => n -> Sentence
atStart NamedChunk
symbol_, NamedChunk -> Sentence
forall n. NamedIdea n => n -> Sentence
atStart NamedChunk
description, ConceptChunk -> Sentence
forall n. NamedIdea n => n -> Sentence
atStart' ConceptChunk
unit_]
  ([i -> Sentence] -> [i] -> [[Sentence]]
forall a b. [a -> b] -> [a] -> [[b]]
mkTable [i -> Sentence
forall c. (HasUID c, HasSymbol c) => c -> Sentence
ch, i -> Sentence
forall n. NamedIdea n => n -> Sentence
atStart, i -> Sentence
forall u. MayHaveUnit u => u -> Sentence
toSentence] ([i] -> [[Sentence]]) -> [i] -> [[Sentence]]
forall a b. (a -> b) -> a -> b
$ [i] -> [i]
forall a. HasSymbol a => [a] -> [a]
sortBySymbol [i]
reqInputs)
  (NamedChunk -> Sentence
forall n. NamedIdea n => n -> Sentence
titleize' NamedChunk
reqInput Sentence -> r -> Sentence
forall r.
(Referable r, HasShortName r) =>
Sentence -> r -> Sentence
`follows` r
req) Bool
True

-- | Reference for the Required Inputs table.
reqInputsRef :: Reference
reqInputsRef :: Reference
reqInputsRef = UID -> Reference
makeTabRef' (NamedChunk
reqInput NamedChunk -> Getting UID NamedChunk UID -> UID
forall s a. s -> Getting a s a -> a
^. Getting UID NamedChunk UID
forall c. HasUID c => Lens' c UID
uid)

-- | Creates a table for use in the Functional Requirments section. Takes a list of tuples containing variables and sources, a label, and a caption. 
mkValsSourceTable :: (Quantity i, MayHaveUnit i) => 
                          [(i, Sentence)] -> String -> Sentence -> LabelledContent
mkValsSourceTable :: [(i, Sentence)] -> String -> Sentence -> LabelledContent
mkValsSourceTable vals :: [(i, Sentence)]
vals labl :: String
labl cap :: Sentence
cap = Reference -> RawContent -> LabelledContent
llcc (String -> Reference
makeTabRef String
labl) (RawContent -> LabelledContent) -> RawContent -> LabelledContent
forall a b. (a -> b) -> a -> b
$ 
  [Sentence] -> [[Sentence]] -> Sentence -> Bool -> RawContent
Table [NamedChunk -> Sentence
forall n. NamedIdea n => n -> Sentence
atStart NamedChunk
symbol_, NamedChunk -> Sentence
forall n. NamedIdea n => n -> Sentence
atStart NamedChunk
description, String -> Sentence
S "Source", ConceptChunk -> Sentence
forall n. NamedIdea n => n -> Sentence
atStart' ConceptChunk
unit_]
  ([(i, Sentence) -> Sentence] -> [(i, Sentence)] -> [[Sentence]]
forall a b. [a -> b] -> [a] -> [[b]]
mkTable [i -> Sentence
forall c. (HasUID c, HasSymbol c) => c -> Sentence
ch (i -> Sentence)
-> ((i, Sentence) -> i) -> (i, Sentence) -> Sentence
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (i, Sentence) -> i
forall a b. (a, b) -> a
fst, i -> Sentence
forall n. NamedIdea n => n -> Sentence
atStart (i -> Sentence)
-> ((i, Sentence) -> i) -> (i, Sentence) -> Sentence
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (i, Sentence) -> i
forall a b. (a, b) -> a
fst, (i, Sentence) -> Sentence
forall a b. (a, b) -> b
snd, i -> Sentence
forall u. MayHaveUnit u => u -> Sentence
toSentence (i -> Sentence)
-> ((i, Sentence) -> i) -> (i, Sentence) -> Sentence
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (i, Sentence) -> i
forall a b. (a, b) -> a
fst] ([(i, Sentence)] -> [[Sentence]])
-> [(i, Sentence)] -> [[Sentence]]
forall a b. (a -> b) -> a -> b
$ [(i, Sentence)] -> [(i, Sentence)]
forall a b. HasSymbol a => [(a, b)] -> [(a, b)]
sortBySymbolTuple [(i, Sentence)]
vals) Sentence
cap Bool
True

mkQRTuple :: (Quantity i, MayHaveUnit i, HasShortName i, Referable i) => [i] -> [(QuantityDict, Sentence)]
mkQRTuple :: [i] -> [(QuantityDict, Sentence)]
mkQRTuple = (i -> (QuantityDict, Sentence))
-> [i] -> [(QuantityDict, Sentence)]
forall a b. (a -> b) -> [a] -> [b]
map (\c :: i
c -> (i -> QuantityDict
forall q. (Quantity q, MayHaveUnit q) => q -> QuantityDict
qw i
c, i -> Sentence
forall r.
(HasUID r, HasRefAddress r, HasShortName r) =>
r -> Sentence
refS i
c))

mkQRTupleRef :: (Quantity i, MayHaveUnit i, HasShortName r, Referable r) => [i] -> [r] -> [(QuantityDict, Sentence)]
mkQRTupleRef :: [i] -> [r] -> [(QuantityDict, Sentence)]
mkQRTupleRef = (i -> r -> (QuantityDict, Sentence))
-> [i] -> [r] -> [(QuantityDict, Sentence)]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith (((i, r) -> (QuantityDict, Sentence))
-> i -> r -> (QuantityDict, Sentence)
forall a b c. ((a, b) -> c) -> a -> b -> c
curry ((i -> QuantityDict)
-> (r -> Sentence) -> (i, r) -> (QuantityDict, Sentence)
forall (p :: * -> * -> *) a b c d.
Bifunctor p =>
(a -> b) -> (c -> d) -> p a c -> p b d
bimap i -> QuantityDict
forall q. (Quantity q, MayHaveUnit q) => q -> QuantityDict
qw r -> Sentence
forall r.
(HasUID r, HasRefAddress r, HasShortName r) =>
r -> Sentence
refS))