public static Resource GetRequest(string id, NameValueCollection queryParam)
        {
            Resource fhirResource = null;

            try
            {
                string identifier = GetIdentifier(id, queryParam);

                if (string.IsNullOrEmpty(identifier))
                {
                    fhirResource = GetAllOperationDefinitions(queryParam);
                }
                else
                {
                    fhirResource = GetOperationDefinition(identifier, queryParam);
                }
            }
            catch (Exception ex)
            {
                if (ex.Message == MISSING_OPDEF_IDENTIFIER)
                {
                    return(OperationOutcome.ForMessage("No Operation Definition id or identifer in Request", OperationOutcome.IssueType.BusinessRule, OperationOutcome.IssueSeverity.Error));
                }
                else if (ex.Message == UNFOUND_OPDEF_IDENTIFIER)
                {
                    return(OperationOutcome.ForMessage("Operation Definition not found", OperationOutcome.IssueType.BusinessRule, OperationOutcome.IssueSeverity.Error));
                }
                else
                {
                    return(OperationOutcome.ForMessage(ex.Message, OperationOutcome.IssueType.Unknown, OperationOutcome.IssueSeverity.Error));
                }
            }

            return(fhirResource);
        }
        private static Resource GetRequest(string identifier, NameValueCollection queryParam)
        {
            if (string.IsNullOrEmpty(identifier))
            {
                return(OperationOutcome.ForMessage("No NamingSystem id or identifer in Request", OperationOutcome.IssueType.BusinessRule, OperationOutcome.IssueSeverity.Error));
            }

            NamingSystem namingSystem     = new NamingSystem();
            string       resourceFilePath = Path.GetDirectoryName(new Uri(Assembly.GetExecutingAssembly().CodeBase).LocalPath) + @"\Test Files\";

            FhirXmlParser fxp = new FhirXmlParser();

            if (identifier.ToUpper() == "NHI" || identifier == DIGITAL_HEALTH_NZ + "/id/nhi" || identifier == "2.16.840.1.113883.2.18.2")
            {
                namingSystem = fxp.Parse <NamingSystem>(File.ReadAllText(resourceFilePath + "NamingSystem_NHI.xml"));
            }
            else if (identifier.ToUpper() == "HPI-CPN" || identifier == DIGITAL_HEALTH_NZ + "/id/hpi-person" || identifier == "2.16.840.1.113883.2.18.3.1")
            {
                namingSystem = fxp.Parse <NamingSystem>(File.ReadAllText(resourceFilePath + "NamingSystem_HPI_CPN.xml"));
            }
            else if (identifier.ToUpper() == "HPI-FAC" || identifier == DIGITAL_HEALTH_NZ + "/id/hpi-facility" || identifier == "2.16.840.1.113883.2.18.3.2")
            {
                namingSystem = fxp.Parse <NamingSystem>(File.ReadAllText(resourceFilePath + "NamingSystem_HPI_FAC.xml"));
            }
            else if (identifier.ToUpper() == "HPI-ORG" || identifier == DIGITAL_HEALTH_NZ + "/id/hpi-organisation" || identifier == "2.16.840.1.113883.2.18.3.3")
            {
                namingSystem = fxp.Parse <NamingSystem>(File.ReadAllText(resourceFilePath + "NamingSystem_HPI_ORG.xml"));
            }
            else if (identifier.ToUpper() == "NZMT" || identifier == NzMt.URI || identifier == "2.16.840.1.113883.2.18.21")
            {
                namingSystem = fxp.Parse <NamingSystem>(File.ReadAllText(resourceFilePath + "NamingSystem_NZMT.xml"));
            }
            else if (identifier.ToUpper() == "NZ_ETHNICITY_LEVEL_1" || identifier == NzEthnicityL1.URI || identifier == "2.16.840.1.113883.2.18.11")
            {
                namingSystem = fxp.Parse <NamingSystem>(File.ReadAllText(resourceFilePath + "NamingSystem_NZ_ETHNICITY_LEVEL_1.xml"));
            }
            else if (identifier.ToUpper() == "NZ_ETHNICITY_LEVEL_2" || identifier == NzEthnicityL2.URI || identifier == "2.16.840.1.113883.2.18.11.1")
            {
                namingSystem = fxp.Parse <NamingSystem>(File.ReadAllText(resourceFilePath + "NamingSystem_NZ_ETHNICITY_LEVEL_2.xml"));
            }
            else if (identifier.ToUpper() == "NZ_ETHNICITY_LEVEL_3" || identifier == NzEthnicityL3.URI || identifier == "2.16.840.1.113883.2.18.11.2")
            {
                namingSystem = fxp.Parse <NamingSystem>(File.ReadAllText(resourceFilePath + "NamingSystem_NZ_ETHNICITY_LEVEL_3.xml"));
            }
            else if (identifier.ToUpper() == "NZ_ETHNICITY_LEVEL_4" || identifier == NzEthnicityL4.URI || identifier == "2.16.840.1.113883.2.18.11.5")
            {
                namingSystem = fxp.Parse <NamingSystem>(File.ReadAllText(resourceFilePath + "NamingSystem_NZ_ETHNICITY_LEVEL_4.xml"));
            }
            else
            {
                return(OperationOutcome.ForMessage("Naming System Not Recognised.", OperationOutcome.IssueType.Unknown, OperationOutcome.IssueSeverity.Error));
            }

            AddNarrative(namingSystem);

            return(namingSystem);
        }
        public static Resource GetRequest(string id, string operation, NameValueCollection queryParam)
        {
            Resource fhirResource = null;

            try
            {
                string identifier = GetIdentifier(id, queryParam);

                // check requested operation
                if (string.IsNullOrEmpty(operation))
                {
                    if (string.IsNullOrEmpty(identifier))
                    {
                        fhirResource = GetAllNamingSystems(queryParam);
                    }
                    else
                    {
                        fhirResource = GetRequest(identifier, queryParam);
                    }
                }
                else if (operation == "$preferred-id")
                {
                    fhirResource = PreferredIdOperation(id, queryParam);
                }
                else
                {
                    return(OperationOutcome.ForMessage("Unrecognised Operation in Request..." + operation, OperationOutcome.IssueType.Unknown, OperationOutcome.IssueSeverity.Error));
                }
            }
            catch (Exception ex)
            {
                if (ex.Message == MISSING_NS_IDENTIFIER)
                {
                    return(OperationOutcome.ForMessage("No Naming System id or identifer in Request", OperationOutcome.IssueType.BusinessRule, OperationOutcome.IssueSeverity.Error));
                }
                else if (ex.Message == MISSING_NS_TYPE)
                {
                    return(OperationOutcome.ForMessage("No Naming System Type in Request", OperationOutcome.IssueType.BusinessRule, OperationOutcome.IssueSeverity.Error));
                }
                else if (ex.Message == UNFOUND_NS_IDENTIFIER)
                {
                    return(OperationOutcome.ForMessage("Naming System Preferred Identifier not found", OperationOutcome.IssueType.BusinessRule, OperationOutcome.IssueSeverity.Error));
                }
                else
                {
                    return(OperationOutcome.ForMessage(ex.Message, OperationOutcome.IssueType.Unknown, OperationOutcome.IssueSeverity.Error));
                }
            }

            return(fhirResource);
        }
        private static Resource GetAllCodeSystems(NameValueCollection queryParam)
        {
            string contentMode = Utilities.GetQueryValue("content-mode", queryParam);
            string supplements = Utilities.GetQueryValue("supplements", queryParam);

            if (supplements == "bundle-type" || supplements == "http://hl7.org/fhir/bundle-type")
            {
                return(GetRequest("bundle-type-german", string.Empty, queryParam));
            }

            Bundle csBundle = new Bundle();

            csBundle.Id   = Guid.NewGuid().ToString();
            csBundle.Type = Bundle.BundleType.Searchset;
            csBundle.Link.Add(new Bundle.LinkComponent {
                Url = ServerCapability.TERMINZ_CANONICAL + "/CodeSystem", Relation = "self"
            });

            if (string.IsNullOrEmpty(contentMode) || contentMode == "not-present")
            {
                csBundle.AddResourceEntry(GetRequest(string.Empty, FhirSnomed.URI, queryParam), FhirSnomed.URI);
                csBundle.AddResourceEntry(GetRequest(string.Empty, FhirLoinc.URI, queryParam), FhirLoinc.URI);
                csBundle.AddResourceEntry(GetRequest(string.Empty, NzMt.URI, queryParam), NzMt.URI);
                csBundle.AddResourceEntry(GetRequest(string.Empty, FhirRxNorm.URI, queryParam), FhirRxNorm.URI);
            }

            if (string.IsNullOrEmpty(contentMode) || contentMode == "complete")
            {
                csBundle.AddResourceEntry(GetRequest("NzEthnicityL1", string.Empty, queryParam), NzEthnicityL1.URI);
                csBundle.AddResourceEntry(GetRequest("NzEthnicityL2", string.Empty, queryParam), NzEthnicityL2.URI);
                csBundle.AddResourceEntry(GetRequest("NzEthnicityL3", string.Empty, queryParam), NzEthnicityL3.URI);
                csBundle.AddResourceEntry(GetRequest("NzEthnicityL4", string.Empty, queryParam), NzEthnicityL4.URI);
                csBundle.AddResourceEntry(GetRequest("NzRegion", string.Empty, queryParam), NzRegion.URI);
                csBundle.AddResourceEntry(GetRequest("bundle-type", string.Empty, queryParam), "http://hl7.org/fhir/bundle-type");
            }

            if (string.IsNullOrEmpty(contentMode) || contentMode == "supplement")
            {
                csBundle.AddResourceEntry(GetRequest("bundle-type-german", string.Empty, queryParam), "http://hl7.org/fhir/bundle-type-de");
            }

            csBundle.Total = csBundle.Entry.Count();

            if (csBundle.Total == 0)
            {
                return(OperationOutcome.ForMessage("No Code Systems match search parameter values.", OperationOutcome.IssueType.NotFound, OperationOutcome.IssueSeverity.Information));
            }

            return(csBundle);
        }
Example #5
0
        public async Task GivenPatients_WhenSearchedWithInvalidSearchAndSortParamsAndHandlingStrict_ThenErrorReturnedWithMessage()
        {
            var tag      = Guid.NewGuid().ToString();
            var patients = await CreatePatients(tag);

            OperationOutcome expectedOperationOutcome = OperationOutcome.ForMessage(
                string.Format(CultureInfo.InvariantCulture, Core.Resources.SortParameterValueIsNotValidSearchParameter, _unsupportedSearchAndSortParam, "Patient"),
                OperationOutcome.IssueType.Invalid,
                OperationOutcome.IssueSeverity.Error);

            await ExecuteAndValidateErrorOperationOutcomeAsync(
                $"Patient?_tag={tag}&_sort={_unsupportedSearchAndSortParam}",
                new Tuple <string, string>("Prefer", "handling=strict"),
                HttpStatusCode.BadRequest,
                expectedOperationOutcome);
        }
Example #6
0
        public async Task GivenPatients_WhenSearchedWithInvalidSearchAndSortParamsAndHandlingLenient_ThenPatientsAreReturnedUnsortedWithWarning()
        {
            var tag = Guid.NewGuid().ToString();

            Patient[] patients = await CreatePatients(tag);

            Resource[] expectedResources = new Resource[patients.Length + 1];
            expectedResources[0] = OperationOutcome.ForMessage(
                string.Format(CultureInfo.InvariantCulture, Core.Resources.SortParameterValueIsNotValidSearchParameter, _unsupportedSearchAndSortParam, "Patient"),
                OperationOutcome.IssueType.NotSupported,
                OperationOutcome.IssueSeverity.Warning);
            patients.Cast <Resource>().ToArray().CopyTo(expectedResources, 1);

            await ExecuteAndValidateBundle(
                $"Patient?_tag={tag}&_sort={_unsupportedSearchAndSortParam}",
                true, // Server sort will fail, so sort expected result and actual result before comparing.
                true, // Turn on test logic for invalid sort parameter.
                new Tuple <string, string>("Prefer", "handling=lenient"),
                expectedResources);
        }
        private static Resource GetAllNamingSystems(NameValueCollection queryParam)
        {
            string kind = Utilities.GetQueryValue("kind", queryParam);

            Bundle nsBundle = new Bundle
            {
                Id   = Guid.NewGuid().ToString(),
                Type = Bundle.BundleType.Searchset
            };

            nsBundle.Link.Add(new Bundle.LinkComponent {
                Url = ServerCapability.TERMINZ_CANONICAL + "/NamingSystem", Relation = "self"
            });

            if (string.IsNullOrEmpty(kind) || kind == "identifier")
            {
                nsBundle.AddResourceEntry(GetRequest("NHI", queryParam), ServerCapability.TERMINZ_CANONICAL + "/NamingSystem/NHI");
                nsBundle.AddResourceEntry(GetRequest("HPI-CPN", queryParam), ServerCapability.TERMINZ_CANONICAL + "/NamingSystem/HPI-CPN");
                nsBundle.AddResourceEntry(GetRequest("HPI-FAC", queryParam), ServerCapability.TERMINZ_CANONICAL + "/NamingSystem/HPI-FAC");
                nsBundle.AddResourceEntry(GetRequest("HPI-ORG", queryParam), ServerCapability.TERMINZ_CANONICAL + "/NamingSystem/HPI-ORG");
            }

            if (string.IsNullOrEmpty(kind) || kind == "codesystem")
            {
                nsBundle.AddResourceEntry(GetRequest("NZMT", queryParam), "/NamingSystem/NZMT");
                nsBundle.AddResourceEntry(GetRequest("NZ_ETHNICITY_LEVEL_1", queryParam), ServerCapability.TERMINZ_CANONICAL + "/NamingSystem/NZ_ETHNICITY_LEVEL_1");
                nsBundle.AddResourceEntry(GetRequest("NZ_ETHNICITY_LEVEL_2", queryParam), ServerCapability.TERMINZ_CANONICAL + "/NamingSystem/NZ_ETHNICITY_LEVEL_2");
                nsBundle.AddResourceEntry(GetRequest("NZ_ETHNICITY_LEVEL_3", queryParam), ServerCapability.TERMINZ_CANONICAL + "/NamingSystem/NZ_ETHNICITY_LEVEL_3");
                nsBundle.AddResourceEntry(GetRequest("NZ_ETHNICITY_LEVEL_4", queryParam), ServerCapability.TERMINZ_CANONICAL + "/NamingSystem/NZ_ETHNICITY_LEVEL_4");
            }

            nsBundle.Total = nsBundle.Entry.Count();

            if (nsBundle.Total == 0)
            {
                return(OperationOutcome.ForMessage("No Naming Systems match search parameter values.", OperationOutcome.IssueType.NotFound, OperationOutcome.IssueSeverity.Information));
            }

            return(nsBundle);
        }
        internal static Resource GetFhirResource(string resource, string id, string operation, NameValueCollection queryParams, string fhirVersion)
        {
            Resource fhirResource = null;

            try
            {
                if (fhirVersion == "r2")
                {
                    fhirResource = OperationOutcome.ForMessage("FHIR r2/DSTU2 not supported by this server", OperationOutcome.IssueType.BusinessRule);
                }
                else if (fhirVersion == "r3")
                {
                    fhirResource = OperationOutcome.ForMessage("FHIR r3/STU3 not supported by this server", OperationOutcome.IssueType.BusinessRule);
                }
                else if (string.IsNullOrEmpty(resource) && operation == "$versions")
                {
                    fhirResource = ServerCapability.GetVersions();
                }
                else if (resource == "metadata")
                {
                    fhirResource = ServerCapability.GetStatement(queryParams);
                }
                else if (resource == "TerminologyCapabilities")
                {
                    fhirResource = TerminologyCapability.GetStatement(true);
                }
                else if (resource == "OperationDefinition")
                {
                    fhirResource = ConformanceOperationDefinition.GetRequest(id, queryParams);
                }
                else if (resource == "CodeSystem")
                {
                    fhirResource = TerminologyCodeSystem.PerformOperation(id, operation, queryParams);
                }
                else if (resource == "ConceptMap" || operation == "$closure")
                {
                    fhirResource = TerminologyConceptMap.PerformOperation(id, operation, queryParams);
                }
                else if (resource == "ValueSet")
                {
                    fhirResource = TerminologyValueSet.PerformOperation(id, operation, queryParams);
                }
                else if (resource == "NamingSystem")
                {
                    fhirResource = TerminologyNamingSystem.GetRequest(id, operation, queryParams);
                }
                else if (resource == "Location")
                {
                    fhirResource = AdministrationLocation.GetRequest(id, queryParams);
                }
                else if (resource == "Organization")
                {
                    fhirResource = AdministrationOrganisation.GetRequest(id, queryParams);
                }
                else
                {
                    fhirResource = OperationOutcome.ForMessage("No module could be found to handle the request '" + resource + "'", OperationOutcome.IssueType.NotFound);
                }
            }
            catch (Exception ex)
            {
                Log.Write("ERROR: " + ex.ToString(), LogLevel.ExceptionOnly);
                throw;
            }

            return(fhirResource);
        }
        public Stream TerminzBatch()
        {
            string rv = string.Empty;

            string responseType = GetResponseType();
            string fhirVersion  = GetFhirVersion();

            // get Bundle from the Request Stream

            string       reqBody   = string.Empty;
            UTF8Encoding enc       = new UTF8Encoding();
            Stream       reqStream = OperationContext.Current.RequestContext.RequestMessage.GetBody <Stream>();

            using (StreamReader reader = new StreamReader(reqStream, enc))
            {
                reqBody = reader.ReadToEnd();
            }

            string reqType = WebOperationContext.Current.IncomingRequest.ContentType.ToLower();

            Resource fhirResource;

            if (reqType.Contains("json"))
            {
                FhirJsonParser fjp = new FhirJsonParser();
                fhirResource = fjp.Parse <Resource>(reqBody);
            }
            else
            {
                FhirXmlParser fxp = new FhirXmlParser();
                fhirResource = fxp.Parse <Resource>(reqBody);
            }

            if (fhirResource.ResourceType == ResourceType.Bundle)
            {
                Bundle fb = (Bundle)fhirResource;
                if (fb.Type == Bundle.BundleType.Batch)
                {
                    Bundle responseBundle = new Bundle();

                    responseBundle.Id   = Guid.NewGuid().ToString();
                    responseBundle.Type = Bundle.BundleType.BatchResponse;

                    foreach (Bundle.EntryComponent comp in fb.Entry)
                    {
                        Bundle.RequestComponent rc = comp.Request;

                        if (rc.Method == Bundle.HTTPVerb.GET)
                        {
                            if (rc.Url.IndexOf("$validate-code") > 0)
                            {
                                // extract and parse query string to get parameters
                                int    qsPos       = rc.Url.IndexOf('?');
                                string querystring = (qsPos < rc.Url.Length - 1) ? rc.Url.Substring(qsPos + 1) : String.Empty;
                                qParam = System.Web.HttpUtility.ParseQueryString(querystring);
                                // extract resource (CodeSystem or ValueSet) ID
                                string resourceID   = string.Empty;
                                string resourceName = resourceID.IndexOf("/ValueSet/") > 0 ? "ValueSet" : "CodeSystem";
                                try
                                {
                                    resourceID = rc.Url.Remove(qsPos);
                                    int resNamePos = resourceID.IndexOf("/" + resourceName + "/");
                                    resourceID = resourceID.Substring(resNamePos + 9).Replace("/", "").Replace("$validate-code", "");
                                }
                                catch { }
                                ServiceInterface appSi = new ServiceInterface();
                                responseBundle.AddResourceEntry(appSi.GetFhirResource(resourceName, resourceID, "$validate-code", qParam, fhirVersion), string.Empty);
                            }
                            else
                            {
                                responseBundle.AddResourceEntry(OperationOutcome.ForMessage("Unrecognised Operation in Request..." + rc.Url, OperationOutcome.IssueType.Unknown), string.Empty);
                            }
                        }
                        else if (rc.Method == Bundle.HTTPVerb.POST)
                        {
                            if (rc.Url.IndexOf("$translate") > 0 && comp.Resource.ResourceType == ResourceType.Parameters)
                            {
                                // extract ConceptMap ID
                                string cmID = string.Empty;
                                try
                                {
                                    cmID = rc.Url.Replace("ConceptMap/", "").Replace("$translate", "").Replace("/", "");
                                }
                                catch { }
                                // get parameters
                                Parameters fParam = (Parameters)comp.Resource;
                                SetQueryParameters(fParam);
                                ServiceInterface appSi = new ServiceInterface();
                                responseBundle.AddResourceEntry(appSi.GetFhirResource("ConceptMap", cmID, "$translate", qParam, fhirVersion), string.Empty);
                            }
                            else
                            {
                                responseBundle.AddResourceEntry(OperationOutcome.ForMessage("Unrecognised Operation in Request..." + rc.Url, OperationOutcome.IssueType.Unknown), string.Empty);
                            }
                        }
                        else
                        {
                            responseBundle.AddResourceEntry(OperationOutcome.ForMessage("Method Not Supported in Batch Mode '" + rc.Method.ToString() + "'", OperationOutcome.IssueType.NotSupported), string.Empty);
                        }
                    }

                    fhirResource = responseBundle;
                }
                else
                {
                    fhirResource = OperationOutcome.ForMessage("No module could be found to handle the bundle type '" + fb.TypeName + "'", OperationOutcome.IssueType.NotFound);
                }
            }
            else
            {
                fhirResource = OperationOutcome.ForMessage("No module could be found to handle the request '" + fhirResource.ResourceType.ToString() + "'", OperationOutcome.IssueType.NotFound);
            }

            if (fhirResource.ResourceType == ResourceType.OperationOutcome)
            {
                AddNarrativeToOperationOutcome(fhirResource);
                OutgoingWebResponseContext response = WebOperationContext.Current.OutgoingResponse;
                response.StatusCode = HttpStatusCode.BadRequest;
                // if wish for more granular response codes, need Issue Type
                //OperationOutcome oo = (OperationOutcome)fhirResource;
                //OperationOutcome.IssueType opOutcome = (OperationOutcome.IssueType)oo.Issue[0].Code;
            }

            // convert to stream to remove leading XML elements and json quotes
            rv = SerializeResponse(fhirResource, responseType, SummaryType.False);
            return(new System.IO.MemoryStream(UTF8Encoding.Default.GetBytes(rv)));
        }
        // entry method - handles all exceptions (converts to outcome operations)
        public static Resource PerformOperation(string id, string operation, NameValueCollection queryParam)
        {
            Resource fhirResource = null;

            try
            {
                string identifier = GetIdentifier(id, queryParam);
                string systemURL  = GetSystem(queryParam);

                // check requested operation
                if (string.IsNullOrEmpty(operation))
                {
                    if (string.IsNullOrEmpty(identifier) && string.IsNullOrEmpty(systemURL))
                    {
                        fhirResource = GetAllCodeSystems(queryParam);
                    }
                    else
                    {
                        fhirResource = GetRequest(identifier, systemURL, queryParam);
                    }
                }
                else if (operation == "$lookup")
                {
                    fhirResource = LookupOperation(systemURL, queryParam);
                }
                else if (operation == "$validate-code")
                {
                    fhirResource = ValidateCodeOperation(systemURL, queryParam);
                }
                else if (operation == "$subsumes")
                {
                    fhirResource = SubsumesOperation(systemURL, queryParam);
                }
                else if (operation == "$find-matches")
                {
                    //throw new Exception(FIND_MATCHES_UNSUPPORTED);
                    fhirResource = FindMatchesOperation(systemURL, queryParam);
                }
                else
                {
                    return(OperationOutcome.ForMessage("Unrecognised Operation in Request..." + operation, OperationOutcome.IssueType.Unknown, OperationOutcome.IssueSeverity.Error));
                }
            }
            catch (Exception ex)
            {
                if (ex.Message == MISSING_CODE_CODING)
                {
                    return(OperationOutcome.ForMessage("No code or coding value in Request", OperationOutcome.IssueType.BusinessRule, OperationOutcome.IssueSeverity.Error));
                }
                else if (ex.Message == MISSING_CODESYSTEM)
                {
                    return(OperationOutcome.ForMessage("No system to define code in Request", OperationOutcome.IssueType.BusinessRule, OperationOutcome.IssueSeverity.Error));
                }
                else if (ex.Message == INVALID_CODE)
                {
                    return(OperationOutcome.ForMessage("Invalid Code.", OperationOutcome.IssueType.CodeInvalid, OperationOutcome.IssueSeverity.Error));
                }
                else if (ex.Message == UNSUPPORTED_CODESYSTEM)
                {
                    return(OperationOutcome.ForMessage("Code System not supported.", OperationOutcome.IssueType.NotSupported, OperationOutcome.IssueSeverity.Error));
                }
                else if (ex.Message == SUBSUMPTION_UNSUPPORTED)
                {
                    return(OperationOutcome.ForMessage("Subsumption not supported for specified Code System.", OperationOutcome.IssueType.NotSupported, OperationOutcome.IssueSeverity.Error));
                }
                else if (ex.Message == FIND_MATCHES_UNSUPPORTED)
                {
                    return(OperationOutcome.ForMessage("find-matches operation not supported for specified Code System.", OperationOutcome.IssueType.NotSupported, OperationOutcome.IssueSeverity.Error));
                }
                else if (ex.Message == MISSING_ATTRIBUTE)
                {
                    return(OperationOutcome.ForMessage("Must submit at least one Attribute/Value Pair Property.", OperationOutcome.IssueType.BusinessRule, OperationOutcome.IssueSeverity.Error));
                }
                else if (ex.Message == UNSUPPORTED_EXACT_SETTING)
                {
                    return(OperationOutcome.ForMessage("Exact Property value not supported.", OperationOutcome.IssueType.NotSupported, OperationOutcome.IssueSeverity.Error));
                }
                else if (ex.Message == UNSUPPORTED_DISPLAY_LANGUAGE)
                {
                    return(OperationOutcome.ForMessage("Display Language requested is not supported (please omit or request en-NZ).", OperationOutcome.IssueType.NotSupported, OperationOutcome.IssueSeverity.Error));
                }
                else if (ex.Message == MISSING_EXACT)
                {
                    return(OperationOutcome.ForMessage("Missing Exact Property.", OperationOutcome.IssueType.BusinessRule, OperationOutcome.IssueSeverity.Error));
                }
                else if (ex.Message == MISSING_FOCUS_CONCEPT)
                {
                    return(OperationOutcome.ForMessage("Missing Focus Concept.", OperationOutcome.IssueType.BusinessRule, OperationOutcome.IssueSeverity.Error));
                }
                else if (ex.Message == NO_EXACT_MATCH)
                {
                    return(OperationOutcome.ForMessage("No Exact Matches.", OperationOutcome.IssueType.BusinessRule, OperationOutcome.IssueSeverity.Error));
                }
                else if (ex.Message == FhirLoinc.UNSUPPORTED_ANSWER_LIST)
                {
                    return(OperationOutcome.ForMessage("LOINC Answer List IDs refer to Value Sets.", OperationOutcome.IssueType.NotSupported, OperationOutcome.IssueSeverity.Error));
                }
                throw;
            }

            return(fhirResource);
        }
        public static Resource GetRequest(string id, NameValueCollection queryParam)
        {
            Bundle locBundle = new Bundle
            {
                Id   = Guid.NewGuid().ToString(),
                Type = Bundle.BundleType.Searchset
            };

            locBundle.Link.Add(new Bundle.LinkComponent {
                Url = ServerCapability.TERMINZ_CANONICAL + "/Location", Relation = "self"
            });

            Location     location = new Location();
            Organization org      = new Organization();

            string identifier         = GetIdentifier(id, queryParam);
            string address            = Utilities.GetQueryValue("address", queryParam);
            string address_city       = Utilities.GetQueryValue("address-city", queryParam);
            string address_postalcode = Utilities.GetQueryValue("address-postalcode", queryParam);
            string name     = Utilities.GetQueryValue("name", queryParam);
            string type     = Utilities.GetQueryValue("type", queryParam);
            bool   idPassed = !string.IsNullOrEmpty(id);
            int    matches  = 0;

            // facilitate (more efficient) postcode and city filtering at DB layer
            if (!string.IsNullOrEmpty(address_postalcode) && string.IsNullOrEmpty(address))
            {
                address = address_postalcode;
            }

            if (!string.IsNullOrEmpty(address_city) && string.IsNullOrEmpty(address))
            {
                address = address_city;
            }

            if (string.IsNullOrEmpty(identifier) && string.IsNullOrEmpty(name) && string.IsNullOrEmpty(address) && string.IsNullOrEmpty(type))
            {
                return(OperationOutcome.ForMessage("No valid search parameters.", OperationOutcome.IssueType.Invalid, OperationOutcome.IssueSeverity.Error));
            }

            //CodeableConcept hpiFac = new CodeableConcept { Text = "HPI-FAC" };

            try
            {
                List <HpiFacility> facilities = SnomedCtSearch.GetLocations(identifier, name, address, type);

                foreach (HpiFacility fac in facilities)
                {
                    bool addLocation = true;

                    Address locAddress = Utilities.GetAddress(fac.FacilityAddress.Trim());

                    if (!string.IsNullOrEmpty(address_city) && locAddress.City.ToUpper() != address_city.ToUpper())
                    {
                        addLocation = false;
                    }

                    if (!string.IsNullOrEmpty(address_postalcode) && locAddress.PostalCode.ToUpper() != address_postalcode.ToUpper())
                    {
                        addLocation = false;
                    }

                    if (addLocation)
                    {
                        bool addOrg = false;
                        org      = new Organization();
                        location = new Location
                        {
                            Id = fac.FacilityId.Trim()
                        };
                        location.Identifier.Add(new Identifier {
                            Value = fac.FacilityId.Trim(), System = NAMING_SYSTEM_IDENTIFIER
                        });
                        location.Name   = fac.FacilityName.Trim();
                        location.Status = Location.LocationStatus.Active;
                        location.Mode   = Location.LocationMode.Instance;
                        location.Type.Add(new CodeableConcept {
                            Text = fac.FacilityTypeName.Trim()
                        });
                        location.Address = locAddress;
                        AddNarrative(location);

                        if (!string.IsNullOrEmpty(fac.OrganisationId))
                        {
                            try
                            {
                                org = (Organization)AdministrationOrganisation.GetRequest(fac.OrganisationId, null);
                                location.ManagingOrganization = new ResourceReference {
                                    Reference = fac.OrganisationId
                                };
                                addOrg = true;
                            }
                            catch { }
                        }

                        locBundle.AddResourceEntry(location, ServerCapability.TERMINZ_CANONICAL + "/Location/" + fac.FacilityId.Trim());
                        matches++;

                        if (addOrg)
                        {
                            locBundle.AddResourceEntry(org, ServerCapability.TERMINZ_CANONICAL + "/Organization" + "/" + fac.OrganisationId.Trim());
                        }
                    }
                }

                if (matches == 0)
                {
                    return(OperationOutcome.ForMessage("No Locations match search parameter values.", OperationOutcome.IssueType.NotFound, OperationOutcome.IssueSeverity.Information));
                }

                locBundle.Total = matches;
            }
            catch (Exception ex)
            {
                return(OperationOutcome.ForMessage("Error: " + ex.Message, OperationOutcome.IssueType.Invalid, OperationOutcome.IssueSeverity.Error));
            }

            // always return bundle because of contained resources <TODO> implement _include so user can specify this

            return(locBundle);
        }
        public static Resource PerformOperation(string id, string operation, NameValueCollection queryParam)
        {
            Resource fhirResource = null;

            try
            {
                string identifier = GetIdentifier(id, queryParam);

                // check requested operation
                if (string.IsNullOrEmpty(operation))
                {
                    if (string.IsNullOrEmpty(identifier))
                    {
                        fhirResource = GetConceptMaps(identifier, queryParam);
                    }
                    else
                    {
                        fhirResource = GetRequest(identifier, queryParam);
                    }
                }
                else if (operation == "$translate")
                {
                    fhirResource = TranslateOperation(id, queryParam);
                }
                else if (operation == "$closure")
                {
                    //return OperationOutcome.ForMessage("Closure operation not yet supported.", OperationOutcome.IssueType.NotSupported);
                    fhirResource = ClosureOperation(queryParam);
                }
                else
                {
                    return(OperationOutcome.ForMessage("Unrecognised Operation in Request..." + operation, OperationOutcome.IssueType.Unknown, OperationOutcome.IssueSeverity.Error));
                }
            }
            catch (Exception ex)
            {
                if (ex.Message == INVALID_CLOSURE_NAME)
                {
                    return(OperationOutcome.ForMessage("Invalid Closure Name", OperationOutcome.IssueType.BusinessRule, OperationOutcome.IssueSeverity.Error));
                }
                else if (ex.Message == INVALID_CLOSURE_PARAMS)
                {
                    return(OperationOutcome.ForMessage("Invalid Closure Parameters - cannot pass both concepts and a version", OperationOutcome.IssueType.BusinessRule, OperationOutcome.IssueSeverity.Error));
                }
                else if (ex.Message == MISSING_CLOSURE_NAME)
                {
                    return(OperationOutcome.ForMessage("No Closure Name in Request", OperationOutcome.IssueType.BusinessRule, OperationOutcome.IssueSeverity.Error));
                }
                else if (ex.Message == REINITIALISE_CLOSURE)
                {
                    return(OperationOutcome.ForMessage("Closure must be reinitialised", OperationOutcome.IssueType.BusinessRule, OperationOutcome.IssueSeverity.Error));
                }
                else if (ex.Message == MISSING_CONCEPTMAP_IDENTIFIER)
                {
                    return(OperationOutcome.ForMessage("No ConceptMap id or identifer in Request", OperationOutcome.IssueType.BusinessRule, OperationOutcome.IssueSeverity.Error));
                }
                else if (ex.Message == MISSING_SOURCE_CODE_CODING)
                {
                    return(OperationOutcome.ForMessage("No source code for mapping in Request", OperationOutcome.IssueType.BusinessRule, OperationOutcome.IssueSeverity.Error));
                }
                else if (ex.Message == MISSING_SOURCE_SYSTEM)
                {
                    return(OperationOutcome.ForMessage("No source system for code in mapping in Request", OperationOutcome.IssueType.BusinessRule, OperationOutcome.IssueSeverity.Error));
                }
                else if (ex.Message == MISSING_TARGET_SYSTEM)
                {
                    return(OperationOutcome.ForMessage("No target system for mapping in Request", OperationOutcome.IssueType.BusinessRule, OperationOutcome.IssueSeverity.Error));
                }
                else if (ex.Message == UNRECOGNISED_CONCEPTMAP)
                {
                    return(OperationOutcome.ForMessage("Concept Map Not Recognised.", OperationOutcome.IssueType.Unknown, OperationOutcome.IssueSeverity.Error));
                }
                else if (ex.Message == UNSUPPORTED_VERSION)
                {
                    return(OperationOutcome.ForMessage("Concept Map Version Not Supported.", OperationOutcome.IssueType.NotSupported, OperationOutcome.IssueSeverity.Error));
                }
                else if (ex.Message == UNSUPPORTED_CODE_SYSTEM)
                {
                    return(OperationOutcome.ForMessage("Code System Not Supported.", OperationOutcome.IssueType.NotSupported, OperationOutcome.IssueSeverity.Error));
                }
                else
                {
                    return(OperationOutcome.ForMessage(ex.Message, OperationOutcome.IssueType.Unknown, OperationOutcome.IssueSeverity.Error));
                }
                throw;
            }

            return(fhirResource);
        }
        public static Resource GetRequest(string id, NameValueCollection queryParam)
        {
            Bundle orgBundle = new Bundle
            {
                Id   = Guid.NewGuid().ToString(),
                Type = Bundle.BundleType.Searchset
            };

            orgBundle.Link.Add(new Bundle.LinkComponent {
                Url = ServerCapability.TERMINZ_CANONICAL + "/Organization", Relation = "self"
            });

            Organization organization = new Organization();

            string identifier         = GetIdentifier(id, queryParam);
            string address            = Utilities.GetQueryValue("address", queryParam);
            string address_city       = Utilities.GetQueryValue("address-city", queryParam);
            string address_postalcode = Utilities.GetQueryValue("address-postalcode", queryParam);
            string name     = Utilities.GetQueryValue("name", queryParam);
            string type     = Utilities.GetQueryValue("type", queryParam);
            bool   idPassed = !string.IsNullOrEmpty(id);
            int    matches  = 0;

            // facilitate (more efficient) postcode and city filtering at DB layer
            if (!string.IsNullOrEmpty(address_postalcode) && string.IsNullOrEmpty(address))
            {
                address = address_postalcode;
            }

            if (!string.IsNullOrEmpty(address_city) && string.IsNullOrEmpty(address))
            {
                address = address_city;
            }

            if (string.IsNullOrEmpty(identifier) && string.IsNullOrEmpty(name) && string.IsNullOrEmpty(address) && string.IsNullOrEmpty(type))
            {
                return(OperationOutcome.ForMessage("No valid search parameters.", OperationOutcome.IssueType.Invalid, OperationOutcome.IssueSeverity.Error));
            }

            //CodeableConcept hpiFac = new CodeableConcept { Text = "HPI-ORG" };

            List <HpiOrganisation> organisations = SnomedCtSearch.GetOrganisations(identifier, name, address, type);

            foreach (HpiOrganisation org in organisations)
            {
                bool addOrg = true;

                Address orgAddress = Utilities.GetAddress(org.OrganisationAddress.Trim());

                if (!string.IsNullOrEmpty(address_city) && orgAddress.City.ToUpper() != address_city.ToUpper())
                {
                    addOrg = false;
                }

                if (!string.IsNullOrEmpty(address_postalcode) && orgAddress.PostalCode.ToUpper() != address_postalcode.ToUpper())
                {
                    addOrg = false;
                }

                if (addOrg)
                {
                    organization = new Organization
                    {
                        Id = org.OrganisationId.Trim()
                    };
                    organization.Identifier.Add(new Identifier {
                        Value = org.OrganisationId.Trim(), System = NAMING_SYSTEM_IDENTIFIER
                    });
                    organization.Name   = org.OrganisationName.Trim();
                    organization.Active = true;
                    organization.Type.Add(new CodeableConcept {
                        Text = org.OrganisationTypeName.Trim()
                    });
                    organization.Address.Add(orgAddress);
                    AddNarrative(organization);
                    orgBundle.AddResourceEntry(organization, ServerCapability.TERMINZ_CANONICAL + "/Organization/ " + org.OrganisationId.Trim());
                    matches++;
                }
            }

            if (matches == 0)
            {
                return(OperationOutcome.ForMessage("No Organisations match search parameter values.", OperationOutcome.IssueType.NotFound, OperationOutcome.IssueSeverity.Information));
            }
            else if (matches == 1 && idPassed)
            {
                return(organization);
            }

            orgBundle.Total = matches;

            return(orgBundle);
        }