private ValidationOperationItems ValidateParameterResource(Parameters ParametersResource)
        {
            var ValidationOperationItems = new ValidationOperationItems();

            ValidationOperationItems.ValidationMode = ResourceValidationModeType.None;
            var ModeParameter = ParametersResource.Parameter.SingleOrDefault(x => x.Name.ToLower() == "mode");

            if (ModeParameter != null)
            {
                if (ModeParameter.Value is Code ModeCode)
                {
                    switch (ModeCode.Value.ToLower())
                    {
                    case "create":
                        ValidationOperationItems.ValidationMode = ResourceValidationModeType.Create;
                        break;

                    case "update":
                        ValidationOperationItems.ValidationMode = ResourceValidationModeType.Update;
                        break;

                    case "delete":
                        ValidationOperationItems.ValidationMode = ResourceValidationModeType.Delete;
                        break;

                    default:
                        ValidationOperationItems.ValidationMode = null;
                        break;
                    }
                }
            }
            else
            {
                ValidationOperationItems.ValidationMode = ResourceValidationModeType.None;
            }

            var ProfileParameter = ParametersResource.Parameter.SingleOrDefault(x => x.Name.ToLower() == "profile");

            if (ProfileParameter != null)
            {
                if (ProfileParameter.Value is FhirUri FhirUri)
                {
                    ValidationOperationItems.ProfileUri = FhirUri.Value;
                }
            }

            if (ValidationOperationItems.ValidationMode != ResourceValidationModeType.Delete)
            {
                var ResourceParameter = ParametersResource.Parameter.SingleOrDefault(x => x.Name.ToLower() == "resource");
                if (ResourceParameter != null)
                {
                    if (ResourceParameter.Resource != null)
                    {
                        ValidationOperationItems.ResourceToValidate = ResourceParameter.Resource;
                    }
                }
            }
            return(ValidationOperationItems);
        }
 private OperationOutcome PerformValidation(ValidationOperationItems ValidationOperationItems)
 {
     return(IFhirValidationSupport.Validate(ValidationOperationItems.ResourceToValidate, new List <string> {
         ValidationOperationItems.ProfileUri
     }));
 }
        private ValidationOperationItems ConsoladateValidationOperationItems(ValidationOperationItems FromUrl, ValidationOperationItems FromParameters)
        {
            var OpOutComeIssues = new List <OperationOutcome.IssueComponent>();
            var ReturnValidationOperationItems = new ValidationOperationItems();

            //Profile
            IPyroFhirUri FhirRequestUriFromUrl        = null;
            IPyroFhirUri FhirRequestUriFromParameters = null;

            if (string.IsNullOrWhiteSpace(FromUrl.ProfileUri) && string.IsNullOrWhiteSpace(FromParameters.ProfileUri))
            {
                var OpOutComeIssue = Common.Tools.FhirOperationOutcomeSupport.CreateIssue(OperationOutcome.IssueSeverity.Error, OperationOutcome.IssueType.NotSupported,
                                                                                          $"No Profile URI found in either the request URL or the Parameter body, Validation cannot be performed with out a profile reference.");
                IssueList.Add(OpOutComeIssue);
            }
            else if (!string.IsNullOrWhiteSpace(FromUrl.ProfileUri))
            {
                FhirRequestUriFromUrl = IPyroFhirUriFactory.CreateFhirRequestUri();
                if (FhirRequestUriFromUrl.Parse(FromUrl.ProfileUri))
                {
                    ReturnValidationOperationItems.FhirRequestUriProfileUri = FhirRequestUriFromUrl;
                    ReturnValidationOperationItems.ProfileUri = FromUrl.ProfileUri;
                }
                else
                {
                    var OpOutComeIssue = Common.Tools.FhirOperationOutcomeSupport.CreateIssue(OperationOutcome.IssueSeverity.Error, OperationOutcome.IssueType.NotSupported,
                                                                                              $"Error in parsing the profile URI found in the request URL, parse error is: {FhirRequestUriFromUrl.ParseErrorMessage}");
                    IssueList.Add(OpOutComeIssue);
                }
            }
            else if (!string.IsNullOrWhiteSpace(FromParameters.ProfileUri))
            {
                FhirRequestUriFromParameters = IPyroFhirUriFactory.CreateFhirRequestUri();
                if (FhirRequestUriFromParameters.Parse(FromParameters.ProfileUri))
                {
                    ReturnValidationOperationItems.FhirRequestUriProfileUri = FhirRequestUriFromParameters;
                    ReturnValidationOperationItems.ProfileUri = FromParameters.ProfileUri;
                }
                else
                {
                    var OpOutComeIssue = Common.Tools.FhirOperationOutcomeSupport.CreateIssue(OperationOutcome.IssueSeverity.Error, OperationOutcome.IssueType.NotSupported,
                                                                                              $"Error in parsing the profile URI found in the Parameters resource, parse error is: {FhirRequestUriFromParameters.ParseErrorMessage}");
                    IssueList.Add(OpOutComeIssue);
                }
            }


            //Mode
            if (!FromUrl.ValidationMode.HasValue && !FromParameters.ValidationMode.HasValue)
            {
                string Message        = $"The mode property is not set to a valid value. Must be either (create, update, delete) or not set at all.";
                var    OpOutComeIssue = Common.Tools.FhirOperationOutcomeSupport.CreateIssue(OperationOutcome.IssueSeverity.Error, OperationOutcome.IssueType.NotSupported, Message);
                IssueList.Add(OpOutComeIssue);
            }
            else if (FromUrl.ValidationMode.HasValue)
            {
                ReturnValidationOperationItems.ValidationMode = FromUrl.ValidationMode.Value;
            }
            else if (FromParameters.ValidationMode.HasValue)
            {
                ReturnValidationOperationItems.ValidationMode = FromParameters.ValidationMode.Value;
            }
            else
            {
                throw new Exception("Server error: Mode parameter not found in Parameter Resource or URL, yet null check failed. ");
            }

            //Resource
            if (FromParameters.ResourceToValidate != null)
            {
                ReturnValidationOperationItems.ResourceToValidate = FromParameters.ResourceToValidate;
            }
            else
            {
                ReturnValidationOperationItems.ResourceToValidate = FromUrl.ResourceToValidate;
            }

            //Report Errors
            if (IssueList.Count > 0)
            {
                return(null);
            }

            return(ReturnValidationOperationItems);
        }
        public IResourceServiceOutcome ValidateResource(OperationClass OperationClass, Resource Resource, IRequestMeta RequestMeta)
        {
            if (OperationClass == null)
            {
                throw new NullReferenceException("OperationClass cannot be null.");
            }
            if (Resource == null)
            {
                throw new NullReferenceException("Resource cannot be null.");
            }
            if (RequestMeta == null)
            {
                throw new NullReferenceException("RequestMeta cannot be null.");
            }
            if (RequestMeta.PyroRequestUri == null)
            {
                throw new NullReferenceException("RequestUri cannot be null.");
            }
            if (RequestMeta.RequestHeader == null)
            {
                throw new NullReferenceException("RequestHeader cannot be null.");
            }
            if (RequestMeta.SearchParameterGeneric == null)
            {
                throw new NullReferenceException("SearchParameterGeneric cannot be null.");
            }
            if (IResourceServices == null)
            {
                throw new NullReferenceException("ResourceServices cannot be null.");
            }
            if (IFhirValidationSupport == null)
            {
                throw new NullReferenceException("IFhirValidationSupport cannot be null.");
            }


            IssueList = new List <OperationOutcome.IssueComponent>();

            ResourceServiceOutcome = IResourceServiceOutcomeFactory.CreateResourceServiceOutcome();

            ISearchParametersServiceOutcome SearchParametersServiceOutcome = ParseUrlSearchParameters(RequestMeta.SearchParameterGeneric, OperationClass);

            FormatMimeType = SearchParametersServiceOutcome.SearchParameters.Format;
            if (SearchParametersServiceOutcome.FhirOperationOutcome != null)
            {
                IssueList.AddRange(SearchParametersServiceOutcome.FhirOperationOutcome.Issue);
                return(FinalResourceServiceOutcome(IssueList));
            }

            //Get ValidationOperationItems from URL
            ValidationOperationItems ValidationOperationItemsFromUrl = new ValidationOperationItems();

            ObtainOperationItemsFromSearchParameters(SearchParametersServiceOutcome, ValidationOperationItemsFromUrl);

            //Get ValidationOperationItems from Parameter Resource
            ValidationOperationItems ValidationOperationItemsFromParametersResource = new ValidationOperationItems();

            if (Resource.ResourceType == ResourceType.Parameters)
            {
                ValidationOperationItemsFromParametersResource = ValidateParameterResource(Resource as Parameters);
            }
            else
            {
                ValidationOperationItemsFromUrl.ResourceToValidate = Resource;
            }

            ValidationOperationItems FinalValidationOperationItems = ConsoladateValidationOperationItems(ValidationOperationItemsFromUrl, ValidationOperationItemsFromParametersResource);

            if (FinalValidationOperationItems == null)
            {
                return(FinalResourceServiceOutcome(IssueList));
            }

            if (FinalValidationOperationItems.ValidationMode == ResourceValidationModeType.Delete)
            {
                var OpOutCome = Common.Tools.FhirOperationOutcomeSupport.Create(OperationOutcome.IssueSeverity.Error, OperationOutcome.IssueType.NotSupported,
                                                                                $"A mode parameter equal to 'delete' can only be used against a Resource instance URL.");
                IssueList.AddRange(OpOutCome.Issue);
                return(FinalResourceServiceOutcome(IssueList));
            }
            else if (FinalValidationOperationItems.ResourceToValidate != null)
            {
                if (!CheckResourceEndpointMatchesResourceToBeValidated(FinalValidationOperationItems.ResourceToValidate.ResourceType, RequestMeta.PyroRequestUri))
                {
                    return(FinalResourceServiceOutcome(IssueList));
                }

                if (FinalValidationOperationItems.FhirRequestUriProfileUri != null)
                {
                    OperationOutcome ProfileValidationOpOutCome = PerformValidation(FinalValidationOperationItems);
                    PerformModeValidation(ProfileValidationOpOutCome, FinalValidationOperationItems, RequestMeta);
                    IssueList.AddRange(ProfileValidationOpOutCome.Issue);
                    return(FinalResourceServiceOutcome(IssueList));
                }
                else
                {
                    OperationOutcome ModeValidationOpOutCome = new OperationOutcome();
                    PerformModeValidation(ModeValidationOpOutCome, FinalValidationOperationItems, RequestMeta);
                    // There is no profile given to validate against.
                    var OpOutCome = Common.Tools.FhirOperationOutcomeSupport.Create(OperationOutcome.IssueSeverity.Error, OperationOutcome.IssueType.NotSupported,
                                                                                    $"The Resource provided for validation '{FinalValidationOperationItems.ResourceToValidate.ResourceType.GetLiteral()}' must match the resource endpoint in the URL '{RequestMeta.PyroRequestUri.FhirRequestUri.ResourseName}'");
                    IssueList.AddRange(OpOutCome.Issue);
                    return(FinalResourceServiceOutcome(IssueList));
                }
            }
            else
            {
                var OpOutCome = Common.Tools.FhirOperationOutcomeSupport.Create(OperationOutcome.IssueSeverity.Error, OperationOutcome.IssueType.NotSupported,
                                                                                $"No Resource provided for validation, if mode equal (None, Create or Update) then a Resource must be provided to validate against.");
                IssueList.AddRange(OpOutCome.Issue);
                return(FinalResourceServiceOutcome(IssueList));
            }
        }
        private void ObtainOperationItemsFromSearchParameters(ISearchParametersServiceOutcome SearchParametersServiceOutcome, ValidationOperationItems ValidationOperationItems)
        {
            var ProFileSearchParameter = SearchParametersServiceOutcome.SearchParameters.SearchParametersList.SingleOrDefault(x => x.Name == "profile");

            if (ProFileSearchParameter is SearchParameterUri ProfileSearchUri)
            {
                if (ProfileSearchUri.ValueList != null && ProfileSearchUri.ValueList.Count > 0)
                {
                    ValidationOperationItems.ProfileUri = ProfileSearchUri.ValueList[0].Value.OriginalString;
                }
            }

            var ModeSearchParameter = SearchParametersServiceOutcome.SearchParameters.SearchParametersList.SingleOrDefault(x => x.Name == "mode");

            if (ModeSearchParameter != null &&
                ModeSearchParameter is SearchParameterToken ModeSearchUri)
            {
                if (ModeSearchUri.ValueList != null && ModeSearchUri.ValueList.Count > 0)
                {
                    string Mode = ModeSearchUri.ValueList[0].Code;
                    switch (Mode.ToLower())
                    {
                    case "create":
                        ValidationOperationItems.ValidationMode = ResourceValidationModeType.Create;
                        break;

                    case "update":
                        ValidationOperationItems.ValidationMode = ResourceValidationModeType.Update;
                        break;

                    case "delete":
                        ValidationOperationItems.ValidationMode = ResourceValidationModeType.Delete;
                        break;

                    default:
                        ValidationOperationItems.ValidationMode = null;
                        break;
                    }
                }
            }
            else
            {
                ValidationOperationItems.ValidationMode = ResourceValidationModeType.None;
            }
        }
        private void PerformModeValidation(OperationOutcome ModeValidationOpOutCome, ValidationOperationItems ValidationOperationItems, IRequestMeta RequestMeta)
        {
            if (ValidationOperationItems.ValidationMode == ResourceValidationModeType.Create)
            {
                if (!string.IsNullOrWhiteSpace(ValidationOperationItems.ResourceToValidate.Id))
                {
                    var ResourceIdIssue = new OperationOutcome.IssueComponent();
                    ResourceIdIssue.Severity = OperationOutcome.IssueSeverity.Warning;
                    ResourceIdIssue.Code     = OperationOutcome.IssueType.Value;
                    ResourceIdIssue.Details  = new CodeableConcept("http://hl7.org/fhir/ValueSet/operation-outcome", "MSG_RESOURCE_ID_MISMATCH", $"The create(POST) interaction creates a new resource in a server assigned location. If the client wishes to have control over the id of a newly submitted resource, it should use the update interaction instead.The Resource provide was found to contain the id: { ValidationOperationItems.ResourceToValidate.Id }");
                    ResourceIdIssue.Location = new List <string>()
                    {
                        $"{ValidationOperationItems.ResourceToValidate.ResourceType.GetLiteral()}.id"
                    };
                    ModeValidationOpOutCome.Issue.Add(ResourceIdIssue);
                }
            }
            else if (ValidationOperationItems.ValidationMode == ResourceValidationModeType.Update)
            {
                if (string.IsNullOrWhiteSpace(ValidationOperationItems.ResourceToValidate.Id))
                {
                    string Message         = $"The Resource SHALL contain an {ValidationOperationItems.ResourceToValidate.ResourceType.GetLiteral()}.id element to perform an update.";
                    var    ResourceIdIssue = new OperationOutcome.IssueComponent();
                    ResourceIdIssue.Severity = OperationOutcome.IssueSeverity.Warning;
                    ResourceIdIssue.Code     = OperationOutcome.IssueType.Value;
                    ResourceIdIssue.Details  = new CodeableConcept("http://hl7.org/fhir/ValueSet/operation-outcome", "MSG_RESOURCE_ID_MISSING", Message);
                    ResourceIdIssue.Location = new List <string>()
                    {
                        $"{ValidationOperationItems.ResourceToValidate.ResourceType.GetLiteral()}.id"
                    };
                    ModeValidationOpOutCome.Issue.Add(ResourceIdIssue);
                }
            }
            else if (ValidationOperationItems.ValidationMode == ResourceValidationModeType.Delete)
            {
                var ResourceIdToDelete = string.Empty;

                if (RequestMeta.PyroRequestUri != null &&
                    RequestMeta.PyroRequestUri.FhirRequestUri != null &&
                    !string.IsNullOrWhiteSpace(RequestMeta.PyroRequestUri.FhirRequestUri.ResourceId))
                {
                    IRequestMeta RequestMetaGetRead = IRequestMetaFactory.CreateRequestMeta().Set($"{RequestMeta.PyroRequestUri.FhirRequestUri.ResourseName}/{RequestMeta.PyroRequestUri.FhirRequestUri.ResourceId}");
                    var          result             = IResourceServices.GetRead(RequestMetaGetRead.PyroRequestUri.FhirRequestUri.ResourceId, RequestMetaGetRead);
                    if (result.ResourceResult != null)
                    {
                        if (result.IsDeleted.HasValue && result.IsDeleted.Value)
                        {
                            //We have it but it is deleted
                            //There is no resource to delete
                            string Message         = $"The Resource is in the server's history the most current instance is already deleted, {ValidationOperationItems.ResourceToValidate.ResourceType.GetLiteral()}/{ValidationOperationItems.ResourceToValidate.Id}";
                            var    ResourceIdIssue = new OperationOutcome.IssueComponent();
                            ResourceIdIssue.Severity = OperationOutcome.IssueSeverity.Warning;
                            ResourceIdIssue.Code     = OperationOutcome.IssueType.NotFound;
                            ResourceIdIssue.Details  = new CodeableConcept("http://hl7.org/fhir/ValueSet/operation-outcome", "SG_DELETED_ID", Message);
                            ModeValidationOpOutCome.Issue.Add(ResourceIdIssue);
                        }
                    }
                    else
                    {
                        //There is no resource to delete
                        string Message         = $"The Resource is not found in the server, their is no resource to delete for {ValidationOperationItems.ResourceToValidate.ResourceType.GetLiteral()}/{ValidationOperationItems.ResourceToValidate.Id}";
                        var    ResourceIdIssue = new OperationOutcome.IssueComponent();
                        ResourceIdIssue.Severity = OperationOutcome.IssueSeverity.Warning;
                        ResourceIdIssue.Code     = OperationOutcome.IssueType.NotFound;
                        ResourceIdIssue.Details  = new CodeableConcept("http://hl7.org/fhir/ValueSet/operation-outcome", "MSG_DELETED", Message);
                        ModeValidationOpOutCome.Issue.Add(ResourceIdIssue);
                    }
                }
            }
            else if (ValidationOperationItems.ValidationMode == ResourceValidationModeType.None)
            {
                // No Validation required for None.
            }
            else
            {
                throw new System.ComponentModel.InvalidEnumArgumentException(ValidationOperationItems.ValidationMode.ToString(), (int)ValidationOperationItems.ValidationMode, typeof(ResourceValidationModeType));
            }
        }