public async Task <IActionResult> Read(string logicalId)
        {
            //TODO: Update to reflect new ID parameter
            var request = FhirRequest.Create(logicalId, ResourceType.DocumentReference, null, Request, RequestingAsid());

            var result = await _nrlsSearch.Get(request);

            if (result == null)
            {
                return(NotFound(OperationOutcomeFactory.CreateNotFound(logicalId)));
            }

            if ((result as DocumentReference).Status != DocumentReferenceStatus.Current)
            {
                return(BadRequest(OperationOutcomeFactory.CreateInactiveDocumentReference()));
            }

            return(Ok(result));
        }
        /// <summary>
        /// Update a DocumentReference using the id in the path or by Master Identifier
        /// </summary>
        /// <remarks>
        /// First we do a search to get the document, then we check the incoming ASID associated OrgCode against the custodian on the document.
        /// If valid we can patch.
        /// We use the FhirMaintain service and FhirSearch service to facilitate this
        /// </remarks>
        public async SystemTasks.Task <OperationOutcome> Patch(FhirRequest request)
        {
            ValidateResource(request.StrResourceType);

            request.ProfileUri = _resourceProfile;

            // NRLS Layers of validation before Fhir Delete Call
            //If we have id path segment we should have nothing else
            if (!string.IsNullOrEmpty(request.Id) && (!string.IsNullOrEmpty(request.IdentifierParameter) || !string.IsNullOrEmpty(request.SubjectParameter)))
            {
                throw new HttpFhirException("Invalid query parameters for Update by Logical Id", OperationOutcomeFactory.CreateInvalidParameter("Invalid query parameters for Update by Logical Id"), HttpStatusCode.BadRequest);
            }

            var identifier = request.IdentifierParameter;
            var identifierValidationResult = _fhirValidation.ValidateIdentifierParameter("identifier", identifier);
            var subject = request.SubjectParameter;
            var subjectValidationResult = _fhirValidation.ValidatePatientParameter(subject);


            if (string.IsNullOrEmpty(request.Id) && identifierValidationResult != null && subjectValidationResult != null)
            {
                throw new HttpFhirException("Missing or Invalid id", OperationOutcomeFactory.CreateInvalidParameter("Invalid parameter: id"), HttpStatusCode.BadRequest);
            }

            if (string.IsNullOrEmpty(request.Id) && identifierValidationResult == null && subjectValidationResult != null)
            {
                throw new HttpFhirException("Missing or Invalid subject parameter", OperationOutcomeFactory.CreateInvalidParameter("Invalid parameter: subject"), HttpStatusCode.BadRequest);
            }

            if (string.IsNullOrEmpty(request.Id) && identifierValidationResult != null && subjectValidationResult == null)
            {
                throw new HttpFhirException("Missing or Invalid identifier parameter", OperationOutcomeFactory.CreateInvalidParameter("Invalid parameter: identifier"), HttpStatusCode.BadRequest);
            }

            var parameters = request.Resource as Parameters;

            var validParameters = _fhirValidation.ValidateParameters(parameters);

            if (!validParameters.Success)
            {
                throw new HttpFhirException("Missing or Invalid parameter", validParameters, HttpStatusCode.BadRequest);
            }

            Resource documentBundle;

            if (!string.IsNullOrEmpty(request.Id))
            {
                ObjectId mongoId;

                if (!ObjectId.TryParse(request.Id, out mongoId))
                {
                    throw new HttpFhirException("Invalid id parameter", OperationOutcomeFactory.CreateInvalidParameter("Invalid parameter", $"The Logical ID format does not apply to the given Logical ID - {request.Id}"), HttpStatusCode.BadRequest);
                }

                request.IsIdQuery = true;

                documentBundle = await _fhirSearch.GetAsBundle <DocumentReference>(request);
            }
            else
            {
                documentBundle = await _fhirSearch.GetByMasterId <DocumentReference>(request);
            }

            var    documentResponse = ParseRead(documentBundle, request.Id);
            string oldVersionId;

            if (documentResponse.ResourceType == ResourceType.Bundle)
            {
                var result = documentResponse as Bundle;

                if (!result.Total.HasValue || result.Total.Value < 1 || result.Entry.FirstOrDefault() == null)
                {
                    return(OperationOutcomeFactory.CreateNotFound(request.Id));
                }

                var orgDocument = result.Entry.FirstOrDefault().Resource as DocumentReference;
                oldVersionId = orgDocument.Meta?.VersionId;

                var orgCode = _fhirValidation.GetOrganizationReferenceId(orgDocument.Custodian);

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

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

                if (orgDocument.Status != DocumentReferenceStatus.Current)
                {
                    //Only allowed to transition to entered-in-error from current
                    return(OperationOutcomeFactory.CreateInactiveDocumentReference());
                }

                if (string.IsNullOrEmpty(request.Id))
                {
                    request.Id = orgDocument.Id;
                }
            }
            else
            {
                return(documentResponse as OperationOutcome);
            }


            UpdateDefinition <BsonDocument> updates = null;

            BuildEnteredInError(oldVersionId, out updates);

            var patched = await _fhirMaintain.Update <DocumentReference>(request, updates);

            if (!patched)
            {
                return(OperationOutcomeFactory.CreateNotFound(request.Id));
            }

            return(OperationOutcomeFactory.CreateUpdated(request.RequestUrl?.AbsoluteUri, request.AuditId));
        }
        public async SystemTasks.Task <Resource> ValidateConditionalUpdate(FhirRequest request)
        {
            if (!request.Resource.ResourceType.Equals(ResourceType.DocumentReference))
            {
                return(OperationOutcomeFactory.CreateInvalidResource("relatesTo"));
            }

            var document = request.Resource as DocumentReference;

            var relatesTo = _fhirValidation.GetValidRelatesTo(document.RelatesTo);

            if (document.RelatesTo.Count == 0)
            {
                //skip checks, request is just a standard create
                return(null);
            }
            else if (relatesTo.element == null)
            {
                return(OperationOutcomeFactory.CreateInvalidResource(relatesTo.issue));
            }

            //Subject already validated during ValidateCreate
            //relatesTo Reference/Identifier already validated during ValidateCreate => validPointer

            var isRelatesToReference = !string.IsNullOrWhiteSpace(relatesTo.element.Target.Reference);

            FhirRequest       pointerRequest = null;
            DocumentReference oldDocument    = null;

            if (isRelatesToReference)
            {
                var pointerId = _fhirValidation.GetReferenceId(relatesTo.element.Target);
                pointerRequest = NrlsPointerHelper.CreateReferenceSearch(request, pointerId);
                oldDocument    = await _fhirSearch.Get <DocumentReference>(pointerRequest);
            }
            else
            {
                var subjectNhsNumber = _fhirValidation.GetSubjectReferenceId(document.Subject);
                pointerRequest = NrlsPointerHelper.CreateMasterIdentifierSearch(request, relatesTo.element.Target.Identifier, subjectNhsNumber);
                var pointers = await _fhirSearch.Find <DocumentReference>(pointerRequest);

                //There should only ever be zero or one
                oldDocument = pointers.Entry.FirstOrDefault()?.Resource as DocumentReference;
            }

            if (oldDocument == null)
            {
                //Cant find related document
                return(OperationOutcomeFactory.CreateInvalidResource("relatesTo.target", "Referenced DocumentReference does not exist."));
            }

            //related document does not have same patient
            if (string.IsNullOrEmpty(oldDocument.Subject.Reference) || oldDocument.Subject.Reference != document.Subject.Reference)
            {
                return(OperationOutcomeFactory.CreateInvalidResource("relatesTo.target", "Resolved DocumentReference is not associated with the same patient."));
            }

            //Reference type checks
            if (isRelatesToReference)
            {
                //related document does not have masterIdentifier or masterIdentifier does not match new
                var docRelatesToIdentifier = document.RelatesTo.First().Target.Identifier;
                if (docRelatesToIdentifier != null)
                {
                    var oldDocRelatesToIdentifier = oldDocument.MasterIdentifier;

                    if (oldDocRelatesToIdentifier == null)
                    {
                        return(OperationOutcomeFactory.CreateInvalidResource("relatesTo.target", "Resolved DocumentReference does not have an MasterIdentifier."));
                    }

                    if (string.IsNullOrWhiteSpace(docRelatesToIdentifier.System) || string.IsNullOrWhiteSpace(docRelatesToIdentifier.Value) ||
                        docRelatesToIdentifier.Value != oldDocRelatesToIdentifier.Value || docRelatesToIdentifier.System != oldDocRelatesToIdentifier.System)
                    {
                        return(OperationOutcomeFactory.CreateInvalidResource("relatesTo.target", "Resolved DocumentReference does not have a matching MasterIdentifier."));
                    }
                }
            }

            //Custodian already validated against incoming ASID during ValidateCreate
            var custodianOdsCode = _fhirValidation.GetOrganizationReferenceId(document.Custodian);

            if (oldDocument.Custodian == null || string.IsNullOrEmpty(oldDocument.Custodian.Reference) || oldDocument.Custodian.Reference != $"{FhirConstants.SystemODS}{custodianOdsCode}")
            {
                //related document does not have same custodian
                return(OperationOutcomeFactory.CreateInvalidResource("relatesTo.target", $"Resolved DocumentReference is not associated with custodian {custodianOdsCode}"));
            }

            if (oldDocument.Status != DocumentReferenceStatus.Current)
            {
                //Only allowed to transition to superseded from current
                return(OperationOutcomeFactory.CreateInactiveDocumentReference());
            }

            return(oldDocument);
        }