/// <summary>
        /// Provide a fault
        /// </summary>
        public bool ProvideFault(Exception error, RestResponseMessage response)
        {
            this.m_tracer.TraceEvent(EventLevel.Error, "Error on WCF FHIR Pipeline: {0}", error);

            RestOperationContext.Current.OutgoingResponse.StatusCode = ClassifyErrorCode(error);
            if (RestOperationContext.Current.OutgoingResponse.StatusCode == 401)
            {
                // Get to the root of the error
                while (error.InnerException != null)
                {
                    error = error.InnerException;
                }

                if (error is PolicyViolationException pve)
                {
                    var method = RestOperationContext.Current.AppliedPolicies.Any(o => o.GetType().Name.Contains("Basic")) ? "Basic" : "Bearer";
                    response.AddAuthenticateHeader(method, RestOperationContext.Current.IncomingRequest.Url.Host, "insufficient_scope", pve.PolicyId, error.Message);
                }
                else if (error is SecurityTokenException ste)
                {
                    response.AddAuthenticateHeader("Bearer", RestOperationContext.Current.IncomingRequest.Url.Host, "token_error", description: ste.Message);
                }
                else if (error is SecuritySessionException ses)
                {
                    switch (ses.Type)
                    {
                    case SessionExceptionType.Expired:
                    case SessionExceptionType.NotYetValid:
                    case SessionExceptionType.NotEstablished:
                        response.StatusCode = (int)System.Net.HttpStatusCode.Unauthorized;
                        response.AddAuthenticateHeader("Bearer", RestOperationContext.Current.IncomingRequest.Url.Host, "unauthorized", PermissionPolicyIdentifiers.Login, ses.Message);
                        break;

                    default:
                        response.StatusCode = (int)System.Net.HttpStatusCode.Forbidden;
                        break;
                    }
                }
            }

            var errorResult = DataTypeConverter.CreateErrorResult(error);

            // Return error in XML only at this point
            new FhirMessageDispatchFormatter().SerializeResponse(response, null, errorResult);
            return(true);
        }
        /// <summary>
        /// Invoke the process message operation
        /// </summary>
        public Resource Invoke(Parameters parameters)
        {
            // Extract the parameters
            var contentParameter = parameters.Parameter.Find(o => o.Name == "content")?.Resource as Bundle;
            var asyncParameter   = parameters.Parameter.Find(o => o.Name == "async")?.Value as FhirBoolean;

            if (contentParameter == null)
            {
                this.m_tracer.TraceError("Missing content parameter");
                throw new ArgumentNullException(m_localizationService.GetString("error.type.ArgumentNullException"));
            }
            else if (asyncParameter?.Value.GetValueOrDefault() == true)
            {
                this.m_tracer.TraceError("Asynchronous messaging is not supported by this repository");
                throw new InvalidOperationException(m_localizationService.GetString("error.type.NotSupportedException"));
            }

            // Message must have a message header
            var messageHeader = contentParameter.Entry.Find(o => o.Resource.TryDeriveResourceType(out ResourceType rt) && rt == ResourceType.MessageHeader)?.Resource as MessageHeader;

            if (messageHeader == null)
            {
                this.m_tracer.TraceError("Message bundle does not contain a MessageHeader");
                throw new ArgumentException(m_localizationService.GetString("error.type.ArgumentNullException"));
            }

            // Determine the appropriate action handler
            if (messageHeader.Event is FhirUri eventUri)
            {
                var handler = ExtensionUtil.GetMessageOperationHandler(new Uri(eventUri.Value));
                if (handler == null)
                {
                    this.m_tracer.TraceError($"There is no message handler for event {eventUri}");
                    throw new NotSupportedException(m_localizationService.GetString("error.type.NotSupportedException"));
                }

                var retVal = new Bundle(); // Return for operation
                retVal.Meta = new Meta()
                {
                    LastUpdated = DateTimeOffset.Now
                };
                var uuid = Guid.NewGuid();
                try
                {
                    // HACK: The .EndsWith is a total hack - FHIR wants .FullUrl to be absolute, but many senders will send relative references which
                    var opReturn = handler.Invoke(messageHeader, contentParameter.Entry.Where(o => messageHeader.Focus.Any(f => o.FullUrl == f.Reference || $"{o.Resource.TypeName}/{o.Resource.Id}" == f.Reference)).ToArray());

                    retVal.Entry.Add(new Bundle.EntryComponent()
                    {
                        FullUrl  = $"urn:uuid:{uuid}",
                        Resource = new MessageHeader()
                        {
                            Id       = uuid.ToString(),
                            Response = new MessageHeader.ResponseComponent()
                            {
                                Code    = MessageHeader.ResponseType.Ok,
                                Details = new ResourceReference($"urn:uuid:{opReturn.Id}")
                            }
                        }
                    });

                    // HACK: Another hack - FullUrl is assumed to be a UUID because I'm not turning an id of XXX and trying to derive a fullUrl for something that is in a
                    // bundle anyways
                    retVal.Entry.Add(new Bundle.EntryComponent()
                    {
                        FullUrl  = $"urn:uuid:{opReturn.Id}",
                        Resource = opReturn
                    });
                }
                catch (Exception e)
                {
                    var outcome = DataTypeConverter.CreateErrorResult(e);
                    outcome.Id = Guid.NewGuid().ToString();
                    retVal.Entry.Add(new Bundle.EntryComponent()
                    {
                        FullUrl  = $"urn:uuid:{uuid}",
                        Resource = new MessageHeader()
                        {
                            Id       = uuid.ToString(),
                            Response = new MessageHeader.ResponseComponent()
                            {
                                Code    = MessageHeader.ResponseType.FatalError,
                                Details = new ResourceReference($"urn:uuid:{outcome.Id}")
                            }
                        }
                    });

                    retVal.Entry.Add(new Bundle.EntryComponent()
                    {
                        FullUrl  = $"urn:uuid:{outcome.Id}",
                        Resource = outcome
                    });

                    throw new FhirException((System.Net.HttpStatusCode)FhirErrorEndpointBehavior.ClassifyErrorCode(e), retVal, m_localizationService.GetString("error.type.FhirException"), e);
                }
                finally
                {
                    retVal.Timestamp = DateTime.Now;
                    retVal.Type      = Bundle.BundleType.Message;
                }
                return(retVal);
            }
            else
            {
                this.m_tracer.TraceError("Currently message headers with EventCoding are not supported");
                throw new InvalidOperationException(m_localizationService.GetString("error.type.NotSupportedException.userMessage"));
            }
        }
        /// <summary>
        /// Install dataset using FHIR services
        /// </summary>
        public void InstallDataset(object sender, EventArgs e)
        {
            using (AuthenticationContext.EnterSystemContext())
            {
                // Data directory
                var dataDirectory  = Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), "data", "fhir");
                var fhirXmlParser  = new FhirXmlParser();
                var fhirJsonParser = new FhirJsonParser();

                if (!Directory.Exists(dataDirectory))
                {
                    Directory.CreateDirectory(dataDirectory);
                }

                this.m_traceSource.TraceInfo("Scanning Directory {0} for FHIR objects", dataDirectory);

                // Process
                foreach (var f in Directory.GetFiles(dataDirectory, "*.*"))
                {
                    try
                    {
                        Resource fhirResource = null;

                        switch (Path.GetExtension(f).ToLowerInvariant())
                        {
                        case ".json":
                            using (var fs = File.OpenRead(f))
                                using (var tr = new StreamReader(fs))
                                    using (var jr = new JsonTextReader(tr))
                                    {
                                        fhirResource = fhirJsonParser.Parse(jr) as Resource;
                                    }

                            break;

                        case ".xml":
                            using (var fs = File.OpenRead(f))
                                using (var xr = XmlReader.Create(fs))
                                {
                                    fhirResource = fhirXmlParser.Parse(xr) as Resource;
                                }

                            break;

                        case ".completed":
                        case ".response":
                            continue;     // skip file
                        }

                        // No FHIR resource
                        if (fhirResource == null)
                        {
                            throw new InvalidOperationException($"Could not parse a FHIR resource from {f}");
                        }

                        // Process the resource
                        if (!fhirResource.TryDeriveResourceType(out var rt))
                        {
                            throw new InvalidOperationException($"FHIR API doesn't support {fhirResource.TypeName}");
                        }

                        var handler = FhirResourceHandlerUtil.GetResourceHandler(rt);
                        if (handler == null)
                        {
                            throw new InvalidOperationException($"This instance of SanteMPI does not support {rt}");
                        }

                        // Handle the resource
                        Resource fhirResult = null;
                        try
                        {
                            fhirResult = handler.Create(fhirResource, TransactionMode.Commit);
                            File.Move(f, Path.ChangeExtension(f, "completed")); // Move to completed so it is not processed again.
                        }
                        catch (Exception ex)
                        {
                            this.m_traceSource.TraceError("Error Applying Dataset: {0}", ex);
                            fhirResult = DataTypeConverter.CreateErrorResult(ex);
                        }

                        // Write the response
                        using (var fs = File.Create(Path.ChangeExtension(f, "response")))
                        {
                            switch (Path.GetExtension(f).ToLowerInvariant())
                            {
                            case ".json":
                                using (var tw = new StreamWriter(fs))
                                    using (var jw = new JsonTextWriter(tw))
                                    {
                                        new FhirJsonSerializer().Serialize(fhirResult, jw);
                                    }

                                break;

                            case ".xml":
                                using (var xw = XmlWriter.Create(fs))
                                {
                                    new FhirXmlSerializer().Serialize(fhirResult, xw);
                                }

                                break;
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        this.m_traceSource.TraceError("Error applying {0}: {1}", f, ex);
                        throw;
                    }
                }
            }
        }