private void ReadInfo(ExeXml.Fun fun, string funId, out Dictionary <string, Tuple <string, string> > changes, out ExeXml.Par parRunCond, out List <ExeXml.Par> parDatabaseName) { parRunCond = null; parDatabaseName = new List <ExeXml.Par>(); changes = new Dictionary <string, Tuple <string, string> >(); // key: group, value.item1: fun/pol-ident, value.item2: on/off foreach (var par in fun.pars.Values) { if (par.Name.ToLower() == DefPar.Common.Run_Cond.ToLower()) // Run_Cond = { xxx } { parRunCond = par; } else if (par.Name.ToLower() == DefQuery.Par.DataBasename.ToLower()) // #_DatabaseName is the only footnote-parameter possible { parDatabaseName.Add(par); // for global conditions (i.e. the Run_Cond) } else if (par.Name.ToLower() == DefPar.ChangeSwitch.PolFun.ToLower()) // PolFun = Guid / PolFun = policy-name { AddToChangeList(changes, par.Group, par.val, false, funId); } else if (par.Name.ToLower() == DefPar.ChangeSwitch.Switch_NewVal.ToLower()) // SwitchNewVal = on/off { AddToChangeList(changes, par.Group, par.val, true, funId); } else { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = false, message = $"Change switch ({funId}): unknown parameter {par.Name}" }); } } if (parRunCond == null) { return; } // make sure that footnote-parameters (i.e. #_DatabasName) do not get into conflict with existing footnote-parameters (i.e. same group) List <int> replaceGroups = new List <int>(); foreach (ExeXml.Par parDB in parDatabaseName) { if (!int.TryParse(parDB.Group, out int g)) { continue; // ignore this rather unlikely case (just keep the strange group) } parDB.Group = GetNewGroup(g).ToString(); replaceGroups.Add(g); } replaceGroups.Sort(); replaceGroups.Reverse(); // avoid replacing ...#1...#12... with ...#9901...#99012... foreach (int group in replaceGroups) // and hope there is no #9 { parRunCond.val = parRunCond.val.Replace($"#{group}", $"#{GetNewGroup(group)}"); } int GetNewGroup(int group) { return(group + 9900); } }
private ExeXml.Fun CloneFun(ExeXml.Fun fun) { ExeXml.Fun clone = new ExeXml.Fun { Name = fun.Name, on = fun.on, order = fun.order }; foreach (ExeXml.Par par in fun.pars.Values) { ExeXml.Par clonePar = new ExeXml.Par() { Name = par.Name, Group = par.Group, order = par.order, val = par.val }; clone.pars.Add(Guid.NewGuid().ToString(), clonePar); } return(clone); }
private bool FindFun(string funID, Dictionary <string, ExeXml.Pol> pols, Description description, out ExeXml.Fun foundFun, out ExeXml.Pol parentPol) { foreach (ExeXml.Pol pol in pols.Values) { if (pol.funs.ContainsKey(funID)) { foundFun = pol.funs[funID]; parentPol = pol; return(true); } } infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = false, message = $"{description.Get()}: unknown function-id {funID}" }); foundFun = null; parentPol = null; return(false); }
private void IntegratePar(ExeXml.Fun addOnPar, Description funDescription) { string insertFunID = null; Dictionary <string, ExeXml.Par> parToAdd = new Dictionary <string, ExeXml.Par>(); // interpret the parameters of the AddOn_Par function foreach (var p in addOnPar.pars) { if (p.Value.val == DefPar.Value.NA) { continue; } if (p.Value.Name.ToLower() == DefPar.AddOn_Par.Insert_Func.ToLower()) { insertFunID = p.Value.val; } else { parToAdd.Add(p.Key, p.Value); // any other parameter is an add-on-parameter (i.e. should be added to the insert-function) } } // check for the only compulsory parameter if (insertFunID == null) { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = false, message = $"{funDescription.Get()}: parameter {DefPar.AddOn_Par.Insert_Func} not defined" }); return; } // find the insert-function in the country file if (!FindFun(insertFunID, infoStore.country.cao.pols, funDescription, out ExeXml.Fun insertFun, out ExeXml.Pol dummy)) { return; } // add the parameters to the insert-function (note: order of parameters is irrelevant for the executable) insertFun.pars.AddRange(parToAdd); }
// implementation of new function ChangeSwitch, which partly replaces run-time changes of ChangeParam (see ApplyChangeParam) // parameters provided: // - optional parameter RunCond (if present: run-time switch-change, if not present: read-time switch-change) // - parameters for switching on/off policies/functions: // parameter-group: PolFun: id/name of policy/function // SwitchNewVal: on/off // examples: Run_Cond = { $ScenarioX = 1 }, PolFun (Group 1) = bsa_cy, NewSwitch (Group 1) = off, // PolFun (Group 2) = A18317A2-25AC-4E58-AFA2-92E80623550F, NewSwitch (Group 2) = on // (in an AddOn:) Run_Cond = { $Sum_xyz > 100 }, PolFun (Group 1) = tco_cy, NewSwitch (Group 1) = off, // PolFun (Group 2) = tin_cy#1, NewSwitch (Group 2) = off // (note: symbolic IDs are already replaced at this stage(by add-on integration)) private void ApplyChangeSwitch() { foreach (var cs in GetSpecificFuns(DefFun.ChangeSwitch)) { ExeXml.Fun fun = cs.Value; string funId = cs.Key; // gather the information by reading parameters: there may be a Run_Cond (optional), // the other parameters are a list of switch changes, defined by the parameters PolFun (=id) and SwitchNewVal (=on/off) ReadInfo(fun, funId, out Dictionary <string, Tuple <string, string> > changes, out ExeXml.Par parRunCond, out List <ExeXml.Par> parDatabaseName); // gather the functions which are affected by the switch-changes (i.e. all functions of a policy or a specific function) // and check for unknown ids or invalid switches CheckInfo(funId, changes, out Dictionary <ExeXml.Fun, bool> switchInfo); // apply the switch changes, taking run-cond into account ApplyInfo(switchInfo, parRunCond, parDatabaseName); // finally, switch ChangeSwitch-function off: thus DropOff will delete it fun.on = false; } }
// important note on new handling of ChangeParam: // - ChangeParam will only allow for read-time changes and does not allow for changing switches anymore // - a new function ChangeSwitch will allow for changing switches of policies/functions at run- or read-time // // justification: // - the only reason for run-time parameter changes are loops: // as far as I can see this option is only used by MTR and LMA to switch policies/functions on/off // - other applications just 'misuse' Param_CondVal (AT, BE), i.e. they do not provide a RunCond and thus c(sh)ould use Param_NewVal // (e.g. AT switches stuff off for SORESI, in a ChangeParam located in a policy that is only on for SORESI) // // actual reason for the abolishment: // full application of run-time parameter changes is very complex (close to impossible, consider e.g. formula-interpretation ...) // changes to old ChangeParam: // - parameter Param_CondVal is abolished (i.e. no run-time changes anymore - but see ApplyChangeSwitch), // respectively renamed to Param_NewVal where the change actually concerns a read-time-change // - parameter RunCond is abolished, respectively replaced by // - parameter Database (non-unique): usage like in Uprate/SetDefault, except not provided means apply for any dataset here // examples: Database = sk_2019, Param_Id = 9ac9d5e6-bbfe-4e5c-a87e-940b33a5457e, Param_NewVal = adp*0.5 (e.g. if adp exists only in this data) // (in an AddOn:) Param_Id = yem_sk_#2.1, Param_NewVal = { dag <= 6 } // (note: symbolic IDs are already replaced at this stage (by add-on integration)) private void ApplyChangeParam() { foreach (var cp in GetSpecificFuns(DefFun.ChangeParam)) { ExeXml.Fun cpFun = cp.Value; string cpFunId = cp.Key; // gather the information (consisting of whether the function applies to the current dataset and the list of changes) Dictionary <string, Tuple <string, string> > changeList = new Dictionary <string, Tuple <string, string> >(); List <string> applyDatasets = new List <string>(); foreach (ExeXml.Par par in cpFun.pars.Values) { if (par.Name.ToLower() == DefPar.ChangeParam.Dataset.ToLower()) { applyDatasets.Add(par.val); } else if (par.Name.ToLower() == DefPar.ChangeParam.Param_Id.ToLower()) { AddToChangeList(changeList, par.Group, par.val, false, cpFunId); } else if (par.Name.ToLower() == DefPar.ChangeParam.Param_NewVal.ToLower()) { AddToChangeList(changeList, par.Group, par.val, true, cpFunId); } else { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = false, message = $"Change param ({cpFunId}): unknown parameter {par.Name}" }); } } // check if the ChangeParam applies to the currently used dataset bool applies = applyDatasets.Count == 0; // if there is no Dataset parameter the change applies (see explanation above) foreach (string dataName in applyDatasets) { if (infoStore.IsUsedDatabase(dataName)) { applies = true; break; } } if (applies) { // check if the IDs exist and (if yes) apply the changes foreach (var change in changeList) // remark: if there are many changes, it may be more efficient to { // loop only once over all pars, but I assume that's not very likely string group = change.Key, changeId = change.Value.Item1, changeNewVal = change.Value.Item2; if (changeId == null || changeNewVal == null) { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = false, message = $"Change param ({cpFunId}): insufficient definition of group {group}" }); continue; } bool found = false; foreach (var pol in infoStore.country.cao.pols.Values) { foreach (var fun in pol.funs.Values) { if (fun.pars.ContainsKey(changeId)) { fun.pars[changeId].val = changeNewVal; found = true; break; } if (found) { break; } } if (found) { break; } } if (!found) { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = false, message = $"Change param ({cpFunId}): parameter id {changeId} not found" }); } } } // finally, switch ChangeParam-function off: thus DropOff will delete it cpFun.on = false; } }
internal Description(Description parDesc, string _queryName) { pol = parDesc.pol; fun = parDesc.fun; funID = parDesc.funID; par = parDesc.par; parID = parDesc.parID; queryName = _queryName; }
internal Description(Description funDesc, ExeXml.Par _par, string _parID = null) { pol = funDesc.pol; fun = funDesc.fun; funID = funDesc.funID; par = _par; parID = _parID; }
internal bool isPlaceholder = false; // is relevant for e.g. FunDefVar and FunDefUprate (see FunBase.GetPlaceholderGroupPar) internal Description(ExeXml.Pol _pol, ExeXml.Fun _fun, string _funID = null) { pol = _pol; fun = _fun; funID = _funID; }
private void CheckAndPrepare() { Dictionary <double, ExeXml.Fun> allFun = new Dictionary <double, ExeXml.Fun>(); // key: order - necessary to do TakePar in spine-order, see below // 1st STEP: IDENTIFY FUNCTIONS foreach (var pol in infoStore.country.cao.pols) // policies are only function-containers, not relevant for the run { // (except from perhaps error-reporting) foreach (var f in pol.Value.funs) { ExeXml.Fun xmlFun = f.Value; string funID = f.Key; Description funDescription = new Description(pol.Value, xmlFun, funID); string funName = xmlFun.Name.ToLower(); double order = GetOrder(pol.Value.order, xmlFun.order); bool recognised = true; if (funName == DefFun.ArithOp.ToLower()) { infoStore.spine.Add(order, new FunArithOp(infoStore)); } else if (funName == DefFun.Elig.ToLower()) { infoStore.spine.Add(order, new FunElig(infoStore)); } else if (funName == DefFun.BenCalc.ToLower()) { infoStore.spine.Add(order, new FunBenCalc(infoStore)); } else if (funName == DefFun.SchedCalc.ToLower()) { infoStore.spine.Add(order, new FunSchedCalc(infoStore)); } else if (funName == DefFun.Min.ToLower()) { infoStore.spine.Add(order, new FunMin(infoStore)); } else if (funName == DefFun.Max.ToLower()) { infoStore.spine.Add(order, new FunMax(infoStore)); } else if (funName == DefFun.Allocate.ToLower()) { infoStore.spine.Add(order, new FunAllocate(infoStore)); } else if (funName == DefFun.DefVar.ToLower()) { infoStore.spine.Add(order, new FunDefVar(infoStore, false)); } else if (funName == DefFun.DefConst.ToLower()) { infoStore.spine.Add(order, new FunDefVar(infoStore, true)); } else if (funName == DefFun.DefIl.ToLower()) { infoStore.spine.Add(order, new FunDefIL(infoStore)); } else if (funName == DefFun.Store.ToLower()) { infoStore.spine.Add(order, new FunStore(infoStore)); } else if (funName == DefFun.Restore.ToLower()) { infoStore.spine.Add(order, new FunRestore(infoStore)); } else if (funName == DefFun.IlVarOp.ToLower()) { infoStore.spine.Add(order, new FunILVarOp(infoStore)); } else if (funName == DefFun.RandSeed.ToLower()) { infoStore.spine.Add(order, new FunRandSeed(infoStore)); } else if (funName == DefFun.CallProgramme.ToLower()) { infoStore.spine.Add(order, new FunCallProgramme(infoStore)); } else if (funName == DefFun.DefInput.ToLower()) { infoStore.spine.Add(order, new FunDefInput(infoStore)); } else if (funName == DefFun.DefTu.ToLower()) { infoStore.spine.Add(order, new FunDefTU(infoStore)); } else if (funName == DefFun.UpdateTu.ToLower()) { infoStore.spine.Add(order, new FunUpdateTU(infoStore)); } else if (funName == DefFun.Uprate.ToLower()) { infoStore.spine.Add(order, new FunUprate(infoStore)); } else if (funName == DefFun.SetDefault.ToLower()) { infoStore.spine.Add(order, new FunSetDefault(infoStore)); } else if (funName == DefFun.DefOutput.ToLower()) { infoStore.spine.Add(order, new FunDefOutput(infoStore)); } else if (funName == DefFun.Loop.ToLower()) { infoStore.spine.Add(order, new FunLoop(infoStore)); } else if (funName == DefFun.UnitLoop.ToLower()) { infoStore.spine.Add(order, new FunUnitLoop(infoStore)); } else if (funName == DefFun.Totals.ToLower()) { infoStore.spine.Add(order, new FunTotals(infoStore)); } else if (funName == DefFun.Scale.ToLower()) { infoStore.spine.Add(order, new FunScale(infoStore)); } else if (funName == DefFun.DropUnit.ToLower()) { infoStore.spine.Add(order, new FunDropKeepUnit(infoStore, false)); } else if (funName == DefFun.KeepUnit.ToLower()) { infoStore.spine.Add(order, new FunDropKeepUnit(infoStore, true)); } else if (funName == DefFun.AddHHMembers.ToLower()) { infoStore.spine.Add(order, new FunAddHHMembers(infoStore)); } else if (funName == DefFun.IlArithOp.ToLower()) { infoStore.spine.Add(order, new FunIlArithOp(infoStore)); } else { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = true, message = $"Unkown function is ignored: {funDescription.Get()}" }); recognised = false; } // identification of parameters is moved below, to be done in spine-order (this is at the stage of moving only necessary for FunScale) //if (recognised) infoStore.spine[order].TakePar(funDescription, xmlFun.pars); if (recognised) { infoStore.spine[order].description = funDescription; allFun.Add(order, f.Value); } } } // 2nd STEP: IDENTIFY (KNOWN) PARAMETERS AND CHECK FOR COMPLETENESS foreach (var f in infoStore.spine) { f.Value.TakePar(f.Value.description, allFun[f.Key].pars); } // 3rd STEP: PUT TUs, VARIABLES, QUERIES, LOOPS, etc. (i.e. stuff that's used by other parameters) INTO RESPECTIVE INDICES foreach (FunBase fun in infoStore.spine.Values) { fun.ProvideIndexInfo(); } // 4th STEP: ANALYSE PARAMETER-VALUES foreach (FunBase fun in infoStore.spine.Values) { if (fun.description.GetFunName().ToLower() != DefFun.DefTu.ToLower()) // for DefTU this function is called by ParTU, i.e. { fun.CheckAndPrepare(); // on first usage (see ParTU for futher explanation) } } }
private void HandleExtensionSwitches(List <ExeXml.AddOn> addOns) { // first overwrite the default switch settings in the country file, if the user changed them (via config-settings sent by the run-tool) TakeExtensionSwitches(infoStore.runConfig.extensionSwitches); // then overwrite with any instructions from extensions, the means the priority of switches to be on or off is as follows: // highest: add-ons (via AddOn_ExtensionSwitch), next: user settings (via run-tool), lowest: default settings (via set-switches-dialog) TakeAddOnExtensionSwitches(addOns); // take care of a "feature" that is mainly there for compatibility with the version before March 2020, where the switches of functions within extension-policies were visible instead of set to switch // namly that such functions can be permanantly off instead of switchable List <ExeXml.Fun> permanentOffFunctions = TakeCareOfPermanentOffFunctions(); // lists for taking into account that pol/fun/par can be switched by more than one extension and that 'on' always wins List <string> onIds = new List <string>(); Dictionary <string, ExeXml.Fun> parsToRemove = new Dictionary <string, ExeXml.Fun>(); foreach (var extension in infoStore.country.extensions.Values) { foreach (var extPol in extension.polIds) { string polId = extPol.Key; bool isBasePol = extPol.Value == true; // true: a base-policy, that is switched off if the extension is on if (!infoStore.country.cao.pols.ContainsKey(polId)) { continue; } ExeXml.Pol pol = infoStore.country.cao.pols[polId]; bool?switchOn = null; if (extension.on == true) { switchOn = isBasePol ? false : true; // extension-switch is on: added-as-on ✔: on; added-as-off ✘: off } else if (!isBasePol) { switchOn = false; // extension-switch is off or n/a: added-as-on ✔: off; added-as-off ✘: do not touch } if (switchOn == true) { pol.on = true; } if (switchOn == false && !onIds.Contains(polId)) { pol.on = false; } // add the policy and all its functions and parameters, which do not have an own setting, to the switched-on (i.e. winning) elements if (switchOn == true) { onIds.AddUnique(polId); foreach (var f in pol.funs) { if (!extension.funIds.ContainsKey(f.Key)) { string funId = f.Key; ExeXml.Fun fun = f.Value; fun.on = true; onIds.AddUnique(funId); foreach (var parId in fun.pars.Keys) { if (!extension.parIds.ContainsKey(parId)) { if (parsToRemove.ContainsKey(parId)) { parsToRemove.Remove(parId); } onIds.AddUnique(parId); } } } } } } foreach (var extFun in extension.funIds) { string funId = extFun.Key; bool isBaseFun = extFun.Value == true; // true: a base-function, that is switched off if the extension is on ExeXml.Fun fun = null; foreach (var pol in infoStore.country.cao.pols) { var funs = from f in pol.Value.funs where f.Key == funId select f; if (!funs.Any()) { continue; } fun = funs.First().Value; if (fun.pars.Count == 0) { fun = null; // this takes care of functions which are set to n/a including all their parameters for this system, i.e. ignores them } break; } if (fun == null) { continue; } // see explanation above, however note: if parent-policy is switched off, all included functions are off as well // if parent-policy is switched on, included functions can still be switched off bool?switchOn = null; if (extension.on == true) { switchOn = isBaseFun ? false : true; // extension-switch is on: added-as-on ✔: on; added-as-off ✘: off } else if (!isBaseFun) { switchOn = false; // extension-switch is off or n/a: added-as-on ✔: off; added-as-off ✘: do not touch } if (switchOn == true) { fun.on = true; } if (switchOn == false && !onIds.Contains(funId)) { fun.on = false; } // add the function and all its parameters, which do not have an own setting, to the switched-on (i.e. winning) elements if (switchOn == true) { onIds.AddUnique(funId); foreach (var parId in fun.pars.Keys) { if (!extension.parIds.ContainsKey(parId)) { if (parsToRemove.ContainsKey(parId)) { parsToRemove.Remove(parId); } onIds.AddUnique(parId); } } } } foreach (var extPar in extension.parIds) { string parId = extPar.Key; bool isBasePar = extPar.Value == true; // other than for pol/fun we do not need the par, but its id and the parent-fun, because we need to delete the parameter in case ExeXml.Fun parentFun = null; foreach (var pol in infoStore.country.cao.pols) { foreach (var fun in pol.Value.funs) { if ((from p in fun.Value.pars where p.Key == parId select p).Any()) { parentFun = fun.Value; break; } } if (parentFun != null) { break; } } if (parentFun == null) { continue; } bool?keepPar = null; if (extension.on == true) { keepPar = isBasePar ? false : true; // extension-switch is on: added-as-on ✔: keep par, added-as-off ✘: remove par } else if (!isBasePar) { keepPar = false; // extension-switch is off or n/a: added-as-on ✔: remove par, added-as-off ✘: do not touch } if (keepPar == true && parsToRemove.ContainsKey(parId)) { parsToRemove.Remove(parId); } if (keepPar == false && !onIds.Contains(parId)) { parsToRemove.TryAdd(parId, parentFun); } if (keepPar == true) { onIds.AddUnique(parId); } } } foreach (var ptr in parsToRemove) { ptr.Value.pars.Remove(ptr.Key); // remove the respective parameters only after taking all extensions into account } foreach (ExeXml.Fun pof in permanentOffFunctions) { pof.on = false; } }
internal void IntegratePol(ExeXml.AddOn addOn, ExeXml.Fun addOnPol, Description funDescription) { string polName = null; // the name of the policy to add string linkPolName = null; // the name of the policy after or before which to add the policy bool before = true; // interpret the parameters of the AddOn_Pol function foreach (var par in addOnPol.pars.Values) { if (par.val == DefPar.Value.NA) { continue; } Description parDescription = new Description(funDescription, par); if (par.Name.ToLower() == DefPar.AddOn_Pol.Pol_Name.ToLower()) { polName = par.val; } else if (par.Name.ToLower() == DefPar.AddOn_Pol.Insert_Before_Pol.ToLower()) { linkPolName = par.val; } else if (par.Name.ToLower() == DefPar.AddOn_Pol.Insert_After_Pol.ToLower()) { linkPolName = par.val; before = false; } else if (par.Name.ToLower() == DefPar.AddOn_Pol.Allow_Duplicates.ToLower()) { } // do nothing, just allow duplicates always else { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = true, message = $"{parDescription.Get()}: unknown parameter: {par.Name}" }); } } // check for compulsory parameters if (polName == null) { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = false, message = $"{funDescription.Get()}: parameter {DefPar.AddOn_Pol.Pol_Name} not defined" }); return; } if (linkPolName == null) { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = false, message = $"{funDescription.Get()}: neither {DefPar.AddOn_Pol.Insert_Before_Pol} nor {DefPar.AddOn_Pol.Insert_After_Pol} defined" }); return; } // integrate the policy ... // ... in the country file, find the policy after or before which to integrate the policy if (!FindPol(addOn, linkPolName, infoStore.country.cao.pols, out ExeXml.Pol linkPol, out string dummy)) { return; } // ... in the add-on file, find the policy to add if (!FindPol(addOn, polName, addOn.cao.pols, out ExeXml.Pol pol, out string polID)) { return; } // ... check if policy was added before, if yes, make a clone with different ids if (infoStore.country.cao.pols.ContainsKey(polID)) { polID = Guid.NewGuid().ToString(); pol = ClonePol(pol); } // ... find an appropriate order pol.order = MakeOrder(linkPol.order, (from p in infoStore.country.cao.pols.Values select p.order).ToList(), before); // ... add the policy infoStore.country.cao.pols.Add(polID, pol); }
private void IntegrateFun(ExeXml.AddOn addOn, ExeXml.Fun addOnFun, Description funDescription) { string funID = null; // the id of the function to add string linkFunID = null; // the id of the function after or before which to add the function bool before = true; // interpret the parameters of the AddOn_Func function foreach (var par in addOnFun.pars.Values) { if (par.val == DefPar.Value.NA) { continue; } Description parDescription = new Description(funDescription, par); if (par.Name.ToLower() == DefPar.AddOn_Func.Id_Func.ToLower()) { funID = par.val; } else if (par.Name.ToLower() == DefPar.AddOn_Func.Insert_Before_Func.ToLower()) { linkFunID = par.val; } else if (par.Name.ToLower() == DefPar.AddOn_Func.Insert_After_Func.ToLower()) { linkFunID = par.val; before = false; } else { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = true, message = $"{parDescription.Get()}: unknown parameter: {par.Name}" }); } } // check for compulsory parameters if (funID == null) { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = false, message = $"{funDescription.Get()}: parameter {DefPar.AddOn_Func.Id_Func} not defined" }); return; } if (linkFunID == null) { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = false, message = $"{funDescription.Get()}: neither {DefPar.AddOn_Func.Insert_Before_Func} nor {DefPar.AddOn_Func.Insert_After_Func} defined" }); return; } // integrate the function ... // ... in the country file, find the function after or before which to integrate the function if (!FindFun(linkFunID, infoStore.country.cao.pols, funDescription, out ExeXml.Fun linkFun, out ExeXml.Pol parentPol)) { return; } // ... in the add-on file, find the function to add if (!FindFun(funID, addOn.cao.pols, funDescription, out ExeXml.Fun fun, out ExeXml.Pol dummy)) { return; } // ... check if function was added before, if yes, make a clone with different ids if (!parentPol.funs.ContainsKey(funID)) { funID = Guid.NewGuid().ToString(); fun = CloneFun(fun); } // ... find an appropriate order fun.order = MakeOrder(linkFun.order, (from f in parentPol.funs.Values select f.order).ToList(), before); // ... add the function parentPol.funs.Add(funID, fun); }
private void ApplyInfo(Dictionary <ExeXml.Fun, bool> switchInfo, ExeXml.Par switchFunRunCond, List <ExeXml.Par> switchFunDatabaseName) { foreach (var si in switchInfo) { ExeXml.Fun fun = si.Key; bool on = si.Value; // read-time change - simply change the switch as required if (switchFunRunCond == null) { fun.on = on; continue; } // run-time change: implement switch by editing or adding the function's RunCond var hasRunCond = from p in fun.pars.Values where p.Name.ToLower() == DefPar.Common.Run_Cond.ToLower() select p; // function does not yet have a RunCond: add a copy of the ChangeSwitch-RunCond if (hasRunCond == null || hasRunCond.Count() == 0) { if (fun.Name.ToLower() != DefFun.DefTu.ToLower() && // DefTU and DefIL do not accept a RunCond (does not make sense) fun.Name.ToLower() != DefFun.DefIl.ToLower()) // and it does no harm if these definitions exist { ExeXml.Par newRunCond = new ExeXml.Par() { Name = DefPar.Common.Run_Cond }; // function is currently on, switch off if RunCon is fulfilled // i.e. run as long as ChangeSwitch-RunCond is not fulfilled if (fun.on) { newRunCond.val = $"!({switchFunRunCond.val})"; } // function is currently off, switch on if RunCond is fulfilled // needs to be switched on, otherwise it is dropped by DropOff // but do not run until ChangeSwitch-RunCond is fulfilled else { fun.on = true; newRunCond.val = switchFunRunCond.val; } fun.pars.Add(Guid.NewGuid().ToString(), newRunCond); } } // function has a RunCond: merge with the ChangeSwitch-RunCond else { ExeXml.Par runCond = hasRunCond.First(); // function is currently on, switch off if RunCon is fulfilled // run if current RunCond is fulfilled and as long as ChangeSwitch-RunCond is not fulfilled if (fun.on) { runCond.val = $"!({switchFunRunCond.val}) & ({runCond.val})"; } // function is currently off, switch on if RunCond is fulfilled // needs to be switched on, otherwise it is dropped by DropOff // but do not run until ChangeSwitch-RunCond is fulfilled, but still also fulfill current RunCond else { fun.on = true; runCond.val = $"({switchFunRunCond.val}) & ({runCond.val})"; } } // transfer a possible #_DatabaseName-footnote from the switch-function to the function it is applied on foreach (ExeXml.Par dbName in switchFunDatabaseName) { fun.pars.Add(Guid.NewGuid().ToString(), dbName); } } }
private bool HandleBreak() { // CHECK IF THERE IS ANY BREAK FUNCTION ... string breakFunId = null; ExeXml.Fun breakFun = null; double breakFunOrder = double.MaxValue; Description funDesc = null; foreach (var pol in infoStore.country.cao.pols) { if (!pol.Value.on) { continue; } foreach (var fun in pol.Value.funs) { if (fun.Value.on && fun.Value.Name.ToLower() == DefFun.Break.ToLower()) { double o = GetOrder(pol.Value.order, fun.Value.order); if (o < breakFunOrder) // only consider 1stBreak in spine (if there are foolishly more) { breakFunId = fun.Key; breakFun = fun.Value; breakFunOrder = o; funDesc = new Description(pol.Value, breakFun, breakFunId); } } } } if (breakFun == null) { return(true); } // ... IF SO, CHECK PARAMETERS bool produceOutput = true, produceTUinfo = false; string outputFileName = string.Empty; foreach (var p in breakFun.pars) { string parID = p.Key; ExeXml.Par par = p.Value; if (par.val.ToLower() == DefPar.Value.NA) { continue; } Description parDesc = new Description(funDesc, par, parID); if (par.Name.ToLower() == DefPar.Break.ProduceOutput.ToLower() || par.Name.ToLower() == DefPar.Break.ProduceTUinfo.ToLower()) { bool produceX = false; if (par.val.ToLower() == DefPar.Value.YES) { produceX = true; } else if (par.val.ToLower() == DefPar.Value.NO) { produceX = false; } else { IssueErr(parDesc, "invalid value (must be yes or no)"); } if (par.Name.ToLower() == DefPar.Break.ProduceOutput.ToLower()) { produceOutput = produceX; } else { produceTUinfo = produceX; } } else if (par.Name.ToLower() == DefPar.Break.OutputFileName.ToLower()) { outputFileName = par.val; } else { IssueErr(parDesc, "unknown parameter"); } } if (produceOutput == false && produceTUinfo == true) { IssueErr(funDesc, "TUinfo can only be produced if output is produced (parameter is ignored)", true); } if (infoStore.communicator.errorCount > 0) { return(false); } // IMPLEMENT THE BREAK // - main task: switch off everything after the Break function // - and, if necessary, search for DefOutput that can provide the output-filename (if not set by parameter OutputFileName) // - and, if necessary, find all TU names double outputFunOrder = produceOutput && outputFileName == string.Empty ? double.MaxValue : -1; // the default for OutputFileName should be the first "normal" outputfile List <string> tuNames = new List <string>(); string indTUName = string.Empty; foreach (var pol in infoStore.country.cao.pols.Values) { if (!pol.on) { continue; } foreach (var fun in pol.funs.Values) { if (!fun.on) { continue; } double funOrder = GetOrder(pol.order, fun.order); if (funOrder > breakFunOrder) { fun.on = false; // switch off everything after the Break function } if (fun.Name.ToLower() == DefFun.DefOutput.ToLower() && funOrder < outputFunOrder && funOrder > breakFunOrder) // get the File paramter of the first DefOutput after the Break { var fn = from p in fun.pars.Values where p.Name.ToLower() == DefPar.DefOutput.File.ToLower() select p.val; if (fn.Count() > 0) { outputFileName = fn.First(); outputFunOrder = funOrder; } } // if necessary, find at least one individual TU for output function, or all (active) TUs if TUinfo should be produced if (!fun.on || !produceOutput || fun.Name.ToLower() != DefFun.DefTu.ToLower()) { continue; } var tuNamePar = from p in fun.pars.Values where p.Name.ToLower() == DefPar.DefTu.Name.ToLower() select p.val; var tuTypePar = from p in fun.pars.Values where p.Name.ToLower() == DefPar.DefTu.Type.ToLower() select p.val; if (tuNamePar.Count() == 0 || tuTypePar.Count() == 0) { continue; } if (produceTUinfo) { tuNames.Add(tuNamePar.First()); } if (indTUName == string.Empty && tuTypePar.First().ToUpper() == DefPar.Value.TUTYPE_IND) { indTUName = tuNamePar.First(); } } } // if necessary produce DefOutput function in redefining the Break function, which is not required anymore if (produceOutput == false) { breakFun.on = false; return(true); } if (outputFileName == string.Empty) { IssueErr(funDesc, "no name for the output file found"); return(false); } if (indTUName == string.Empty) { IssueErr(funDesc, "no DefTU with Type=IND found (required as DefOutput's TAX_UNIT)"); return(false); } int iGroup = 0, order = 0; breakFun.Name = DefFun.DefOutput; breakFun.pars.Clear(); breakFun.pars.Add(Guid.NewGuid().ToString(), new ExeXml.Par() { Name = DefPar.DefOutput.File, val = outputFileName, order = (++order).ToString() }); breakFun.pars.Add(Guid.NewGuid().ToString(), new ExeXml.Par() { Name = DefPar.DefOutput.VarGroup, val = "*", order = (++order).ToString() }); breakFun.pars.Add(Guid.NewGuid().ToString(), new ExeXml.Par() { Name = DefPar.DefOutput.ILGroup, val = "*", order = (++order).ToString() }); breakFun.pars.Add(Guid.NewGuid().ToString(), new ExeXml.Par() { Name = DefPar.Common.TAX_UNIT, val = indTUName, order = (++order).ToString() }); foreach (string tuName in tuNames) { string sGroup = (++iGroup).ToString(); breakFun.pars.Add(Guid.NewGuid().ToString(), new ExeXml.Par() { Name = DefPar.DefOutput.UnitInfo_TU, val = tuName, Group = sGroup, order = (++order).ToString() }); foreach (string uiId in new List <string> { DefPar.Value.UNITINFO_HEADID, DefPar.Value.UNITINFO_ISPARTNER, DefPar.Value.UNITINFO_ISDEPCHILD, DefPar.Value.UNITINFO_ISOWNCHILD, DefPar.Value.UNITINFO_ISOWNDEPCHILD, DefPar.Value.UNITINFO_ISDEPPARENT, DefPar.Value.UNITINFO_ISDEPRELATIVE, DefPar.Value.UNITINFO_ISLONEPARENT }) { breakFun.pars.Add(Guid.NewGuid().ToString(), new ExeXml.Par() { Name = DefPar.DefOutput.UnitInfo_Id, val = uiId, Group = sGroup, order = (++order).ToString() }); } } void IssueErr(Description d, string m, bool isW = false) { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = isW, message = $"{d.Get()}: {m}" }); } return(true); }