/// <summary>
        /// Create RSP_K21 message
        /// </summary>
        internal NHapi.Base.Model.IMessage CreateRSP_K21(RegistryQueryResult result, RegistryQueryRequest filter, List <Everest.Connectors.IResultDetail> dtls)
        {
            // Return value
            var retVal = new NHapi.Model.V25.Message.RSP_K21();

            retVal.MSH.MessageType.MessageStructure.Value = "RSP_K21";

            var qak = retVal.QAK;
            var msa = retVal.MSA;
            var dsc = retVal.DSC;
            var qpd = retVal.QPD;

            qak.QueryTag.Value           = result.QueryTag;
            msa.AcknowledgmentCode.Value = "AA";
            if (dtls.Exists(o => o.Type == Everest.Connectors.ResultDetailType.Error))
            {
                qak.QueryResponseStatus.Value = "AE";
                msa.AcknowledgmentCode.Value  = "AE";
                foreach (var dtl in dtls)
                {
                    var err = retVal.GetStructure("ERR", retVal.currentReps("ERR")) as NHapi.Model.V25.Segment.ERR;
                    MessageUtil.UpdateERR(err, dtl, Context);
                }
            }
            else if (result.Results == null || result.Results.Count == 0)
            {
                qak.QueryResponseStatus.Value = "NF";
            }
            else
            {
                // Create the pid
                qak.QueryResponseStatus.Value = "OK";
                qak.HitCount.Value            = result.TotalResults.ToString();
                qak.ThisPayload.Value         = result.Results.Count.ToString();
                //qak.HitsRemaining.Value = (result.TotalResults - result.StartRecordNumber).ToString();
                foreach (RegistrationEvent res in result.Results)
                {
                    var pid = retVal.GetQUERY_RESPONSE(retVal.QUERY_RESPONSERepetitionsUsed);
                    UpdatePID(res, pid.PID, false);
                    UpdateQRI(res, pid.QRI);
                    pid.PID.SetIDPID.Value = retVal.QUERY_RESPONSERepetitionsUsed.ToString();
                }

                // DSC segment?
                if (result.TotalResults > result.Results.Count)
                {
                    retVal.DSC.ContinuationPointer.Value = result.ContinuationPtr;
                    retVal.DSC.ContinuationStyle.Value   = "I";
                }
            }

            // Actual query paramaeters
            var regFilter    = filter.QueryRequest.FindComponent(SVC.Core.ComponentModel.HealthServiceRecordSiteRoleType.SubjectOf) as RegistrationEvent;
            var personFilter = regFilter.FindComponent(SVC.Core.ComponentModel.HealthServiceRecordSiteRoleType.SubjectOf) as Person;

            qpd.QueryTag.Value = filter.QueryTag;
            qpd.MessageQueryName.Identifier.Value = "IHE PDQ Query";
            var terser = new Terser(retVal);
            int qpdRep = 0;

            if (personFilter.GenderCode != null)
            {
                terser.Set(String.Format("/QPD-3({0})-1", qpdRep), "@PID.8");
                terser.Set(String.Format("/QPD-3({0})-2", qpdRep++), personFilter.GenderCode);
            }
            if (personFilter.AlternateIdentifiers != null && personFilter.AlternateIdentifiers.Count > 0)
            {
                var altId = personFilter.AlternateIdentifiers[0];

                if (altId.Domain != null)
                {
                    terser.Set(String.Format("/QPD-3({0})-1", qpdRep), "@PID.3.4.2");
                    terser.Set(String.Format("/QPD-3({0})-2", qpdRep++), altId.Domain);
                    terser.Set(String.Format("/QPD-3({0})-1", qpdRep), "@PID.3.4.3");
                    terser.Set(String.Format("/QPD-3({0})-2", qpdRep++), "ISO");
                }
                if (altId.Identifier != null)
                {
                    terser.Set(String.Format("/QPD-3({0})-1", qpdRep), "@PID.3.1");
                    terser.Set(String.Format("/QPD-3({0})-2", qpdRep++), altId.Identifier);
                }
                if (altId.AssigningAuthority != null)
                {
                    terser.Set(String.Format("/QPD-3({0})-1", qpdRep), "@PID.3.4.1");
                    terser.Set(String.Format("/QPD-3({0})-2", qpdRep++), altId.AssigningAuthority);
                }
            }
            if (personFilter.Names != null && personFilter.Names.Count > 0)
            {
                var name = personFilter.Names[0];
                foreach (var pt in name.Parts)
                {
                    string pidNo = ComponentUtility.XPN_MAP.First(o => o.Value == pt.Type).Key;
                    terser.Set(String.Format("/QPD-3({0})-1", qpdRep), String.Format("@PID.5.{0}", pidNo));
                    terser.Set(String.Format("/QPD-3({0})-2", qpdRep++), pt.Value);
                }
                if (name.Use != NameSet.NameSetUse.Search)
                {
                    terser.Set(String.Format("/QPD-3({0})-1", qpdRep), "@PID.5.7");
                    terser.Set(String.Format("/QPD-3({0})-2", qpdRep++), ComponentUtility.XPN_USE_MAP.First(o => o.Value == name.Use).Key);
                }
            }
            if (personFilter.BirthTime != null)
            {
                terser.Set(String.Format("/QPD-3({0})-1", qpdRep), "@PID.7");
                terser.Set(String.Format("/QPD-3({0})-2", qpdRep++), new TS(personFilter.BirthTime.Value).Value);
            }
            if (personFilter.Addresses != null && personFilter.Addresses.Count > 0)
            {
                var addr = personFilter.Addresses[0];
                foreach (var pt in addr.Parts)
                {
                    string pidNo = ComponentUtility.AD_MAP.First(o => o.Value == pt.PartType).Key;
                    terser.Set(String.Format("/QPD-3({0})-1", qpdRep), String.Format("@PID.11.{0}", pidNo));
                    terser.Set(String.Format("/QPD-3({0})-2", qpdRep++), pt.AddressValue);
                }
                if (addr.Use != AddressSet.AddressSetUse.Search)
                {
                    terser.Set(String.Format("/QPD-3({0})-1", qpdRep), "@PID.11.7");
                    terser.Set(String.Format("/QPD-3({0})-2", qpdRep++), ComponentUtility.AD_USE_MAP.First(o => o.Value == addr.Use).Key);
                }
            }
            var ma = personFilter.FindComponent(SVC.Core.ComponentModel.HealthServiceRecordSiteRoleType.RepresentitiveOf) as PersonalRelationship;

            if (ma != null)
            {
                if (ma.LegalName != null)
                {
                    foreach (var pt in ma.LegalName.Parts)
                    {
                        string pidNo = ComponentUtility.XPN_MAP.First(o => o.Value == pt.Type).Key;
                        terser.Set(String.Format("/QPD-3({0})-1", qpdRep), String.Format("@PID.6.{0}", pidNo));
                        terser.Set(String.Format("/QPD-3({0})-2", qpdRep++), pt.Value);
                    }
                }
                if (ma.AlternateIdentifiers != null && ma.AlternateIdentifiers.Count > 0)
                {
                    var altId = ma.AlternateIdentifiers[0];

                    if (altId.Domain != null)
                    {
                        terser.Set(String.Format("/QPD-3({0})-1", qpdRep), "@PID.21.4.2");
                        terser.Set(String.Format("/QPD-3({0})-2", qpdRep++), altId.Domain);
                        terser.Set(String.Format("/QPD-3({0})-1", qpdRep), "@PID.21.4.3");
                        terser.Set(String.Format("/QPD-3({0})-2", qpdRep++), "ISO");
                    }
                    if (altId.Identifier != null)
                    {
                        terser.Set(String.Format("/QPD-3({0})-1", qpdRep), "@PID.21.1");
                        terser.Set(String.Format("/QPD-3({0})-2", qpdRep++), altId.Identifier);
                    }
                    if (altId.AssigningAuthority != null)
                    {
                        terser.Set(String.Format("/QPD-3({0})-1", qpdRep), "@PID.21.4.1");
                        terser.Set(String.Format("/QPD-3({0})-2", qpdRep++), altId.AssigningAuthority);
                    }
                }
            }
            return(retVal);
        }
        /// <summary>
        /// Handle a received message
        /// </summary>
        /// <param name="e"></param>
        /// <returns></returns>
        public NHapi.Base.Model.IMessage HandleMessage(HL7.TransportProtocol.Hl7MessageReceivedEventArgs e)
        {
            ISystemConfigurationService config = this.Context.GetService(typeof(ISystemConfigurationService)) as ISystemConfigurationService;
            ILocalizationService        locale = this.Context.GetService(typeof(ILocalizationService)) as ILocalizationService;

            // Get the message type
            IMessage response = null;

            try
            {
                if (e.Message.Version == "2.5" || e.Message.Version == "2.3.1")
                {
                    // Get the MSH segment
                    var terser  = new Terser(e.Message);
                    var trigger = terser.Get("/MSH-9-2");
                    Trace.TraceInformation("Message is of type {0} {1}", e.Message.GetType().FullName, trigger);

                    switch (trigger)
                    {
                    case "Q23":
                        if (e.Message is NHapi.Model.V25.Message.QBP_Q21)
                        {
                            response = HandlePixQuery(e.Message as NHapi.Model.V25.Message.QBP_Q21, e);
                        }
                        else
                        {
                            response = MessageUtil.CreateNack(e.Message, "AR", "200", locale.GetString("MSGE074"), config);
                        }
                        break;

                    case "A01":
                    case "A04":
                    case "A05":
                        if (e.Message is NHapi.Model.V231.Message.ADT_A01)
                        {
                            response = HandlePixAdmit(e.Message as NHapi.Model.V231.Message.ADT_A01, e);
                        }
                        else
                        {
                            response = MessageUtil.CreateNack(e.Message, "AR", "200", locale.GetString("MSGE074"), config);
                        }
                        break;

                    case "A08":
                        if (e.Message is NHapi.Model.V231.Message.ADT_A01)
                        {
                            response = HandlePixUpdate(e.Message as NHapi.Model.V231.Message.ADT_A01, e);
                        }
                        else if (e.Message is NHapi.Model.V231.Message.ADT_A08)
                        {
                            response = HandlePixUpdate(e.Message as NHapi.Model.V231.Message.ADT_A08, e);
                        }
                        else
                        {
                            response = MessageUtil.CreateNack(e.Message, "AR", "200", locale.GetString("MSGE074"), config);
                        }
                        break;

                    case "A40":
                        if (e.Message is NHapi.Model.V231.Message.ADT_A39)
                        {
                            response = HandlePixMerge(e.Message as NHapi.Model.V231.Message.ADT_A39, e);
                        }
                        else if (e.Message is NHapi.Model.V231.Message.ADT_A40)
                        {
                            response = HandlePixMerge(e.Message as NHapi.Model.V231.Message.ADT_A40, e);
                        }
                        else
                        {
                            response = MessageUtil.CreateNack(e.Message, "AR", "200", locale.GetString("MSGE074"), config);
                        }
                        break;

                    default:
                        response = MessageUtil.CreateNack(e.Message, "AR", "201", locale.GetString("HL7201"), config);
                        Trace.TraceError("{0} is not a supported trigger", trigger);
                        break;
                    }
                }

                // response still null?
                if (response == null)
                {
                    response = MessageUtil.CreateNack(e.Message, "AR", "203", locale.GetString("HL7203"), config);
                }
            }
            catch (Exception ex)
            {
                Trace.TraceError(ex.ToString());
                response = MessageUtil.CreateNack(e.Message, "AR", "207", ex.Message, config);
            }

            return(response);
        }
        /// <summary>
        /// Update the specified PID
        /// </summary>
        public void UpdatePID(Core.ComponentModel.RegistrationEvent registrationEvent, NHapi.Model.V25.Segment.PID pid, bool summaryOnly)
        {
            var subject = registrationEvent.FindComponent(SVC.Core.ComponentModel.HealthServiceRecordSiteRoleType.SubjectOf) as Person;
            var aut     = registrationEvent.FindComponent(SVC.Core.ComponentModel.HealthServiceRecordSiteRoleType.AuthorOf) as RepositoryDevice;

            // Update time
            pid.LastUpdateDateTime.Time.Value = ((TS)subject.Timestamp).Value;
            if (aut != null)
            {
                pid.LastUpdateFacility.NamespaceID.Value = aut.Jurisdiction;
            }

            // Alternate identifiers
            foreach (var altId in subject.AlternateIdentifiers)
            {
                var id = pid.GetPatientIdentifierList(pid.PatientIdentifierListRepetitionsUsed);
                UpdateCX(altId, id);
            }

            // Other identifiers
            foreach (var othId in subject.OtherIdentifiers)
            {
                var id = pid.GetPatientIdentifierList(pid.PatientIdentifierListRepetitionsUsed);
                UpdateCX(othId.Value, id);

                // Correct v3 codes
                if (othId.Key.CodeSystem == "1.3.6.1.4.1.33349.3.98.12")
                {
                    id.IdentifierTypeCode.Value = othId.Key.Code;
                }
                else if (othId.Key.CodeSystem == "2.16.840.1.113883.2.20.3.85")
                {
                    switch (othId.Key.Code)
                    {
                    case "SIN":
                        id.IdentifierTypeCode.Value = "SS";
                        break;

                    case "DL":
                        id.IdentifierTypeCode.Value = othId.Key.Code;
                        break;

                    default:
                        id.IdentifierTypeCode.Value = null;
                        break;
                    }
                }
                else
                {
                    id.IdentifierTypeCode.Value = null;
                }
            }

            // IHE: This first repetition should be null
            if (summaryOnly)
            {
                pid.GetPatientName(0);
                pid.GetPatientName(1).NameTypeCode.Value = "S";
                return;
            }

            // Populate Names
            if (subject.Names != null)
            {
                foreach (var name in subject.Names)
                {
                    var xpn = pid.GetPatientName(pid.PatientNameRepetitionsUsed);
                    UpdateXPN(name, xpn);
                }
            }

            // Birth time
            if (subject.BirthTime != null)
            {
                MARC.Everest.DataTypes.TS ts = new Everest.DataTypes.TS(subject.BirthTime.Value, ReverseLookup(ComponentUtility.TS_PREC_MAP, subject.BirthTime.Precision));
                pid.DateTimeOfBirth.Time.Value = MARC.Everest.Connectors.Util.ToWireFormat(ts);
            }

            // Admin Sex
            if (subject.GenderCode != null)
            {
                pid.AdministrativeSex.Value = subject.GenderCode;
            }

            // Address
            if (subject.Addresses != null)
            {
                foreach (var addr in subject.Addresses)
                {
                    var ad = pid.GetPatientAddress(pid.PatientAddressRepetitionsUsed);
                    UpdateAD(addr, ad);
                }
            }

            // Death
            if (subject.DeceasedTime != null)
            {
                pid.PatientDeathIndicator.Value = "Y";
                MARC.Everest.DataTypes.TS ts = new Everest.DataTypes.TS(subject.DeceasedTime.Value, ReverseLookup(ComponentUtility.TS_PREC_MAP, subject.DeceasedTime.Precision));
                pid.PatientDeathDateAndTime.Time.Value = MARC.Everest.Connectors.Util.ToWireFormat(ts);
            }

            // MB Order
            if (subject.BirthOrder.HasValue)
            {
                pid.MultipleBirthIndicator.Value = "Y";
                if (subject.BirthOrder.Value > 0)
                {
                    pid.BirthOrder.Value = subject.BirthOrder.ToString();
                }
            }

            // Citizenship
            if (subject.Citizenship != null)
            {
                foreach (var cit in subject.Citizenship)
                {
                    if (cit.Status == SVC.Core.ComponentModel.Components.StatusType.Active)
                    {
                        var c = pid.GetCitizenship(pid.CitizenshipRepetitionsUsed);
                        UpdateCE(new CodeValue(cit.CountryCode, this.m_config.OidRegistrar.GetOid("ISO3166-1").Oid), c);
                    }
                }
            }

            if (subject.MaritalStatus != null)
            {
                UpdateCE(subject.MaritalStatus, pid.MaritalStatus);
            }
            // Language
            if (subject.Language != null)
            {
                foreach (var lang in subject.Language)
                {
                    if (lang.Type == LanguageType.Preferred)
                    {
                        UpdateCE(new CodeValue(lang.Language, this.m_config.OidRegistrar.GetOid("ISO639-1").Oid), pid.PrimaryLanguage);
                        break;
                    }
                }
            }

            // Mothers name
            var relations = subject.FindAllComponents(SVC.Core.ComponentModel.HealthServiceRecordSiteRoleType.RepresentitiveOf);

            foreach (var r in relations)
            {
                if (r is PersonalRelationship)
                {
                    var psn = r as PersonalRelationship;
                    if (psn.RelationshipKind != "MTH")
                    {
                        continue;
                    }

                    if (psn.AlternateIdentifiers != null)
                    {
                        foreach (var altid in psn.AlternateIdentifiers)
                        {
                            var id = pid.GetMotherSIdentifier(pid.MotherSIdentifierRepetitionsUsed);
                            UpdateCX(altid, id);
                        }
                    }
                    if (psn.LegalName != null)
                    {
                        UpdateXPN(psn.LegalName, pid.GetMotherSMaidenName(0));
                    }
                }
            }

            // Telecom addresses
            foreach (var tel in subject.TelecomAddresses)
            {
                if (tel.Use == "HP" && tel.Value.StartsWith("tel"))
                {
                    MessageUtil.XTNFromTel(new TEL()
                    {
                        Value        = tel.Value,
                        Use          = MARC.Everest.Connectors.Util.Convert <SET <CS <TelecommunicationAddressUse> > >(tel.Use),
                        Capabilities = MARC.Everest.Connectors.Util.Convert <SET <CS <TelecommunicationCabability> > >(tel.Capability)
                    }, pid.GetPhoneNumberHome(pid.PhoneNumberHomeRepetitionsUsed));
                }
                else if (tel.Use == "HP")
                {
                    pid.GetPhoneNumberHome(pid.PhoneNumberHomeRepetitionsUsed).EmailAddress.Value = tel.Value;
                }
                else if (tel.Use == "WP" && tel.Value.StartsWith("tel"))
                {
                    MessageUtil.XTNFromTel(new TEL()
                    {
                        Value        = tel.Value,
                        Use          = MARC.Everest.Connectors.Util.Convert <SET <CS <TelecommunicationAddressUse> > >(tel.Use),
                        Capabilities = MARC.Everest.Connectors.Util.Convert <SET <CS <TelecommunicationCabability> > >(tel.Capability)
                    }, pid.GetPhoneNumberBusiness(pid.PhoneNumberBusinessRepetitionsUsed));
                }
                else if (tel.Use == "WP")
                {
                    pid.GetPhoneNumberBusiness(pid.PhoneNumberBusinessRepetitionsUsed).EmailAddress.Value = tel.Value;
                }
            }

            // Race
            if (subject.Race != null)
            {
                foreach (var rc in subject.Race)
                {
                    this.UpdateCE(rc, pid.GetRace(pid.RaceRepetitionsUsed));
                }
            }

            // Ethnic code
            if (subject.EthnicGroup != null)
            {
                foreach (var e in subject.EthnicGroup)
                {
                    this.UpdateCE(e, pid.GetEthnicGroup(pid.EthnicGroupRepetitionsUsed));
                }
            }


            // Place of birth
            if (subject.BirthPlace != null)
            {
                pid.BirthPlace.Value = subject.BirthPlace.Name;
            }
        }
        /// <summary>
        /// Handle a PIX query
        /// </summary>
        private IMessage HandlePixQuery(NHapi.Model.V25.Message.QBP_Q21 request, Hl7MessageReceivedEventArgs evt)
        {
            // Get config
            var config      = this.Context.GetService(typeof(ISystemConfigurationService)) as ISystemConfigurationService;
            var locale      = this.Context.GetService(typeof(ILocalizationService)) as ILocalizationService;
            var dataService = this.Context.GetService(typeof(IClientRegistryDataService)) as IClientRegistryDataService;

            // Create a details array
            List <IResultDetail> dtls = new List <IResultDetail>();

            // Validate the inbound message
            MessageUtil.Validate((IMessage)request, config, dtls, this.Context);

            IMessage response = null;

            // Control
            if (request == null)
            {
                return(null);
            }

            // Construct appropriate audit
            AuditData audit = null;

            // Data controller
            AuditUtil auditUtil = new AuditUtil()
            {
                Context = this.Context
            };

            //DataUtil dataUtil = new DataUtil() { Context = this.Context };

            try
            {
                // Create Query Data
                ComponentUtility cu = new ComponentUtility()
                {
                    Context = this.Context
                };
                DeComponentUtility dcu = new DeComponentUtility()
                {
                    Context = this.Context
                };
                var data = cu.CreateQueryComponents(request, dtls);

                if (data == null)
                {
                    throw new InvalidOperationException(locale.GetString("MSGE00A"));
                }


                RegistryQueryResult result = dataService.Query(data);
                dtls.AddRange(result.Details);

                // Update locations?
                foreach (var dtl in dtls)
                {
                    if (dtl is PatientNotFoundResultDetail)
                    {
                        dtl.Location = "QPD^1^3^1^1";
                    }
                    else if (dtl is UnrecognizedPatientDomainResultDetail)
                    {
                        dtl.Location = "QPD^1^3^1^4";
                    }
                    else if (dtl is UnrecognizedTargetDomainResultDetail)
                    {
                        dtl.Location = "QPD^1^4^";
                    }
                }


                audit = auditUtil.CreateAuditData("ITI-9", ActionType.Execute, OutcomeIndicator.Success, evt, result);

                // Now process the result
                response = dcu.CreateRSP_K23(result, dtls);
                //var r = dcu.CreateRSP_K23(null, null);
                // Copy QPD
                try
                {
                    (response as NHapi.Model.V25.Message.RSP_K23).QPD.MessageQueryName.Identifier.Value = request.QPD.MessageQueryName.Identifier.Value;
                    Terser reqTerser = new Terser(request),
                           rspTerser = new Terser(response);
                    rspTerser.Set("/QPD-1", reqTerser.Get("/QPD-1"));
                    rspTerser.Set("/QPD-2", reqTerser.Get("/QPD-2"));
                    rspTerser.Set("/QPD-3-1", reqTerser.Get("/QPD-3-1"));
                    rspTerser.Set("/QPD-3-4-1", reqTerser.Get("/QPD-3-4-1"));
                    rspTerser.Set("/QPD-3-4-2", reqTerser.Get("/QPD-3-4-2"));
                    rspTerser.Set("/QPD-3-4-3", reqTerser.Get("/QPD-3-4-3"));
                    rspTerser.Set("/QPD-4-1", reqTerser.Get("/QPD-4-1"));
                    rspTerser.Set("/QPD-4-4-1", reqTerser.Get("/QPD-4-4-1"));
                    rspTerser.Set("/QPD-4-4-2", reqTerser.Get("/QPD-4-4-2"));
                    rspTerser.Set("/QPD-4-4-3", reqTerser.Get("/QPD-4-4-3"));
                }
                catch (Exception e)
                {
                    Trace.TraceError(e.ToString());
                }
                //MessageUtil.((response as NHapi.Model.V25.Message.RSP_K23).QPD, request.QPD);

                MessageUtil.UpdateMSH(new NHapi.Base.Util.Terser(response), request, config);
            }
            catch (Exception e)
            {
                Trace.TraceError(e.ToString());
                if (!dtls.Exists(o => o is UnrecognizedPatientDomainResultDetail || o is UnrecognizedTargetDomainResultDetail || o.Message == e.Message || o.Exception == e))
                {
                    dtls.Add(new ResultDetail(ResultDetailType.Error, e.Message, e));
                }
                response = MessageUtil.CreateNack(request, dtls, this.Context, typeof(RSP_K23));
                Terser errTerser = new Terser(response);
                // HACK: Fix the generic ACK with a real ACK for this message
                errTerser.Set("/MSH-9-2", "K23");
                errTerser.Set("/MSH-9-3", "RSP_K23");
                errTerser.Set("/QAK-2", "AE");
                errTerser.Set("/MSA-1", "AE");
                errTerser.Set("/QAK-1", request.QPD.QueryTag.Value);
                audit = auditUtil.CreateAuditData("ITI-9", ActionType.Execute, OutcomeIndicator.EpicFail, evt, new List <VersionedDomainIdentifier>());
            }
            finally
            {
                IAuditorService auditSvc = this.Context.GetService(typeof(IAuditorService)) as IAuditorService;
                if (auditSvc != null)
                {
                    auditSvc.SendAudit(audit);
                }
            }

            return(response);
        }
        /// <summary>
        /// Handle a PIX admission
        /// </summary>
        private IMessage HandlePixAdmit(NHapi.Model.V231.Message.ADT_A01 request, Hl7MessageReceivedEventArgs evt)
        {
            // Get config
            var config      = this.Context.GetService(typeof(ISystemConfigurationService)) as ISystemConfigurationService;
            var locale      = this.Context.GetService(typeof(ILocalizationService)) as ILocalizationService;
            var dataService = this.Context.GetService(typeof(IClientRegistryDataService)) as IClientRegistryDataService;
            // Create a details array
            List <IResultDetail> dtls = new List <IResultDetail>();

            // Validate the inbound message
            MessageUtil.Validate((IMessage)request, config, dtls, this.Context);

            IMessage response = null;

            // Control
            if (request == null)
            {
                return(null);
            }

            // Data controller
            AuditUtil auditUtil = new AuditUtil()
            {
                Context = this.Context
            };
            //DataUtil dataUtil = new DataUtil() { Context = this.Context };

            // Construct appropriate audit
            AuditData audit = null;

            try
            {
                // Create Query Data
                ComponentUtility cu = new ComponentUtility()
                {
                    Context = this.Context
                };
                DeComponentUtility dcu = new DeComponentUtility()
                {
                    Context = this.Context
                };
                var data = cu.CreateComponents(request, dtls);
                if (data == null)
                {
                    throw new InvalidOperationException(locale.GetString("MSGE00A"));
                }

                var result = dataService.Register(data, request.MSH.ProcessingID.ProcessingID.Value == "P" ? DataPersistenceMode.Production : DataPersistenceMode.Debugging);
                if (result == null || result.VersionId == null)
                {
                    throw new InvalidOperationException(locale.GetString("DTPE001"));
                }

                dtls.AddRange(result.Details);

                audit = auditUtil.CreateAuditData("ITI-8", result.VersionId.UpdateMode == UpdateModeType.Update ? ActionType.Update : ActionType.Create, OutcomeIndicator.Success, evt, new List <VersionedDomainIdentifier>()
                {
                    result.VersionId
                });

                // Now process the result
                response = MessageUtil.CreateNack(request, dtls, this.Context, typeof(NHapi.Model.V231.Message.ACK));
                MessageUtil.UpdateMSH(new NHapi.Base.Util.Terser(response), request, config);
                (response as NHapi.Model.V231.Message.ACK).MSH.MessageType.TriggerEvent.Value = request.MSH.MessageType.TriggerEvent.Value;
                (response as NHapi.Model.V231.Message.ACK).MSH.MessageType.MessageType.Value  = "ACK";
            }
            catch (Exception e)
            {
                Trace.TraceError(e.ToString());
                if (!dtls.Exists(o => o.Message == e.Message || o.Exception == e))
                {
                    dtls.Add(new ResultDetail(ResultDetailType.Error, e.Message, e));
                }
                response = MessageUtil.CreateNack(request, dtls, this.Context, typeof(NHapi.Model.V231.Message.ACK));
                audit    = auditUtil.CreateAuditData("ITI-8", ActionType.Create, OutcomeIndicator.EpicFail, evt, new List <VersionedDomainIdentifier>());
            }
            finally
            {
                IAuditorService auditSvc = this.Context.GetService(typeof(IAuditorService)) as IAuditorService;
                if (auditSvc != null)
                {
                    auditSvc.SendAudit(audit);
                }
            }
            return(response);
        }
        /// <summary>
        /// Handle the PIX merge request
        /// </summary>
        private IMessage HandlePixMerge(NHapi.Model.V231.Message.ADT_A39 request, Hl7MessageReceivedEventArgs evt)
        {
            // Get config
            var config      = this.Context.GetService(typeof(ISystemConfigurationService)) as ISystemConfigurationService;
            var locale      = this.Context.GetService(typeof(ILocalizationService)) as ILocalizationService;
            var dataService = this.Context.GetService(typeof(IClientRegistryDataService)) as IClientRegistryDataService;

            // Create a details array
            List <IResultDetail> dtls = new List <IResultDetail>();

            // Validate the inbound message
            MessageUtil.Validate((IMessage)request, config, dtls, this.Context);

            IMessage response = null;

            // Control
            if (request == null)
            {
                return(null);
            }

            // Data controller
            //DataUtil dataUtil = new DataUtil() { Context = this.Context };
            AuditUtil auditUtil = new AuditUtil()
            {
                Context = this.Context
            };

            // Construct appropriate audit
            List <AuditData> audit = new List <AuditData>();

            try
            {
                // Create Query Data
                ComponentUtility cu = new ComponentUtility()
                {
                    Context = this.Context
                };
                DeComponentUtility dcu = new DeComponentUtility()
                {
                    Context = this.Context
                };
                var data = cu.CreateComponents(request, dtls);
                if (data == null)
                {
                    throw new InvalidOperationException(locale.GetString("MSGE00A"));
                }

                // Merge
                var result = dataService.Merge(data, request.MSH.ProcessingID.ProcessingID.Value == "P" ? DataPersistenceMode.Production : DataPersistenceMode.Debugging);

                if (result == null || result.VersionId == null)
                {
                    throw new InvalidOperationException(locale.GetString("DTPE001"));
                }

                List <VersionedDomainIdentifier> deletedRecordIds = new List <VersionedDomainIdentifier>(),
                                                 updatedRecordIds = new List <VersionedDomainIdentifier>();

                // Subjects
                var oidData = config.OidRegistrar.GetOid("CR_CID").Oid;
                foreach (Person subj in data.FindAllComponents(SVC.Core.ComponentModel.HealthServiceRecordSiteRoleType.SubjectOf))
                {
                    PersonRegistrationRef replcd = subj.FindComponent(SVC.Core.ComponentModel.HealthServiceRecordSiteRoleType.ReplacementOf) as PersonRegistrationRef;
                    deletedRecordIds.Add(new VersionedDomainIdentifier()
                    {
                        Identifier = replcd.Id.ToString(),
                        Domain     = oidData
                    });
                    updatedRecordIds.Add(new VersionedDomainIdentifier()
                    {
                        Identifier = subj.Id.ToString(),
                        Domain     = oidData
                    });
                }

                // Now audit
                audit.Add(auditUtil.CreateAuditData("ITI-8", ActionType.Delete, OutcomeIndicator.Success, evt, deletedRecordIds));
                audit.Add(auditUtil.CreateAuditData("ITI-8", ActionType.Update, OutcomeIndicator.Success, evt, updatedRecordIds));
                // Now process the result
                response = MessageUtil.CreateNack(request, dtls, this.Context, typeof(NHapi.Model.V231.Message.ACK));
                MessageUtil.UpdateMSH(new NHapi.Base.Util.Terser(response), request, config);
                (response as NHapi.Model.V231.Message.ACK).MSH.MessageType.TriggerEvent.Value = request.MSH.MessageType.TriggerEvent.Value;
                (response as NHapi.Model.V231.Message.ACK).MSH.MessageType.MessageType.Value  = "ACK";
            }
            catch (Exception e)
            {
                Trace.TraceError(e.ToString());
                if (!dtls.Exists(o => o.Message == e.Message || o.Exception == e))
                {
                    dtls.Add(new ResultDetail(ResultDetailType.Error, e.Message, e));
                }
                response = MessageUtil.CreateNack(request, dtls, this.Context, typeof(NHapi.Model.V231.Message.ACK));
                audit.Add(auditUtil.CreateAuditData("ITI-8", ActionType.Delete, OutcomeIndicator.EpicFail, evt, new List <VersionedDomainIdentifier>()));
            }
            finally
            {
                IAuditorService auditSvc = this.Context.GetService(typeof(IAuditorService)) as IAuditorService;
                if (auditSvc != null)
                {
                    foreach (var aud in audit)
                    {
                        auditSvc.SendAudit(aud);
                    }
                }
            }
            return(response);
        }
        /// <summary>
        /// Handle the pdq query
        /// </summary>
        private IMessage HandlePdqQuery(QBP_Q21 request, Hl7MessageReceivedEventArgs evt)
        {
            // Get config
            var config      = this.Context.GetService(typeof(ISystemConfigurationService)) as ISystemConfigurationService;
            var locale      = this.Context.GetService(typeof(ILocalizationService)) as ILocalizationService;
            var dataService = this.Context.GetService(typeof(IClientRegistryDataService)) as IClientRegistryDataService;

            // Create a details array
            List <IResultDetail> dtls = new List <IResultDetail>();

            // Validate the inbound message
            MessageUtil.Validate((IMessage)request, config, dtls, this.Context);

            IMessage response = null;

            // Control
            if (request == null)
            {
                return(null);
            }


            // Data controller
            //DataUtil dataUtil = new DataUtil() { Context = this.Context };
            AuditUtil auditUtil = new AuditUtil()
            {
                Context = this.Context
            };
            // Construct appropriate audit
            AuditData audit = null;

            try
            {
                // Create Query Data
                ComponentUtility cu = new ComponentUtility()
                {
                    Context = this.Context
                };
                DeComponentUtility dcu = new DeComponentUtility()
                {
                    Context = this.Context
                };
                var data = cu.CreateQueryComponentsPdq(request, dtls);
                if (data == null)
                {
                    Trace.TraceError("{0} problems mapping message:", dtls.Count);
                    foreach (var itm in dtls)
                    {
                        Trace.TraceError($"\t{itm.Type} : {itm.Message}");
                    }
                    throw new InvalidOperationException();// locale?.GetString("MSGE00A") ?? "Could not process components");
                }

                // Is this a continue or new query?
                RegistryQueryResult result = dataService.Query(data);

                audit = auditUtil.CreateAuditData("ITI-21", ActionType.Execute, OutcomeIndicator.Success, evt, result);

                // Now process the result
                response = dcu.CreateRSP_K21(result, data, dtls);
                //MessageUtil.CopyQPD((response as RSP_K21).QPD, request.QPD, data);
                MessageUtil.UpdateMSH(new NHapi.Base.Util.Terser(response), request, config);
                Terser ters = new Terser(response);
                ters.Set("/MSH-9-2", "K22");
            }
            catch (Exception e)
            {
                Trace.TraceError(e.ToString());


                if (!dtls.Exists(o => o.Message == e.Message || o.Exception == e))
                {
                    if (dtls.Count == 0)
                    {
                        dtls.Add(new ResultDetail(ResultDetailType.Error, e.Message, e));
                    }
                }
                // HACK: Only one error allowed in nHAPI for some reason :
                // TODO: Fix NHapi
                dtls.RemoveAll(o => o.Type != ResultDetailType.Error);
                while (dtls.Count > 1)
                {
                    dtls.RemoveAt(1);
                }
                response = MessageUtil.CreateNack(request, dtls, this.Context, typeof(RSP_K21));

                Terser errTerser = new Terser(response);
                // HACK: Fix the generic ACK with a real ACK for this message
                errTerser.Set("/MSH-9-2", "K22");
                errTerser.Set("/MSH-9-3", "RSP_K21");
                errTerser.Set("/QAK-2", "AE");
                errTerser.Set("/MSA-1", "AE");
                errTerser.Set("/QAK-1", request.QPD.QueryTag.Value);
                audit = auditUtil.CreateAuditData("ITI-21", ActionType.Execute, OutcomeIndicator.EpicFail, evt, new List <VersionedDomainIdentifier>());
            }
            finally
            {
                IAuditorService auditSvc = this.Context.GetService(typeof(IAuditorService)) as IAuditorService;
                if (auditSvc != null)
                {
                    auditSvc.SendAudit(audit);
                }
            }

            return(response);
        }
        /// <summary>
        /// Update the NK1 segment
        /// </summary>
        private void UpdateNK1(PersonalRelationship subject, NK1 nk1)
        {
            if (subject.AlternateIdentifiers != null)
            {
                foreach (var altId in subject.AlternateIdentifiers)
                {
                    UpdateCX(altId, nk1.GetNextOfKinAssociatedPartySIdentifiers(nk1.NextOfKinAssociatedPartySIdentifiersRepetitionsUsed));
                }
            }

            // Birth time
            if (subject.BirthTime != null)
            {
                MARC.Everest.DataTypes.TS ts = new Everest.DataTypes.TS(subject.BirthTime.Value, ReverseLookup(ComponentUtility.TS_PREC_MAP, subject.BirthTime.Precision));
                nk1.DateTimeOfBirth.Time.Value = MARC.Everest.Connectors.Util.ToWireFormat(ts);
            }

            if (subject.GenderCode != null)
            {
                nk1.AdministrativeSex.Value = subject.GenderCode;
            }

            if (subject.LegalName != null)
            {
                UpdateXPN(subject.LegalName, nk1.GetName(0));
            }

            if (subject.PerminantAddress != null)
            {
                UpdateAD(subject.PerminantAddress, nk1.GetAddress(0));
            }

            if (subject.RelationshipKind != null)
            {
                nk1.Relationship.Identifier.Value = subject.RelationshipKind;
            }

            if (subject.TelecomAddresses != null)
            {
                foreach (var tel in subject.TelecomAddresses)
                {
                    if (tel.Use == "HP" && tel.Value.StartsWith("tel"))
                    {
                        MessageUtil.XTNFromTel(new TEL()
                        {
                            Value        = tel.Value,
                            Use          = MARC.Everest.Connectors.Util.Convert <SET <CS <TelecommunicationAddressUse> > >(tel.Use),
                            Capabilities = MARC.Everest.Connectors.Util.Convert <SET <CS <TelecommunicationCabability> > >(tel.Capability)
                        }, nk1.GetContactPersonSTelephoneNumber(nk1.ContactPersonSTelephoneNumberRepetitionsUsed));
                    }
                    else if (tel.Use == "HP")
                    {
                        nk1.GetPhoneNumber(nk1.ContactPersonSTelephoneNumberRepetitionsUsed).EmailAddress.Value = tel.Value;
                    }
                    else if (tel.Use == "WP" && tel.Value.StartsWith("tel"))
                    {
                        MessageUtil.XTNFromTel(new TEL()
                        {
                            Value        = tel.Value,
                            Use          = MARC.Everest.Connectors.Util.Convert <SET <CS <TelecommunicationAddressUse> > >(tel.Use),
                            Capabilities = MARC.Everest.Connectors.Util.Convert <SET <CS <TelecommunicationCabability> > >(tel.Capability)
                        }, nk1.GetContactPersonSTelephoneNumber(nk1.ContactPersonSTelephoneNumberRepetitionsUsed));
                    }
                    else if (tel.Use == "WP")
                    {
                        nk1.GetPhoneNumber(nk1.ContactPersonSTelephoneNumberRepetitionsUsed).EmailAddress.Value = tel.Value;
                    }
                }
            }
        }