public void CreateOrganizationNotFound_Is_Valid()
        {
            var actual = OperationOutcomeFactory.CreateOrganizationNotFound("testid");

            //Base checks for all OperactionOutcomes
            Assert.IsType <OperationOutcome>(actual);

            //Assert.NotNull(actual.Meta);
            //Assert.NotNull(actual.Meta.Profile);
            //Assert.NotEmpty(actual.Meta.Profile);
            //Assert.Contains("https://fhir.nhs.uk/STU3/StructureDefinition/Spine-OperationOutcome-1-0", actual.Meta.Profile);

            Assert.NotNull(actual.Issue);
            Assert.NotEmpty(actual.Issue);

            Assert.NotNull(actual.Issue.First().Details);
            Assert.NotNull(actual.Issue.First().Details.Coding);
            Assert.NotEmpty(actual.Issue.First().Details.Coding);


            //Specific OperationOutcome checks
            Assert.Equal("The ODS code in the custodian and/or author element is not resolvable – testid.", actual.Issue.First().Diagnostics);
            Assert.Equal(OperationOutcome.IssueType.NotFound.ToString(), actual.Issue.First().Code.ToString());
            Assert.Equal(OperationOutcome.IssueSeverity.Error.ToString(), actual.Issue.First().Severity.ToString());

            Assert.Equal("ORGANISATION_NOT_FOUND", actual.Issue.First().Details.Coding.First().Code);
            Assert.Equal("Organisation record not found", actual.Issue.First().Details.Coding.First().Display);
            Assert.Equal("https://fhir.nhs.uk/STU3/CodeSystem/Spine-ErrorOrWarningCode-1", actual.Issue.First().Details.Coding.First().System);
        }
        /// <summary>
        /// Search for Documents or Get one by _id
        /// </summary>
        /// <remarks>
        /// As the NRLS is implemented with just a search and not read, to read a document the _id parameter is supplied
        /// </remarks>
        public async Task <Bundle> Find(FhirRequest request)
        {
            ValidateResource(request.StrResourceType);

            request.ProfileUri = _resourceProfile;

            var id = request.IdParameter;

            //We are going to be strict hear for search and only proceed if we have valid parameters
            if (request.InvalidParameters.Count() > 0)
            {
                throw new HttpFhirException("Invalid parameters", OperationOutcomeFactory.CreateInvalidParameter($"Invalid parameter: {string.Join(", ", request.InvalidParameters)}"), HttpStatusCode.BadRequest);
            }

            //If we have an _id param it should be the only param so check for that here.
            if (request.HasIdParameter)
            {
                ObjectId mongoId;
                if (!ObjectId.TryParse(id, out mongoId))
                {
                    throw new HttpFhirException("Invalid _id parameter", OperationOutcomeFactory.CreateNotFound(id), HttpStatusCode.NotFound);
                }

                if (request.QueryParameters.Count() > 1)
                {
                    throw new HttpFhirException("Invalid _id parameter combination", OperationOutcomeFactory.CreateInvalidParameter("Invalid parameter: _id"), HttpStatusCode.BadRequest);
                }

                request.Id        = id;
                request.IsIdQuery = true;

                var results = await _fhirSearch.GetAsBundle <DocumentReference>(request);

                var response = ParseRead(results, id) as Bundle;

                return(response);
            }

            //If we are here then it is a standard search query
            var patient = request.QueryParameters.FirstOrDefault(x => x.Item1 == "subject");

            if (patient != null)
            {
                var invalidPatient = _fhirValidation.ValidatePatientParameter(patient.Item2);

                if (invalidPatient != null)
                {
                    throw new HttpFhirException("Missing or Invalid patient parameter", invalidPatient, HttpStatusCode.BadRequest);
                }

                var nhsNumber = _fhirValidation.GetSubjectReferenceParameterId(patient.Item2);

                var patientRequest = NrlsPointerHelper.CreatePatientSearch(request, nhsNumber);
                var patients       = await _fhirSearch.Find <Patient>(patientRequest);

                if (patients.Entry.Count == 0)
                {
                    throw new HttpFhirException("Unknown patient", OperationOutcomeFactory.CreatePatientNotFound(nhsNumber), HttpStatusCode.NotFound);
                }
            }
            else
            {
                throw new HttpFhirException("Missing or Invalid patient parameter", OperationOutcomeFactory.CreateInvalidParameter("Missing parameter: subject"), HttpStatusCode.BadRequest);
            }

            var custodian = request.QueryParameters.FirstOrDefault(x => x.Item1 == "custodian");
            var useCustodianIdentifierValidation = false;

            if (custodian == null)
            {
                //temporarily also support the incorrectly spec'd custodian.identifier parameter
                //custodian is a reference type and should not be used in this way
                custodian = request.QueryParameters.FirstOrDefault(x => x.Item1 == "custodian.identifier");

                useCustodianIdentifierValidation = custodian != null;
            }

            if (custodian != null)
            {
                //temporarily also support the incorrectly spec'd custodian.identifier parameter
                var invalidCustodian = useCustodianIdentifierValidation ? _fhirValidation.ValidateCustodianIdentifierParameter(custodian.Item2) :
                                       _fhirValidation.ValidateCustodianParameter(custodian.Item2);

                if (invalidCustodian != null)
                {
                    throw new HttpFhirException("Missing or Invalid custodian parameter", invalidCustodian, HttpStatusCode.BadRequest);
                }

                var custodianOrgCode = useCustodianIdentifierValidation? _fhirValidation.GetOrganizationParameterIdentifierId(custodian.Item2) :
                                       _fhirValidation.GetOrganizationParameterId(custodian.Item2);

                var custodianRequest = NrlsPointerHelper.CreateOrgSearch(request, custodianOrgCode);
                var custodians       = await _fhirSearch.Find <Organization>(custodianRequest);

                if (custodians.Entry.Count == 0)
                {
                    var invalidOrg = OperationOutcomeFactory.CreateOrganizationNotFound(custodianOrgCode);

                    throw new HttpFhirException("Missing or Invalid custodian parameter", invalidOrg, HttpStatusCode.NotFound);
                }

                //This is now out of scope
                //var invalidOrgInteraction = ValidateOrganisationInteraction(request.RequestingAsid, custodianOrgCode, true);

                //if (invalidOrgInteraction != null)
                //{
                //    throw new HttpFhirException("Invalid Provider Request Exception", invalidOrgInteraction, HttpStatusCode.Unauthorized);
                //}
            }

            var type = request.QueryParameters.FirstOrDefault(x => x.Item1 == "type.coding");

            if (type != null)
            {
                var invalidType = _fhirValidation.ValidTypeParameter(type.Item2);

                if (invalidType != null)
                {
                    throw new HttpFhirException("Missing or Invalid type parameter", invalidType, HttpStatusCode.BadRequest);
                }
            }

            var summary = request.QueryParameters.FirstOrDefault(x => x.Item1 == "_summary");

            if (summary != null)
            {
                var validSummaryParams          = new string[] { "subject", "_format", "_summary" };
                var invalidSummaryParams        = request.QueryParameters.Where(x => !validSummaryParams.Contains(x.Item1));
                OperationOutcome invalidSummary = null;

                if (invalidSummaryParams.Any())
                {
                    var invalidSummaryParamsList = string.Join(", ", invalidSummaryParams.Select(x => $"{x.Item1}={x.Item2}"));

                    invalidSummary = OperationOutcomeFactory.CreateInvalidParameter("Invalid parameter", $"Unsupported search parameter - {invalidSummaryParamsList}");

                    throw new HttpFhirException("Missing or Invalid type parameter", invalidSummary, HttpStatusCode.BadRequest);
                }

                invalidSummary = _fhirValidation.ValidSummaryParameter(summary.Item2);

                if (invalidSummary != null)
                {
                    throw new HttpFhirException("Missing or Invalid type parameter", invalidSummary, HttpStatusCode.BadRequest);
                }

                request.IsSummary = true;
            }

            //Only allow current pointers
            var queryParameters = request.QueryParameters.ToList();

            queryParameters.Add(new Tuple <string, string>("status", "current"));
            request.QueryParameters   = queryParameters;
            request.AllowedParameters = request.AllowedParameters.Concat(new string[] { "status" }).ToArray();

            return(await _fhirSearch.Find <DocumentReference>(request));
        }
        public async SystemTasks.Task <OperationOutcome> ValidateCreate(FhirRequest request)
        {
            ValidateResource(request.StrResourceType);

            request.ProfileUri = _resourceProfile;

            // NRLS Layers of validation before Fhir Search Call
            var document = request.Resource as DocumentReference;

            //NRL Pointer validation
            var validProfile = _fhirValidation.ValidPointer(document);

            if (!validProfile.Success)
            {
                throw new HttpFhirException("Invalid NRLS Pointer", validProfile, HttpStatusCode.BadRequest);
            }


            //Now we need to do some additional validation on ODS codes && Master Ids
            //We need to use an external source (in reality yes but we are just going to do an internal query to fake ods & pointer search)

            if (document.MasterIdentifier != null)
            {
                var nhsNumber = _fhirValidation.GetSubjectReferenceId(document.Subject);

                var masterIdentifierRequest = NrlsPointerHelper.CreateMasterIdentifierSearch(request, document.MasterIdentifier, nhsNumber);
                var miPointers = await _fhirSearch.GetByMasterId <DocumentReference>(masterIdentifierRequest);

                if (miPointers.Entry.Count > 0)
                {
                    return(OperationOutcomeFactory.CreateDuplicateRequest(document.MasterIdentifier));
                }
            }


            var custodianOrgCode = _fhirValidation.GetOrganizationReferenceId(document.Custodian);

            var invalidAsid = InvalidAsid(custodianOrgCode, request.RequestingAsid);

            if (invalidAsid != null)
            {
                return(invalidAsid);
            }

            var custodianRequest = NrlsPointerHelper.CreateOrgSearch(request, custodianOrgCode);
            var custodians       = await _fhirSearch.Find <Organization>(custodianRequest);

            if (custodians.Entry.Count == 0)
            {
                return(OperationOutcomeFactory.CreateOrganizationNotFound(custodianOrgCode));
            }

            var authorOrgCode = _fhirValidation.GetOrganizationReferenceId(document.Author?.FirstOrDefault());
            var authorRequest = NrlsPointerHelper.CreateOrgSearch(request, authorOrgCode);
            var authors       = await _fhirSearch.Find <Organization>(authorRequest);

            if (authors.Entry.Count == 0)
            {
                return(OperationOutcomeFactory.CreateOrganizationNotFound(authorOrgCode));
            }

            //To better mimic NRL here we would create a new patient record for a patient that is not currently know (aka no clinical record)

            return(null);
        }