private void ValidateConcept(DocTemplateUsage docUsage, DocModelView docView, DocExchangeRequirementEnum reqInherit, Type typeEntity, List<SEntity> list, StringBuilder sb, Dictionary<string, Type> typemap, ref int grandtotalpass, ref int grandtotalskip, ref int grandtotallist)
{
if (docUsage.Definition == null || docUsage.Definition.IsDisabled || docUsage.Suppress)
return;
DocExchangeRequirementEnum req = DocExchangeRequirementEnum.NotRelevant;
bool includeconcept = true;
if (this.m_filterexchange != null)
{
includeconcept = false;
foreach (DocExchangeItem ei in docUsage.Exchanges)
{
if (ei.Exchange == this.m_filterexchange && ei.Applicability == DocExchangeApplicabilityEnum.Export &&
(ei.Requirement == DocExchangeRequirementEnum.Mandatory || ei.Requirement == DocExchangeRequirementEnum.Optional))
{
includeconcept = true;
req = ei.Requirement;
}
}
}
else
{
// check net requirement if mandatory for any exchange
foreach (DocExchangeItem docExchangeItem in docUsage.Exchanges)
{
switch (docExchangeItem.Requirement)
{
case DocExchangeRequirementEnum.Mandatory:
req = DocExchangeRequirementEnum.Mandatory;
break;
case DocExchangeRequirementEnum.Optional:
if (req == DocExchangeRequirementEnum.NotRelevant)
{
req = DocExchangeRequirementEnum.Optional;
}
break;
case DocExchangeRequirementEnum.Excluded:
if (req == DocExchangeRequirementEnum.NotRelevant)
{
req = DocExchangeRequirementEnum.Excluded;
}
break;
}
}
}
if (req == DocExchangeRequirementEnum.NotRelevant)
{
req = reqInherit;
if (reqInherit != DocExchangeRequirementEnum.NotRelevant)
{
includeconcept = true;
}
}
if (!includeconcept)
return;
if (list.Count == 0)
{
sb.Append("<details><summary>");
sb.Append(docUsage.Definition.Name);
sb.AppendLine("</summary></details>");
return;
}
StringBuilder sbDetail = new StringBuilder();
if (docUsage.Definition != null && docUsage.Definition.Rules != null)
{
// new-style validation -- compiled code (fast)
string methodname = DocumentationISO.MakeLinkName(docView) + "_" + DocumentationISO.MakeLinkName(docUsage.Definition);
System.Reflection.MethodInfo method = typeEntity.GetMethod(methodname);
int fail = 0;
int pass = 0; // pass graph check
int passRule = 0; // pass rule check
int failRule = 0; // fail rule check
List<DocModelRule> trace = new List<DocModelRule>();
DocModelRule[] parameterrules = docUsage.Definition.GetParameterRules();
Dictionary<DocModelRuleAttribute, bool> conditions = new Dictionary<DocModelRuleAttribute, bool>();
if (docUsage.Definition.Name.Contains("-086"))
{
this.ToString();
}
foreach (SEntity ent in list)
{
if(docUsage.Definition.Name.Contains("-077") && ent.GetType().Name.Equals("IfcWindow"))
{
this.ToString();
}
object[] args = new object[0];
if (parameterrules != null && parameterrules.Length > 0)
{
args = new object[parameterrules.Length];
foreach (DocTemplateItem docItem in docUsage.Items)
{
//if (!docItem.Optional)
{
trace.Clear();
conditions.Clear();
if (docItem == docUsage.Items[0])
{
sbDetail.Append("<tr valign=\"top\"><td rowspan=\"" + docUsage.Items.Count + "\">#");
sbDetail.Append(ent.OID);
sbDetail.Append("</td>");
}
else
{
sbDetail.Append("<tr valign=\"top\">");
}
for (int iParam = 0; iParam < parameterrules.Length; iParam++)
{
DocModelRule prule = parameterrules[iParam];
sbDetail.Append("<td>");
DocTemplateUsage docUsageInner = docItem.GetParameterConcept(prule.Identification, null);//verify...
if (docUsageInner != null)
{
// report inner rules...
foreach (DocTemplateItem docItemInner in docUsageInner.Items)
{
sbDetail.Append(docItemInner.RuleParameters);
if (docItemInner.Optional)
{
sbDetail.Append("*");
}
sbDetail.Append("<br/>");
}
}
else
{
string pval = docItem.GetParameterValue(prule.Identification);
sbDetail.Append(pval);
}
sbDetail.Append("</td>");
}
sbDetail.Append("<td>");
bool? result = true;
foreach (DocModelRule rule in docUsage.Definition.Rules)
{
trace.Clear();
bool? itemresult = rule.Validate(ent, docItem, typemap, trace, ent, docUsage, conditions);
if (itemresult != null && !itemresult.Value && result != null)
{
result = false;
// check if conditions were all met; if not, then not a failure
foreach(DocModelRule checkparam in parameterrules)
{
if(checkparam.IsCondition())
{
bool paramspec = false;
if (!conditions.TryGetValue((DocModelRuleAttribute)checkparam, out paramspec) || paramspec == false)
{
result = null;
break;
}
}
}
break;
}
else if (itemresult == null)
{
result = null; //verify: was commented out -- put back in to indicate that entire rule is inapplicable.
}
}
if (result != null && !result.Value)
{
foreach (DocModelRule mm in trace)
{
if (mm is DocModelRuleEntity)
{
sbDetail.Append("\\");
}
else if (mm is DocModelRuleAttribute)
{
sbDetail.Append(".");
}
sbDetail.Append(mm.Name);
}
docItem.ValidationStructure[ent] = false;
#if false // don't mark overall usage as failure, since operator may only require one to be true
if (!docItem.Optional)
{
docUsage.ValidationStructure[ent] = false;
docUsage.Validation = false;
docUsage.Definition.Validation = false;
fail++;
}
#endif
}
else if (result != null && result.Value)
{
// check for any nested failures
foreach (DocTemplateUsage docInnerConcept in docItem.Concepts)
{
foreach (DocTemplateItem docInnerItem in docInnerConcept.Items)
{
bool innerresult = false;
if(docInnerItem.ValidationStructure.TryGetValue(ent, out innerresult))
{
if(!innerresult)
{
sbDetail.Append("~");
sbDetail.Append(docInnerItem.RuleParameters);
sbDetail.Append("<br/>");
result = false;
fail++;
break;
}
}
}
}
if (result != null && result.Value)
{
sbDetail.Append("+");
pass++;
docItem.ValidationStructure[ent] = true;
if (!docUsage.ValidationStructure.ContainsKey(ent)) // if no failures so far, then concept passes for now
{
docUsage.ValidationStructure[ent] = true;
}
}
}
else if (result == null)
{
sbDetail.Append("*"); // NOT APPLICABLE
// new V9.5: don't mark non-applicable as passing
/*
docItem.ValidationStructure[ent] = true;
if (!docUsage.ValidationStructure.ContainsKey(ent))
{
docUsage.ValidationStructure[ent] = true;
}*/
}
sbDetail.Append("</td><td>");
if (result == null)
{
// don't evaluate constraint if it doesn't apply
}
else if (method != null)
{
try
{
bool[] ruleresult = (bool[])method.Invoke(ent, null);//, args);
if (ruleresult != null)
{
bool allpass = true;
foreach (bool compresult in ruleresult)
{
if (!compresult)
{
allpass = false;
break;
}
}
if (allpass)
{
sbDetail.Append("+");
passRule++;
docUsage.ValidationConstraints[ent] = true;
if (docUsage.Validation == null)
{
docUsage.Validation = true;
}
}
else
{
// run detailed report
foreach (DocModelRule rule in docUsage.Definition.Rules)
{
TraceRule(docUsage.Definition, rule, sbDetail, ent, list);
}
failRule++;
docUsage.ValidationConstraints[ent] = false;
docUsage.Validation = false;
}
}
else
{
sbDetail.Append("FAIL");
failRule++;
}
}
catch (System.Reflection.TargetInvocationException et)
{
sbDetail.Append(et.InnerException.GetType().Name);
failRule++;
}
catch (Exception ex)
{
sbDetail.Append(ex.GetType().Name);
failRule++;
}
}
else
{
sbDetail.Append("FAIL - Incompatible Template");
}
sbDetail.AppendLine("</td></tr>");
}
}
// capture items that didn't match
}
else
{
// check for if there are no parameters
sbDetail.Append("<tr valign=\"top\"><td>#");
sbDetail.Append(ent.OID);
sbDetail.Append("</td><td>");
DocModelRule ruleFail = null;
bool? result = true;
foreach (DocModelRule rule in docUsage.Definition.Rules)
{
trace.Clear();
bool? itemresult = rule.Validate(ent, null, typemap, trace, ent, docUsage, conditions);
if (itemresult != null && !itemresult.Value)
{
result = false;
}
else if (itemresult == null)
{
result = null;
}
if (itemresult != null && !itemresult.Value)
{
if (ruleFail != null)
{
sbDetail.Append("<br/>");
}
ruleFail = rule;
foreach (DocModelRule mm in trace)
{
if (mm is DocModelRuleEntity)
{
sbDetail.Append("\\");
}
else if (mm is DocModelRuleAttribute)
{
sbDetail.Append(".");
}
sbDetail.Append(mm.Name);
}
}
}
if (result == null)
{
// no applicable rules, so passing
pass++;
}
else if (result != null && result.Value)
{
// all rules passed
docUsage.ValidationStructure[ent] = true;
if (docUsage.Validation == null)
{
docUsage.Validation = true;
}
pass++;
}
else if (ruleFail != null)
{
docUsage.ValidationStructure[ent] = false;
docUsage.Validation = false;
fail++;
}
if (result == null)
{
sbDetail.Append("*");
}
else if (ruleFail == null)
{
sbDetail.Append("+");
}
sbDetail.Append("</td><td>");
if (method != null)
{
try
{
bool[] ruleresult = (bool[])method.Invoke(ent, args);
if (ruleresult != null)
{
bool allpass = true;
foreach (bool compresult in ruleresult)
{
if (!compresult)
{
allpass = false;
break;
}
}
if (allpass)
{
sbDetail.Append("+");
docUsage.ValidationConstraints[ent] = true;
passRule++;
}
else
{
// run second-stage validation and trace
bool debugpass = true;
StringBuilder sbCheck = new StringBuilder();
foreach (DocModelRule rule in docUsage.Definition.Rules)
{
bool eachpass = TraceRule(docUsage.Definition, rule, sbCheck, ent, list);
if (!eachpass)
{
debugpass = false;
}
}
if (!debugpass)
{
sbDetail.Append(sbCheck.ToString());
docUsage.ValidationConstraints[ent] = false;
docUsage.Validation = false;
failRule++;
}
else
{
sbDetail.Append("+");
docUsage.ValidationConstraints[ent] = true;
if (docUsage.Validation == null)
{
docUsage.Validation = true;
}
passRule++;
}
}
}
else
{
sbDetail.Append("FAIL");
failRule++;
}
}
catch (System.Reflection.TargetInvocationException et)
{
sbDetail.Append(et.InnerException.GetType().Name);
failRule++;
}
catch (Exception ex)
{
sbDetail.Append(ex.GetType().Name);
failRule++;
}
}
else
{
sbDetail.Append("FAIL - Incompatible Template");
}
sbDetail.AppendLine("</td></tr>");
}
}
grandtotallist++;
// nested concepts -- only one must pass
StringBuilder sbNested = new StringBuilder();
if (docUsage.Concepts.Count > 0)
{
sbNested.AppendLine("<p>Validation of concept groups (only one must pass):</p>");
int subtotalpass = 0;
int subtotalskip = 0;
int subtotallist = 0;
foreach (DocTemplateUsage docSub in docUsage.Concepts)
{
ValidateConcept(docSub, docView, reqInherit, typeEntity, list, sbNested, typemap, ref subtotalpass, ref subtotalskip, ref subtotallist);
}
if (subtotalpass > 0)
{
//grandtotalpass++;
sbNested.AppendLine("<p>RESULT: PASS (" + subtotalpass + "/" + subtotallist + ")</p>");
}
else
{
fail++;
sbNested.AppendLine("<p>RESULT: FAIL (" + subtotalpass + "/" + subtotallist + ")</p>");
}
}
sb.AppendLine("<details><summary>" + docUsage.Definition.Name);
sb.Append(" (Operator: " + docUsage.Operator.ToString() + ")");
if(req == DocExchangeRequirementEnum.Optional)
{
sb.Append(" [OPTIONAL]");
}
if (fail > 0 || failRule > 0)
{
docUsage.Validation = false;
docUsage.Definition.Validation = false;
if(req == DocExchangeRequirementEnum.Optional)
{
grandtotalskip++;
}
sb.AppendLine(" - [FAIL]");
}
else
{
docUsage.Validation = true;
if (docUsage.Definition.Validation == null)
{
docUsage.Definition.Validation = true;
}
grandtotalpass++;
}
sb.AppendLine("</summary>");
sb.AppendLine("<table border=\"1\" >");
sb.Append("<tr><th>Instance</th>");
foreach (DocModelRule docRule in parameterrules)
{
sb.Append("<th>");
sb.Append(docRule.Identification);
if (docRule.IsCondition())
{
sb.Append("?");
}
sb.Append("</th>");
}
sb.Append("<th>Structure</th>");
sb.Append("<th>Constraints</th>");
sb.AppendLine("</tr>");
sb.AppendLine(sbDetail.ToString());
sb.AppendLine("</table>");
sb.AppendLine(sbNested.ToString());
sb.AppendLine("</details>");
}
}