/// <returns>true if it has failures</returns> private bool ValidateZones(Facility requirement, Facility submitted, Facility retFacility) { if (requirement.Zones == null) { return(false); } var ret = false; // hack: create a fake modelFacility candidates from spaces. var fakeSubmittedFacility = new Facility(); fakeSubmittedFacility.Floors = fakeSubmittedFacility.Clone(submitted.Floors as IEnumerable <Floor>).ToList(); fakeSubmittedFacility.Zones = new List <Zone>(); var lSpaces = submitted.Get <Space>().ToList(); foreach (var zoneRequirement in requirement.Zones) { var v = new CobieObjectValidator <Zone, Space>(zoneRequirement) { TerminationMode = TerminationMode }; if (!v.HasRequirements) { continue; } // hack: now create a fake Zone based on candidates from spaces. var fakeZone = fakeSubmittedFacility.Create <Zone>(); fakeZone.Categories = zoneRequirement.Categories.Clone().ToList(); fakeZone.Name = zoneRequirement.Name; fakeZone.ExternalEntity = zoneRequirement.ExternalEntity; fakeZone.ExternalSystem = zoneRequirement.ExternalSystem; fakeZone.ExternalId = zoneRequirement.ExternalId; fakeZone.Spaces = new List <SpaceKey>(); var candidateSpaces = v.GetCandidates(lSpaces).ToList(); if (candidateSpaces.Any()) { foreach (var spaceMatch in candidateSpaces) { var mSpace = spaceMatch.MatchedObject as Space; if (mSpace == null) { continue; } var sk = new SpaceKey { Name = mSpace.Name }; fakeZone.Spaces.Add(sk); } if (retFacility.Zones == null) { retFacility.Zones = new List <Zone>(); } var validatedZone = v.Validate(fakeZone, retFacility); retFacility.Zones.Add(validatedZone); var tmpFloor = retFacility.Get <Floor>(fl => fl.Name == TemporaryFloorName).FirstOrDefault(); if (tmpFloor == null) { continue; } // ensure that the floor and spaces are avalialale in the report facility foreach (var spaceKey in validatedZone.Spaces) { // 1) on the floor var submissionOwningFloor = submitted.Get <Floor>(f => f.Spaces != null && f.Spaces.Any(sp => sp.Name == spaceKey.Name)).FirstOrDefault(); if (submissionOwningFloor == null) { continue; } var destFloor = retFacility.Get <Floor>(f => f.Name == submissionOwningFloor.Name).FirstOrDefault(); if (destFloor == null) { destFloor = retFacility.Create <Floor>(); destFloor.Name = submissionOwningFloor.Name; destFloor.ExternalEntity = submissionOwningFloor.ExternalEntity; destFloor.ExternalId = submissionOwningFloor.ExternalId; destFloor.ExternalSystem = submissionOwningFloor.ExternalSystem; destFloor.Elevation = submissionOwningFloor.Elevation; destFloor.Spaces = new List <Space>(); retFacility.Floors.Add(destFloor); // finally add it in the facility tree } // 2) now on the space. var sourceSpace = tmpFloor.Spaces.FirstOrDefault(sp => sp.Name == spaceKey.Name); if (sourceSpace != null) { destFloor.Spaces.Add(sourceSpace); } } retFacility.Floors.Remove(tmpFloor); } else { if (retFacility.Zones == null) { retFacility.Zones = new List <Zone>(); } retFacility.Zones.Add(v.Validate((Zone)null, retFacility)); } ret |= v.HasFailures; } return(ret); }
/// <param name="candidateParent">If null provides a missing match report</param> /// <param name="targetFacility">The target facility is required to ensure that the facility tree is properly referenced</param> /// <returns></returns> internal T Validate(T candidateParent, Facility targetFacility) { var iSubmitted = 0; var iPassed = 0; List <TSub> candidateChildren = null; var returnChildren = new List <TSub>(); // initialisation var retType = targetFacility.Create <T>(); retType.Categories = new List <Category>(); retType.SetRequirementExternalSystem(_requirementObject.ExternalSystem); retType.SetRequirementExternalId(_requirementObject.ExternalId); retType.SetRequirementName(_requirementObject.Name); retType.SetRequirementCategories(_requirementObject.Categories); // improve returning Parent if (candidateParent == null) // the following properties depend on the nullity of candidate { retType.Name = _requirementObject.Name; } else { retType.Name = candidateParent.Name; retType.ExternalId = candidateParent.ExternalId; retType.ExternalSystem = candidateParent.ExternalSystem; retType.Categories = candidateParent.Categories.Clone().ToList(); candidateChildren = candidateParent.GetChildObjects <TSub>(); if (candidateChildren != null) { iSubmitted = candidateChildren.Count; } } var returnWithoutFurtherTests = false; if (!RequirementDetails.Any()) { retType.Description = "Classification has no requirements.\r\n"; retType.Categories.Add(FacilityValidator.PassedCat); iPassed = iSubmitted; returnWithoutFurtherTests = true; } // if candidate is null then consider there's no match if (candidateParent == null) { // it's only a failure if the requirement was itself required (not only it had atteributes required) if (_requirementObject.Categories != null && _requirementObject.Categories.Any(c => c.Classification == "DPoW" && c.Code == "required") ) { retType.Categories.Add(FacilityValidator.FailedCat); } else { retType.Categories.Add(FacilityValidator.PassedCat); } retType.Description = "No candidates in submission match the required classification.\r\n"; retType.Attributes.AddRange(RequirementAttributes()); returnWithoutFurtherTests = true; } if (returnWithoutFurtherTests) { retType.SetSubmittedChildrenCount(iSubmitted); retType.SetValidChildrenCount(iPassed); return(retType); } // ==================== begin testing at parent level CachedPropertiesAndAttributesValidator <T> parentCachedValidator; try { parentCachedValidator = new CachedPropertiesAndAttributesValidator <T>(candidateParent); } catch (ValidationException ex) { retType.Categories.Add(FacilityValidator.FailedCat); retType.Description += ex.Message; return(retType); } if (retType.Attributes == null) { retType.Attributes = new List <Attribute>(); } // produce parent level description var outstandingRequirementsCount = 0; foreach (var req in RequirementDetails) { object satValue; var pass = parentCachedValidator.CanSatisfy(req, out satValue); var a = targetFacility.Clone(req.Attribute); // todo: determine the correct theoretical behaviour; it should probably be null, but needs changes in the reporting mechanism. // ReSharper disable once ConvertIfStatementToNullCoalescingExpression if (satValue != null) { a.Value = AttributeValue.CreateFromObject(satValue); } else { a.Value = AttributeValue.CreateFromObject(""); } //// it was previously: //if (satValue is AttributeValue) // a.Value = satValue as AttributeValue; //else // a.Value = null; if (pass) { a.Categories = new List <Category> { FacilityValidator.PassedCat }; } else { a.Categories = new List <Category> { FacilityValidator.FailedCat }; outstandingRequirementsCount++; } retType.Attributes.Add(a); } retType.Description = string.Format("{0} of {1} requirement addressed.", RequirementDetails.Count - outstandingRequirementsCount, RequirementDetails.Count); var anyChildFails = false; // ==================== begin testing at child level // if (candidateChildren != null) { foreach (var modelChild in candidateChildren) { var iChildRequirementsMatched = 0; var reportChild = targetFacility.Create <TSub>(); reportChild.Name = modelChild.Name; reportChild.ExternalId = modelChild.ExternalId; reportChild.Categories = new List <Category>(); reportChild.Attributes = new List <Attribute>(); // child classification can be copied from model // if (modelChild.Categories != null) { reportChild.Categories.AddRange(modelChild.Categories); } var childCachedValidator = new CachedPropertiesAndAttributesValidator <TSub>(modelChild); foreach (var req in RequirementDetails) { object satValue; if (childCachedValidator.CanSatisfy(req, out satValue)) { // passes locally if (!parentCachedValidator.AlreadySatisfies(req)) { iChildRequirementsMatched++; } var a = targetFacility.Clone(req.Attribute); a.Value = AttributeValue.CreateFromObject(satValue); a.Categories = new List <Category> { FacilityValidator.PassedCat }; reportChild.Attributes.Add(a); } else if (!parentCachedValidator.AlreadySatisfies(req)) // fails locally, and is not passed at higher level, then add to explicit report fail { var a = targetFacility.Clone(req.Attribute); // todo: determine the correct theoretical behaviour; it should probably be null, but needs changes in the reporting mechanism. // ReSharper disable once ConvertIfStatementToNullCoalescingExpression if (satValue != null) { a.Value = AttributeValue.CreateFromObject(satValue); } else { a.Value = AttributeValue.CreateFromObject(""); } a.Categories = new List <Category> { FacilityValidator.FailedCat }; reportChild.Attributes.Add(a); } } var sb = new StringBuilder(); sb.AppendFormat("{0} of {1} outstanding requirements addressed.", iChildRequirementsMatched, outstandingRequirementsCount); var pass = (outstandingRequirementsCount == iChildRequirementsMatched); if (!pass) { anyChildFails = true; reportChild.Categories.Add(FacilityValidator.FailedCat); } else { iPassed++; reportChild.Categories.Add(FacilityValidator.PassedCat); } reportChild.Description = sb.ToString(); returnChildren.Add(reportChild); } } retType.SetChildObjects(returnChildren); retType.Categories.Add( anyChildFails ? FacilityValidator.FailedCat : FacilityValidator.PassedCat ); retType.SetSubmittedChildrenCount(iSubmitted); retType.SetValidChildrenCount(iPassed); return(retType); }