// used by HasMinValInTU and HasMaxValInTU protected void PrepareMinMaxPar(FunBase fun, List <string> footnoteNumbers) { minMaxVal = fun.GetFootnotePar <ParVarIL>(DefQuery.Par.Val, footnoteNumbers); if (minMaxVal == null) { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = false, message = $"{description.Get()}: compulsory query-parameter {DefQuery.Par.Val} missing" }); } ParBool parUnique = fun.GetFootnotePar <ParBool>(DefQuery.Par.Unique, footnoteNumbers); if (parUnique != null) { minMaxUnique = parUnique.GetBoolValue(); } ParBool parAd = fun.GetFootnotePar <ParBool>(DefQuery.Par.Adults_Only, footnoteNumbers); if (parAd != null) { minMaxAdultsOnly = parAd.GetBoolValue(); } }
// note that at this stage parameters are available (via GetxxxPar-functions of FunBase) // but not yet prepared, i.e. only xmlValue is available internal override void ProvideIndexInfo() { ParBase parName = GetUniquePar <ParBase>(DefPar.DefIl.Name); if (parName == null) { return; } Dictionary <string, double> content = new Dictionary <string, double>(); foreach (var part in GetPlaceholderPar <ParBase>()) { string varILName = part.Key; content.Add(varILName, GetAddMod(part.Value)); // note that vars/ILs are 'registered' (i.e.a.o. checked) in ParIL.CheckAndPrepare (i.e. on 1st use) } ParBool parWarn = GetUniquePar <ParBool>(DefPar.DefIl.Warn_If_NonMonetary); bool warnIfNonMon = parWarn == null?DefinitionAdmin.GetParDefault <bool>(DefFun.DefIl, DefPar.DefIl.Warn_If_NonMonetary) : ParBool.IsTrue(parWarn.xmlValue); // note: GetParBoolValueOrDefault cannot be used as parameter WarnIfNonMon is not yet checked infoStore.operandAdmin.RegisterIL(parName.xmlValue, DefFun.DefIl, description, content, warnIfNonMon); }
/// <summary> /// try to identify parameters and, if valid, generate the respective ParXXX and put into respective lists (see above) /// </summary> private void ClassifyParameters(Dictionary <string, ExeXml.Par> xmlParList, DefinitionAdmin.Fun funDef) { int dummyGroupNumber = -9999; // this is for placeholder-parameters, see below foreach (var xmlPar in xmlParList) { Description parDescription = new Description(description, xmlPar.Value, xmlPar.Key); string xmlParName = xmlPar.Value.Name; // first check if it is an 'ordinary' parameter ... DefinitionAdmin.Par parDef = funDef.GetParDef(xmlParName); if (parDef != null) { string officialParName = funDef.GetOfficalParName(xmlParName); // is (in contrast to xmlParName) case-sensitive and // corresponds to constants as defined in Common-library // generate parameter ... ParBase par = GeneratePar(xmlPar, parDef, parDescription); // ... and put it into the list it belongs too ... if (parDef.isFootnote) // ... footnote-list { if (GetGroupNumber(xmlPar.Value, parDescription, out int dummy)) { if (!footnotePar.ContainsKey(xmlPar.Value.Group)) { footnotePar.Add(xmlPar.Value.Group, new Dictionary <string, ParBase>()); } if (!footnotePar[xmlPar.Value.Group].ContainsKey(officialParName)) { footnotePar[xmlPar.Value.Group].Add(officialParName, par); } else { ReportDoubleDef(parDescription); } } } else if (parDef.maxCount == 1) // ... unique-parameter-list { if (!uniquePar.ContainsKey(officialParName)) { uniquePar.Add(officialParName, par); if (infoStore.runConfig.warnAboutUselessGroups && !string.IsNullOrEmpty(xmlPar.Value.Group)) { ReportUselessGroup(parDescription); } } else { ReportDoubleDef(parDescription); } } else // ... non-unique-parameter-list { if (!nonUniquePar.ContainsKey(officialParName)) { nonUniquePar.Add(officialParName, new List <ParBase>()); } nonUniquePar[officialParName].Add(par); if (infoStore.runConfig.warnAboutUselessGroups && !string.IsNullOrEmpty(xmlPar.Value.Group)) { ReportUselessGroup(parDescription); } } continue; } // ... if not successuful, check if it is a group parameter ... parDef = funDef.GetGroupParDef(xmlParName, out string groupName); if (parDef != null) { if (GetGroupNumber(xmlPar.Value, parDescription, out int groupNo)) { // generate parameter ... ParBase par = GeneratePar(xmlPar, parDef, parDescription); // ... and put it into group-parameter-list if (!groupPar.ContainsKey(groupName)) { groupPar.Add(groupName, new SortedList <int, List <ParBase> >()); } if (!groupPar[groupName].ContainsKey(groupNo)) { groupPar[groupName].Add(groupNo, new List <ParBase>()); } if (parDef.maxCount > 1 || GetUniqueGroupPar <ParBase>(xmlPar.Value.Name, groupPar[groupName][groupNo]) == null) { groupPar[groupName][groupNo].Add(par); } else { ReportDoubleDef(parDescription); } } continue; } // ... if still not successful, it could still be placehoder parameter ... if (funDef.AllowsForPlaceholders()) { parDef = funDef.GetPlaceholderDef(out string phGroupName); ParBase par = GeneratePar(xmlPar, parDef, parDescription, true); if (phGroupName == null) // non-group placeholder, as e.g. in SetDefault, DefIL { if (!placeholderPar.TryAdd(xmlParName, par)) { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = true, message = $" {parDescription.Get()}: {xmlParName} double definition (is ignored)" }); } } else // group placeholder, as e.g. in DefVar (PH, IsGlobal, IsMonetary), Uprate (PH, FactorCond) { GetGroupNumber(xmlPar.Value, parDescription, // note that this returns a dummy-group if the user didn't indicate one out int groupNo, true); // as placeholders only actually need a group if they are "further specified" (e.g. uprating-factors: factor_condition) if (!groupPar.ContainsKey(phGroupName)) { groupPar.Add(phGroupName, new SortedList <int, List <ParBase> >()); } if (!groupPar[phGroupName].ContainsKey(groupNo)) { groupPar[phGroupName].Add(groupNo, new List <ParBase>()); } groupPar[phGroupName][groupNo].Add(par); } continue; } // ... now we give up infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = true, message = $" {parDescription.Get()}: unknown parameter" }); } if (infoStore.runConfig.warnAboutUselessGroups) { foreach (var groupType in groupPar) { if (groupType.Key.ToLower() == DefPar.SchedCalc.Band_XXX.ToLower()) { continue; } foreach (var group in groupType.Value) { if (group.Key >= 0 && group.Value.Count == 1) { ReportUselessGroup(group.Value[0].description); } } } } // internal function for generating parameters ParBase GeneratePar(KeyValuePair <string, ExeXml.Par> xmlPar, DefinitionAdmin.Par parDef, Description parDescription, bool isPlaceholder = false) { ParBase par; switch (parDef.valueType) { case DefPar.PAR_TYPE.FORMULA: par = new ParFormula(infoStore); break; case DefPar.PAR_TYPE.CONDITION: par = new ParCond(infoStore); break; case DefPar.PAR_TYPE.BOOLEAN: par = new ParBool(infoStore); break; case DefPar.PAR_TYPE.NUMBER: par = new ParNumber(infoStore); break; case DefPar.PAR_TYPE.TEXT: par = new ParBase(infoStore); break; case DefPar.PAR_TYPE.VAR: par = new ParVar(infoStore); break; case DefPar.PAR_TYPE.OUTVAR: par = new ParOutVar(infoStore); break; case DefPar.PAR_TYPE.IL: par = new ParIL(infoStore); break; case DefPar.PAR_TYPE.TU: par = new ParTU(infoStore); break; case DefPar.PAR_TYPE.VARorIL: par = new ParVarIL(infoStore); break; case DefPar.PAR_TYPE.CATEG: par = new ParCateg(infoStore, parDef.categValues); break; case DefPar.PAR_TYPE.PLACEHOLDER: par = new ParBase(infoStore); break; default: throw new Exception($"Not yet properly implemented parameter value type {parDef.valueType}"); } par.description = parDescription; par.xmlValue = xmlPar.Value.val; par.description.isPlaceholder = isPlaceholder; return(par); } bool GetGroupNumber(ExeXml.Par p, Description parDescription, out int groupNumber, bool allowDummy = false) { groupNumber = dummyGroupNumber++; // placeholders (e.g.uprating factors) only actually need a group if (string.IsNullOrEmpty(p.Group)) // if they are "further specified" (e.g.factor_condition) { if (allowDummy) { return(true); } infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = false, message = $" {parDescription.Get()}: missing group" }); return(false); } if (int.TryParse(p.Group, out groupNumber)) { return(true); } infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = false, message = $" {parDescription.Get()}: invalid group {p.Group} (must be an integer number)" }); return(false); } void ReportDoubleDef(Description parDescription) { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = false, message = $" {parDescription.Get()}: defined more than once" }); } void ReportUselessGroup(Description parDescription) { if (parDescription.GetFunName() != DefFun.Store) // add a special exception for Store, as it has its own reporting { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = true, message = $" {parDescription.Get()}: group has no use" }); } } }
protected override void PrepareNonCommonPar() { if (!IsRunCondMet()) // note that this works for info that is clearly available at read-time, e.g. {IsUsedDatabase} or {1} { return; // but simply returns true for global variables, which may (in theory) change over run-time } // to handle the latter IsRunCond is called again in the Run-function (see below) // consequently for e.g. {0} the variables are not even generated // while for {$Const}, with $Const=0 at the point of request, the variables exist but are set to 0 // this also reflects the behaviour of the old executable ParBase parSysYear = GetUniquePar <ParBase>(isConst ? DefPar.DefConst.Const_SystemYear : DefPar.DefVar.Var_SystemYear); if (parSysYear != null && !EM_Helpers.DoesValueMatchPattern(parSysYear.xmlValue, infoStore.country.sys.year)) { return; } ParBase parDataSet = GetUniquePar <ParBase>(isConst ? DefPar.DefConst.Const_Dataset : DefPar.DefVar.Var_Dataset); if (parDataSet != null && !infoStore.IsUsedDatabase(parDataSet.xmlValue)) { return; } foreach (var g in GetParGroups(isConst ? DefPar.DefConst.THE_ONLY_GROUP : DefPar.DefVar.THE_ONLY_GROUP)) { List <ParBase> group = g.Value; // global variables (DefConst) allow for parameter Condition (but there is no reason why it wouldn't work for DefVar as well, thus no check) ParCond cond = GetUniqueGroupPar <ParCond>(DefPar.DefConst.Condition, group); List <ParFormula> initFormulas = GetPlaceholderGroupPar <ParFormula>(group); if (initFormulas.Count == 0) // there can be single Monetary parameters if definition is n/a for this system { continue; } if (cond == null && initFormulas.Count > 1) { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = false, message = $"{initFormulas[0].description.Get()}: multiple definition, group {g.Key} is already in use" }); continue; } foreach (ParFormula initFormula in initFormulas) { string varName = initFormula.description.GetParName(); if (!EM_Helpers.IsValidName(varName, out string illegal)) { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = false, message = $"{initFormula.description.Get()}: name contains illegal character(s) '{illegal}'" }); continue; } if (isConst && cond == null && !initFormula.IsGlobal()) { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = true, message = $"{initFormula.description.Get()}: trying to initialise global variable with a non-global amount" }); } bool isMonetary = false; if (!isConst) // variables defined with DefConst cannot be monetary (more precisely, should not be added over TUs) { // if monetary-parameter is defined, use it, otherwise monetary=true (more precisely, get the default value from lib-def) ParBool parMonetary = GetUniqueGroupPar <ParBool>(DefPar.DefVar.Var_Monetary, group); isMonetary = parMonetary != null?parMonetary.GetBoolValue() : DefinitionAdmin.GetParDefault <bool>(funName: DefFun.DefVar, parName: DefPar.DefVar.Var_Monetary); } if (!infoStore.operandAdmin.Exists(varName)) // double definition is not illegal (maybe questionable, but handled like this in old exe) { infoStore.operandAdmin.RegisterVar(name: varName, creatorFun: DefFun.DefVar, description: initFormula.description, isMonetary: isMonetary, isGlobal: isConst && cond == null, isWriteable: true, // DefVar defined variables can be used as output-var (this is a bit lax with DefConst) setInitialised: true); // DefVar defined variables always have an initial value - // if user sets it n/a it does not exist, otherwise she needs to assign a value // actual initialisation is done in the Run function if (!infoStore.operandAdmin.Exists(varName)) { continue; // registration failed } } else if (infoStore.operandAdmin.GetCreatorFun(varName) != DefFun.DefVar && infoStore.operandAdmin.GetCreatorFun(varName) != DefFun.DefConst) { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = false, message = $"{description.Get()} {varName}: {DefFun.DefVar}/{DefFun.DefConst} can only overwrite variables created by (another) {DefFun.DefVar}/{DefFun.DefConst}" }); continue; } // variable cannot yet be initialised, as at this stage the hh-data does not exist (no formula interpretation possible yet) // note on still setting the variable initialised at this stage, in context with the "not-initialised" warning: // parameters are prepared in the spine-order, thus parameters which are prepared before would get a "not known" // and parameters prepared afterwards are "legal" users if (!varDefs.ContainsKey(varName)) { varDefs.Add(varName, new List <VarDef>()); // see definition of varDefs for reason for Dictionary } varDefs[varName].Add(new VarDef() { varSpec = new VarSpec() { name = varName }, initFormula = initFormula, condition = cond, groupNo = g.Key }); } } // a variable can only be defined more than once within one function, if it is conditioned: // only one definition can exist without a condition (which will be used as the default fallback value if conditions also exist) foreach (List <VarDef> condConstDef in varDefs.Values) { if (condConstDef.Count > 1 && (from c in condConstDef where c.condition == null select c).Count() > 1) { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = false, message = $"{description.Get()}: multiple definitions of {condConstDef[0].varSpec.name} without {DefPar.DefConst.Condition} found" }); } } }
protected override void PrepareNonCommonPar() { ParCateg parType = GetUniquePar <ParCateg>(DefPar.DefTu.Type); if (parType != null) { tuType = parType.GetCateg(); } if (tuType != DefPar.Value.TUTYPE_IND) { // get the INCOME used to define the head headDefInc = GetUniquePar <ParVarIL>(DefPar.DefTu.HeadDefInc); if (headDefInc == null) // if no income defined, use ils_origy as default { headDefInc = new ParVarIL(infoStore); headDefInc.xmlValue = infoStore.country.sys.headDefInc == string.Empty ? DefVarName.ILSORIGY : infoStore.country.sys.headDefInc; headDefInc.description = description; headDefInc.CheckAndPrepare(this); } // get all the conditions and set the defaults if they did not exist before if (extHeadCond == null) { extHeadCond = new ParCond(infoStore) { xmlValue = DefPar.DefTu.DEFAULT_CONDITION.EXTHEAD, description = description }; extHeadCond.CheckAndPrepare(this); } } if (partnerCond == null) { partnerCond = new ParCond(infoStore) { xmlValue = DefPar.DefTu.DEFAULT_CONDITION.PARTNER, description = description }; partnerCond.CheckAndPrepare(this); } if (depChildCond == null) { depChildCond = new ParCond(infoStore) { xmlValue = "{0}", description = description }; depChildCond.CheckAndPrepare(this); } if (ownChildCond == null) { ownChildCond = new ParCond(infoStore) { xmlValue = DefPar.DefTu.DEFAULT_CONDITION.OWNCHILD, description = description }; ownChildCond.CheckAndPrepare(this); } if (ownDepChildCond == null) { ownDepChildCond = new ParCond(infoStore) { xmlValue = DefPar.DefTu.DEFAULT_CONDITION.OWNDEPCHILD, description = description }; ownDepChildCond.CheckAndPrepare(this); } if (looseDepChildCond == null) { looseDepChildCond = new ParCond(infoStore) { xmlValue = DefPar.DefTu.DEFAULT_CONDITION.LOOSEDEPCHILD, description = description }; looseDepChildCond.CheckAndPrepare(this); } if (depParentCond == null) { depParentCond = new ParCond(infoStore) { xmlValue = DefPar.DefTu.DEFAULT_CONDITION.DEPPARENT, description = description }; depParentCond.CheckAndPrepare(this); } if (depRelativeCond == null) { depRelativeCond = new ParCond(infoStore) { xmlValue = DefPar.DefTu.DEFAULT_CONDITION.DEPRELATIVE, description = description }; depRelativeCond.CheckAndPrepare(this); } if (loneParentCond == null) { loneParentCond = new ParCond(infoStore) { xmlValue = DefPar.DefTu.DEFAULT_CONDITION.LONEPARENT, description = description }; loneParentCond.CheckAndPrepare(this); } // get all the booleans and set the values ParBool noChildIfHeadPar = GetUniquePar <ParBool>(DefPar.DefTu.NoChildIfHead); noChildIfHead = noChildIfHeadPar != null && noChildIfHeadPar.GetBoolValue(); ParBool noChildIfPartnerPar = GetUniquePar <ParBool>(DefPar.DefTu.NoChildIfPartner); noChildIfPartner = noChildIfPartnerPar != null && noChildIfPartnerPar.GetBoolValue(); ParBool assignDepChOfDependentsPar = GetUniquePar <ParBool>(DefPar.DefTu.AssignDepChOfDependents); assignDepChOfDependents = assignDepChOfDependentsPar != null && assignDepChOfDependentsPar.GetBoolValue(); ParBool assignPartnerOfDependentsPar = GetUniquePar <ParBool>(DefPar.DefTu.AssignPartnerOfDependents); assignPartnerOfDependents = assignPartnerOfDependentsPar != null && assignPartnerOfDependentsPar.GetBoolValue(); ParBool stopIfNoHeadFoundPar = GetUniquePar <ParBool>(DefPar.DefTu.StopIfNoHeadFound); stopIfNoHeadFound = stopIfNoHeadFoundPar != null && stopIfNoHeadFoundPar.GetBoolValue(); ParCateg multiplePartnersPar = GetUniquePar <ParCateg>(DefPar.DefTu.MultiplePartners); multiplePartners = multiplePartnersPar == null ? string.Empty : multiplePartnersPar.GetCateg(); }
protected override void PrepareNonCommonPar() { if (GetParGroups(DefPar.SchedCalc.Band_XXX).Count < 1) { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = false, message = $"{description.Get()}: SchedCalc must have at least one band" }); return; } foreach (KeyValuePair <int, List <ParBase> > bandParList in GetParGroups(DefPar.SchedCalc.Band_XXX)) { Band band = new Band(); // Prepare the Band Limits band.band = bandParList.Key; band.pLowLim = GetUniqueGroupPar <ParFormula>(DefPar.SchedCalc.Band_LowLim, bandParList.Value); if (band.pLowLim != null) // if there is a lowLim { if (band.pLowLim.IsGlobal(true)) { band.lowLim = band.pLowLim.GetGlobalValue(); band.pLowLim = null; } else { doRunTimeLimCheck = true; } } band.pUpLim = GetUniqueGroupPar <ParFormula>(DefPar.SchedCalc.Band_UpLim, bandParList.Value); if (band.pUpLim != null) // if there is a lowLim { if (band.pUpLim.IsGlobal(true)) { band.upLim = band.pUpLim.GetGlobalValue(); band.pUpLim = null; } else { doRunTimeLimCheck = true; } } // Prepare the Band Rate/Amount band.pRate = GetUniqueGroupPar <ParFormula>(DefPar.SchedCalc.Band_Rate, bandParList.Value); band.pAmount = GetUniqueGroupPar <ParFormula>(DefPar.SchedCalc.Band_Amount, bandParList.Value); if (band.pRate != null && band.pAmount != null) // Rate and Amount cannot co-exist { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = false, message = $"{description.Get()}: Rate and Amount cannot co-exist in group {band.band}" }); } if (band.pRate == null && band.pAmount == null) // Rate and Amount cannot both be missing { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = false, message = $"{description.Get()}: Rate and Amount cannot both be missing in group {band.band}" }); } if (band.pRate != null) { if (band.pRate.IsGlobal(true)) { band.rate = band.pRate.GetGlobalValue(); band.pRate = null; } else { doRunTimeRateCheck = true; } } if (band.pAmount != null) { if (band.pAmount.IsGlobal(true)) { band.amount = band.pAmount.GetGlobalValue(); band.pAmount = null; } else { doRunTimeRateCheck = true; } } bands.Add(band); } // check that all required limits exist for (int i = 1; i < bands.Count; i++) { // if both limits are missing then produce an error if (bands[i - 1].upLim == double.MaxValue && bands[i - 1].pUpLim == null && bands[i].lowLim == double.MinValue && bands[i].pLowLim == null) { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = false, message = $"{description.Get()}: Band {bands[i - 1].band}: insufficient definition of upper limit. Use parameters 'band_uplim' or 'band_lowlim'(+1)." }); } // if both limits are there, then produce an error else if ((bands[i - 1].upLim != double.MaxValue || bands[i - 1].pUpLim != null) && (bands[i].lowLim != double.MinValue || bands[i].pLowLim != null)) { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = false, message = $"{description.Get()}: Double definition of upper limit as 'Band_UpLim {bands[i - 1].band}' and 'Band_LowLim {bands[i].band}'." }); } // else, make sure that the upper limit always exist (copy from Group+1 lower limit if required) else if (bands[i - 1].upLim == double.MaxValue && bands[i - 1].pUpLim == null) { if (bands[i].pLowLim == null) { bands[i - 1].upLim = bands[i].lowLim; // copy the litteral limit if it exists } else { bands[i - 1].pUpLim = bands[i].pLowLim; // else copy the parameter to be run at run-time } } } // if possible, check that limits are also in order if (!doRunTimeLimCheck) { CheckGroupLimits(bands); } // prepare the other parameters basePar = GetUniquePar <ParFormula>(DefPar.SchedCalc.Base); if (basePar == null) { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = false, message = $"{description.Get()}: Missing required parameter Base" }); } ParBool doAverageRatesPar = GetUniquePar <ParBool>(DefPar.SchedCalc.Do_Average_Rates); doAverageRates = doAverageRatesPar != null && doAverageRatesPar.GetBoolValue(); ParBool simpleProgPar = GetUniquePar <ParBool>(DefPar.SchedCalc.Simple_Prog); simpleProg = simpleProgPar != null && simpleProgPar.GetBoolValue(); quotientPar = GetUniquePar <ParFormula>(DefPar.SchedCalc.Quotient); if (quotientPar != null) { if (quotientPar.IsGlobal(true)) { quotient = quotientPar.GetGlobalValue(); quotientPar = null; } } baseThresholdPar = GetUniquePar <ParFormula>(DefPar.SchedCalc.BaseThreshold); if (baseThresholdPar != null) { if (baseThresholdPar.IsGlobal(true)) { baseThreshold = baseThresholdPar.GetGlobalValue(); baseThresholdPar = null; } } ParNumber roundBasePar = GetUniquePar <ParNumber>(DefPar.SchedCalc.Round_Base); if (roundBasePar != null) { roundBase = roundBasePar.GetValue(); } }
protected override void PrepareNonCommonPar() { ParVar fv = GetUniquePar <ParVar>(DefPar.AddHHMembers.FlagVar); if (fv != null) { flagVar = new VarSpec() { name = fv.name } } ; foreach (var g in GetParGroups(DefPar.AddHHMembers.GROUP_MAIN)) { var group = g.Value; int groupNo = g.Key; AddInstruction addInstruction = new AddInstruction(); // first find out whether we are adding children or partners or other persons ... ParCateg parWho = GetUniqueGroupPar <ParCateg>(DefPar.AddHHMembers.Add_Who, group); if (parWho == null) { continue; // compulsory parameter, error already issued } addInstruction.addWho = parWho.GetCateg(); // ... depending on that, check the add-condition ParCond parParent = GetUniqueGroupPar <ParCond>(DefPar.AddHHMembers.ParentCond, group); ParCond parPartner = GetUniqueGroupPar <ParCond>(DefPar.AddHHMembers.PartnerCond, group); ParCond parOther = GetUniqueGroupPar <ParCond>(DefPar.AddHHMembers.HHCond, group); string missing = string.Empty; string tooMuch = string.Empty; switch (addInstruction.addWho) { case DefPar.Value.ADDHHMEMBERS_CHILD: if (parParent != null) { addInstruction.cond = parParent; } else { missing = DefPar.AddHHMembers.ParentCond; } if (parPartner != null) { tooMuch = DefPar.AddHHMembers.PartnerCond + " "; } if (parOther != null) { tooMuch = DefPar.AddHHMembers.HHCond; } ParBool parIsPP = GetUniqueGroupPar <ParBool>(DefPar.AddHHMembers.IsPartnerParent, group); if (parIsPP != null) { addInstruction.isPartnerParent = parIsPP.GetBoolValue(); } break; case DefPar.Value.ADDHHMEMBERS_PARTNER: if (parParent != null) { tooMuch = DefPar.AddHHMembers.ParentCond + " "; } if (parPartner != null) { addInstruction.cond = parPartner; } else { missing = DefPar.AddHHMembers.PartnerCond; } if (parOther != null) { tooMuch = DefPar.AddHHMembers.HHCond; } break; case DefPar.Value.ADDHHMEMBERS_OTHER: if (parParent != null) { tooMuch = DefPar.AddHHMembers.ParentCond + " "; } if (parPartner != null) { tooMuch = DefPar.AddHHMembers.PartnerCond; } if (parOther != null) { addInstruction.cond = parOther; } else { missing = DefPar.AddHHMembers.HHCond; } break; default: continue; // error is caught by general error handling } if (missing != string.Empty) { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = false, message = $"{description.Get()} (group {groupNo}): {DefPar.AddHHMembers.Add_Who}={addInstruction.addWho} requires parameter {missing}" }); } if (tooMuch != string.Empty) { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = true, message = $"{description.Get()} (group {groupNo}): {DefPar.AddHHMembers.Add_Who}={addInstruction.addWho} does not require {tooMuch}" }); } // here we are only gathering the variables that are to be set, but do not evaluate whether they exist // note: this function does not "register" variables, i.e. if a variable is not used anywhere else, it cannot be set foreach (ParFormula parVarDefinition in GetPlaceholderGroupPar <ParFormula>(group)) { string varName = parVarDefinition.description.GetParName(); if (addInstruction.prepVarDefinitions.ContainsKey(varName)) { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = false, message = $"{parVarDefinition.description.Get()}: double definition of variable {varName}" }); continue; } if (varName == DefVarName.IDHH || varName == DefVarName.IDPERSON || varName == DefVarName.DWT || varName == DefVarName.DCT) { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = false, message = $"{parVarDefinition.description.Get()}: variable {varName} is system-set and cannot be changed" }); continue; } addInstruction.prepVarDefinitions.Add(varName, parVarDefinition); } addInstructions.Add(addInstruction); } }