-- | Defines an AST to be paired with an ExternalLibrary for a specific use-case
module Language.Drasil.Code.ExternalLibraryCall (ExternalLibraryCall,
  StepGroupFill(..), StepFill(..), FunctionIntFill(..), ArgumentFill(..),
  ParameterFill(..), ClassInfoFill(..), MethodInfoFill(..), externalLibCall,
  choiceStepsFill, choiceStepFill, mandatoryStepFill, mandatoryStepsFill,
  callStepFill, libCallFill, userDefinedArgFill, basicArgFill, functionArgFill,
  customObjArgFill, recordArgFill, unnamedParamFill, unnamedParamPBVFill,
  userDefinedParamFill, customClassFill, implementationFill,
  constructorInfoFill, methodInfoFill, appendCurrSolFill, populateSolListFill,
  assignArrayIndexFill, assignSolFromObjFill, initSolListFromArrayFill,
  initSolListWithValFill, solveAndPopulateWhileFill, returnExprListFill,
  fixedStatementFill, fixedStatementFill', initSolWithValFill
) where

import Language.Drasil.Chunk.Code (CodeVarChunk)
import Language.Drasil.Chunk.Parameter (ParameterChunk, pcAuto, pcVal)
import Language.Drasil.Chunk.NamedArgument (NamedArgument)
import Language.Drasil (CodeExpr)
import Language.Drasil.Mod (Initializer, StateVariable)

import Data.List.NonEmpty (NonEmpty(..), fromList)

-- | External library call holds a group of step groups.
type ExternalLibraryCall = [StepGroupFill]

-- Convention is to end types with "Fill" because they fill in the use-case
-- specific information for an ExternalLibrary

-- This AST mirrors the ExternalLibrary AST by intention.
-- | Holds a group of steps ('StepFill's). The
-- Int is to "choose" from the options in 'ExternalLibrary'.
data StepGroupFill = SGF Int [StepFill]

-- | Mirrors ExternalLibrary's 'Step'. A StepFill can be a call to an external library function or method.
data StepFill = CallF FunctionIntFill
  | LoopF (NonEmpty FunctionIntFill) [CodeExpr] (NonEmpty StepFill)
  | StatementF [CodeVarChunk] [CodeExpr]

-- | Mirrors ExternalLibrary's 'FunctionInterface'.
newtype FunctionIntFill = FIF [ArgumentFill]
-- | Mirrors ExternalLibrary's 'ArgumentInfo'. Determines the context needed for an argument to work.
data ArgumentFill = UserDefinedArgF (Maybe NamedArgument) CodeExpr -- ^ For arguments that are completely dependent on use case.
  | BasicF CodeExpr                                                -- ^ A basic function.
  | FnF [ParameterFill] StepFill                                   -- ^ Fills in the names for the unnamed parameters.
  | ClassF [StateVariable] ClassInfoFill                           -- ^ List of CodeChunk for state variables.
  | RecordF [CodeExpr]                                             -- ^ Fills in the field values.

-- | Mirrors ExternalLibrary's 'Parameter'.
data ParameterFill = NameableParamF ParameterChunk | UserDefined ParameterChunk

-- | Mirrors ExternalLibrary's 'ClassInfo'.
data ClassInfoFill = RegularF [MethodInfoFill] | ImplementsF [MethodInfoFill]

-- | Mirrors ExternalLibrary's 'MethodInfo'.
data MethodInfoFill = CIF [ParameterFill] [Initializer] [StepFill]
  | MIF [ParameterFill] (NonEmpty StepFill)

-- | Constructs an ExternalLibraryCall specification.
externalLibCall :: [StepGroupFill] -> ExternalLibraryCall
externalLibCall :: [StepGroupFill] -> [StepGroupFill]
externalLibCall = [StepGroupFill] -> [StepGroupFill]
forall a. a -> a
id

-- | Corresponds to ExternalLibrary's 'choiceSteps'. Provides the index of the
-- steps that should be used for the current use case.
choiceStepsFill :: Int -> [StepFill] -> StepGroupFill
choiceStepsFill :: Int -> [StepFill] -> StepGroupFill
choiceStepsFill = Int -> [StepFill] -> StepGroupFill
SGF

-- | Corresponds to ExternalLibrary's 'choiceStep'. Provides the index of the
-- step that should be used for the current use case.
choiceStepFill :: Int -> StepFill -> StepGroupFill
choiceStepFill :: Int -> StepFill -> StepGroupFill
choiceStepFill Int
i StepFill
s = Int -> [StepFill] -> StepGroupFill
SGF Int
i [StepFill
s]

-- | Corresponds to ExternalLibrary's 'mandatorySteps'.
mandatoryStepFill :: StepFill -> StepGroupFill
mandatoryStepFill :: StepFill -> StepGroupFill
mandatoryStepFill StepFill
s = Int -> [StepFill] -> StepGroupFill
SGF Int
0 [StepFill
s]

-- | Corresponds to ExternalLibrary's 'mandatoryStep'.
mandatoryStepsFill :: [StepFill] -> StepGroupFill
mandatoryStepsFill :: [StepFill] -> StepGroupFill
mandatoryStepsFill = Int -> [StepFill] -> StepGroupFill
SGF Int
0

-- | Corresponds to ExternalLibrary's 'callStep'.
callStepFill :: FunctionIntFill -> StepFill
callStepFill :: FunctionIntFill -> StepFill
callStepFill = FunctionIntFill -> StepFill
CallF

-- | Corresponds to ExternalLibrary's 'loopStep'.
loopStepFill :: [FunctionIntFill] -> [CodeExpr] -> [StepFill] -> StepFill
loopStepFill :: [FunctionIntFill] -> [CodeExpr] -> [StepFill] -> StepFill
loopStepFill [] [CodeExpr]
_ [StepFill]
_ = [Char] -> StepFill
forall a. HasCallStack => [Char] -> a
error [Char]
"loopStepFill should be called with a non-empty list of FunctionInterfaceFill"
loopStepFill [FunctionIntFill]
_ [CodeExpr]
_ [] = [Char] -> StepFill
forall a. HasCallStack => [Char] -> a
error [Char]
"loopStepFill should be called with a non-empty list of StepFill"
loopStepFill [FunctionIntFill]
fifs [CodeExpr]
cdchs [StepFill]
sfs = NonEmpty FunctionIntFill
-> [CodeExpr] -> NonEmpty StepFill -> StepFill
LoopF ([FunctionIntFill] -> NonEmpty FunctionIntFill
forall a. HasCallStack => [a] -> NonEmpty a
fromList [FunctionIntFill]
fifs) [CodeExpr]
cdchs ([StepFill] -> NonEmpty StepFill
forall a. HasCallStack => [a] -> NonEmpty a
fromList [StepFill]
sfs)

-- | Corresponds to any of ExternalLibrary's 'FunctionInterface' constructors.
libCallFill :: [ArgumentFill] -> FunctionIntFill
libCallFill :: [ArgumentFill] -> FunctionIntFill
libCallFill = [ArgumentFill] -> FunctionIntFill
FIF

-- | Does not correspond to anything in ExternalLibrary. To be used when the
-- presence of an argument is only a consequence of the use case.
userDefinedArgFill :: CodeExpr -> ArgumentFill
userDefinedArgFill :: CodeExpr -> ArgumentFill
userDefinedArgFill = Maybe NamedArgument -> CodeExpr -> ArgumentFill
UserDefinedArgF Maybe NamedArgument
forall a. Maybe a
Nothing

-- | Corresponds to ExternalLibrary's 'inlineArg', 'inlineNamedArg', 'preDefinedArg',
-- and 'preDefinedNamedArg'. Provides the 'CodeExpr' for the argument's value.
basicArgFill :: CodeExpr -> ArgumentFill
basicArgFill :: CodeExpr -> ArgumentFill
basicArgFill = CodeExpr -> ArgumentFill
BasicF

-- | Corresponds to ExternalLibrary's 'functionArg'.
functionArgFill :: [ParameterFill] -> StepFill -> ArgumentFill
functionArgFill :: [ParameterFill] -> StepFill -> ArgumentFill
functionArgFill = [ParameterFill] -> StepFill -> ArgumentFill
FnF

-- | Corresponds to ExternalLibrary's 'customObjArg'. Provides the list of state
-- variables for the class that must be written in the calling program.
customObjArgFill :: [StateVariable] -> ClassInfoFill -> ArgumentFill
customObjArgFill :: [StateVariable] -> ClassInfoFill -> ArgumentFill
customObjArgFill = [StateVariable] -> ClassInfoFill -> ArgumentFill
ClassF

-- | Corresponds to ExternalLibrary's 'recordArg'. Provides the list of 'CodeExpr's for
-- the values of the fields that must be set by the calling program.
recordArgFill :: [CodeExpr] -> ArgumentFill
recordArgFill :: [CodeExpr] -> ArgumentFill
recordArgFill = [CodeExpr] -> ArgumentFill
RecordF

-- | Corresponds to ExternalLibrary's 'unnamedParam'. Provides the 'CodeVarChunk'
-- representing the parameter.
unnamedParamFill :: CodeVarChunk -> ParameterFill
unnamedParamFill :: CodeVarChunk -> ParameterFill
unnamedParamFill = ParameterChunk -> ParameterFill
NameableParamF (ParameterChunk -> ParameterFill)
-> (CodeVarChunk -> ParameterChunk)
-> CodeVarChunk
-> ParameterFill
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CodeVarChunk -> ParameterChunk
forall c. CodeIdea c => c -> ParameterChunk
pcAuto

-- | Corresponds to ExternalLibrary's 'unnamedParam'. Provides the 'CodeVarChunk'
-- representing the parameter. Specifies that the parameter is passed by value.
unnamedParamPBVFill :: CodeVarChunk -> ParameterFill
unnamedParamPBVFill :: CodeVarChunk -> ParameterFill
unnamedParamPBVFill = ParameterChunk -> ParameterFill
NameableParamF (ParameterChunk -> ParameterFill)
-> (CodeVarChunk -> ParameterChunk)
-> CodeVarChunk
-> ParameterFill
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CodeVarChunk -> ParameterChunk
forall c. CodeIdea c => c -> ParameterChunk
pcVal

-- | Does not correspond to anything in ExternalLibrary. To be used when the
-- presence of a parameter is only a consequence of the use case.
userDefinedParamFill :: CodeVarChunk -> ParameterFill
userDefinedParamFill :: CodeVarChunk -> ParameterFill
userDefinedParamFill = ParameterChunk -> ParameterFill
UserDefined (ParameterChunk -> ParameterFill)
-> (CodeVarChunk -> ParameterChunk)
-> CodeVarChunk
-> ParameterFill
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CodeVarChunk -> ParameterChunk
forall c. CodeIdea c => c -> ParameterChunk
pcAuto

-- | Corresponds to ExternalLibrary's 'customClass'.
customClassFill :: [MethodInfoFill] -> ClassInfoFill
customClassFill :: [MethodInfoFill] -> ClassInfoFill
customClassFill = [MethodInfoFill] -> ClassInfoFill
RegularF

-- | Corresponds to ExternalLibrary's 'implementation'.
implementationFill :: [MethodInfoFill] -> ClassInfoFill
implementationFill :: [MethodInfoFill] -> ClassInfoFill
implementationFill = [MethodInfoFill] -> ClassInfoFill
ImplementsF

-- | Corresponds to ExternalLibrary's 'constructorInfo'. Provides Variable-Value
-- pairs for variables initialized by the constructor.
constructorInfoFill :: [ParameterFill] -> [Initializer] -> [StepFill] ->
  MethodInfoFill
constructorInfoFill :: [ParameterFill] -> [Initializer] -> [StepFill] -> MethodInfoFill
constructorInfoFill = [ParameterFill] -> [Initializer] -> [StepFill] -> MethodInfoFill
CIF

-- | Corresponds to ExternalLibrary's 'methodInfo'.
methodInfoFill :: [ParameterFill] -> [StepFill] -> MethodInfoFill
methodInfoFill :: [ParameterFill] -> [StepFill] -> MethodInfoFill
methodInfoFill [ParameterFill]
_ [] = [Char] -> MethodInfoFill
forall a. HasCallStack => [Char] -> a
error [Char]
"methodInfoFill should be called with non-empty list of StepFill"
methodInfoFill [ParameterFill]
pfs [StepFill]
sfs = [ParameterFill] -> NonEmpty StepFill -> MethodInfoFill
MIF [ParameterFill]
pfs ([StepFill] -> NonEmpty StepFill
forall a. HasCallStack => [a] -> NonEmpty a
fromList [StepFill]
sfs)

-- | Corresponds to ExternalLibrary's 'appendCurrSol'. Provides the 'CodeVarChunk'
-- for the solution list.
appendCurrSolFill :: CodeVarChunk -> StepFill
appendCurrSolFill :: CodeVarChunk -> StepFill
appendCurrSolFill CodeVarChunk
s = [CodeVarChunk] -> [CodeExpr] -> StepFill
statementStepFill [CodeVarChunk
s] []

-- | Corresponds to ExternalLibrary's 'populateSolList'. Provides the 'CodeVarChunk'
-- for the solution list.
populateSolListFill :: CodeVarChunk -> [StepFill]
populateSolListFill :: CodeVarChunk -> [StepFill]
populateSolListFill CodeVarChunk
s = Int -> StepFill -> [StepFill]
forall a. Int -> a -> [a]
replicate Int
2 ([CodeVarChunk] -> [CodeExpr] -> StepFill
statementStepFill [CodeVarChunk
s] [])

-- | Corresponds to ExternalLibrary's 'assignArrayIndex'. Provides the 'CodeVarChunk'
-- for the array variable. Provides the 'CodeExpr's for the values to assign to each
-- array index.
assignArrayIndexFill :: CodeVarChunk-> [CodeExpr] -> StepFill
assignArrayIndexFill :: CodeVarChunk -> [CodeExpr] -> StepFill
assignArrayIndexFill CodeVarChunk
a = [CodeVarChunk] -> [CodeExpr] -> StepFill
statementStepFill [CodeVarChunk
a]

-- | Corresponds to ExternalLibrary's 'assignSolFromObj'. Provides the 'CodeVarChunk'
-- for the variable that the solution should be assigned to.
assignSolFromObjFill :: CodeVarChunk -> StepFill
assignSolFromObjFill :: CodeVarChunk -> StepFill
assignSolFromObjFill CodeVarChunk
s = [CodeVarChunk] -> [CodeExpr] -> StepFill
statementStepFill [CodeVarChunk
s] []

-- | Corresponds to ExternalLibrary's 'initSolListFromArray'. Provides the
-- 'CodeVarChunk' for the solution list.
initSolListFromArrayFill :: CodeVarChunk -> StepFill
initSolListFromArrayFill :: CodeVarChunk -> StepFill
initSolListFromArrayFill CodeVarChunk
s = [CodeVarChunk] -> [CodeExpr] -> StepFill
statementStepFill [CodeVarChunk
s] []

-- | Corresponds to ExternalLibrary's 'initSolListWithVal'. Provides the
-- 'CodeVarChunk' for the solution list and the 'CodeExpr' for the initial element of
-- the solution list
initSolListWithValFill :: CodeVarChunk -> CodeExpr -> StepFill
initSolListWithValFill :: CodeVarChunk -> CodeExpr -> StepFill
initSolListWithValFill CodeVarChunk
s CodeExpr
v = [CodeVarChunk] -> [CodeExpr] -> StepFill
statementStepFill [CodeVarChunk
s] [CodeExpr
v]

-- | Corresponds to ExternalLibrary's 'solveAndPopulateWhile'. Provides the 'CodeExpr'
-- for the upper bound in the while loop condition and the 'CodeVarChunk' for the
-- solution list.
solveAndPopulateWhileFill :: FunctionIntFill -> CodeExpr -> FunctionIntFill ->
  CodeVarChunk -> StepFill
solveAndPopulateWhileFill :: FunctionIntFill
-> CodeExpr -> FunctionIntFill -> CodeVarChunk -> StepFill
solveAndPopulateWhileFill FunctionIntFill
lcf CodeExpr
ub FunctionIntFill
slvf CodeVarChunk
s = [FunctionIntFill] -> [CodeExpr] -> [StepFill] -> StepFill
loopStepFill [FunctionIntFill
lcf] [CodeExpr
ub]
  [FunctionIntFill -> StepFill
callStepFill FunctionIntFill
slvf, CodeVarChunk -> StepFill
appendCurrSolFill CodeVarChunk
s]

-- | Corresponds to ExternalLibrary's 'returnExprList'. Provides the list of 'CodeExpr's
-- to return.
returnExprListFill :: [CodeExpr] -> StepFill
returnExprListFill :: [CodeExpr] -> StepFill
returnExprListFill = [CodeVarChunk] -> [CodeExpr] -> StepFill
statementStepFill []

-- | Corresponds to ExternalLibrary's 'statementStep'. Provides the
-- use-case-specific 'CodeVarChunk's and 'CodeExpr's that parameterize the statement.
statementStepFill :: [CodeVarChunk] -> [CodeExpr] -> StepFill
statementStepFill :: [CodeVarChunk] -> [CodeExpr] -> StepFill
statementStepFill = [CodeVarChunk] -> [CodeExpr] -> StepFill
StatementF

-- | Corresponds to ExternalLibrary's 'fixedReturn'.
-- No parameters because the statement is not use-case-dependent.
fixedStatementFill :: StepFill
fixedStatementFill :: StepFill
fixedStatementFill = [CodeVarChunk] -> [CodeExpr] -> StepFill
StatementF [] []

-- | Corresponds to ExternalLibrary's 'fixedReturn''.
-- use-case-specific a 'CodeExpr' that parameterize the statement.
fixedStatementFill' :: CodeExpr -> StepFill
fixedStatementFill' :: CodeExpr -> StepFill
fixedStatementFill' CodeExpr
a = [CodeVarChunk] -> [CodeExpr] -> StepFill
StatementF [] [CodeExpr
a]

-- | Corresponds to ExternalLibrary's 'initSolWithVal'. Provides the
-- 'CodeVarChunk' for one solution and one 'CodeExpr' for the initial element of
-- the solution list
initSolWithValFill :: CodeVarChunk -> CodeExpr -> StepFill
initSolWithValFill :: CodeVarChunk -> CodeExpr -> StepFill
initSolWithValFill CodeVarChunk
s CodeExpr
v = [CodeVarChunk] -> [CodeExpr] -> StepFill
statementStepFill [CodeVarChunk
s] [CodeExpr
v]