001/*-
002 * #%L
003 * HAPI FHIR JPA Server
004 * %%
005 * Copyright (C) 2014 - 2024 Smile CDR, Inc.
006 * %%
007 * Licensed under the Apache License, Version 2.0 (the "License");
008 * you may not use this file except in compliance with the License.
009 * You may obtain a copy of the License at
010 *
011 *      http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing, software
014 * distributed under the License is distributed on an "AS IS" BASIS,
015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016 * See the License for the specific language governing permissions and
017 * limitations under the License.
018 * #L%
019 */
020package ca.uhn.fhir.jpa.term.loinc;
021
022import ca.uhn.fhir.i18n.Msg;
023import ca.uhn.fhir.jpa.entity.TermConcept;
024import ca.uhn.fhir.jpa.term.IZipContentsHandlerCsv;
025import ca.uhn.fhir.jpa.term.api.ITermLoaderSvc;
026import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
027import org.apache.commons.csv.CSVRecord;
028import org.hl7.fhir.r4.model.ConceptMap;
029import org.hl7.fhir.r4.model.Enumerations;
030import org.hl7.fhir.r4.model.ValueSet;
031
032import java.util.List;
033import java.util.Map;
034import java.util.Properties;
035
036import static ca.uhn.fhir.jpa.term.loinc.LoincUploadPropertiesEnum.LOINC_CODESYSTEM_VERSION;
037import static ca.uhn.fhir.jpa.term.loinc.LoincUploadPropertiesEnum.LOINC_CONCEPTMAP_VERSION;
038import static org.apache.commons.lang3.StringUtils.defaultString;
039import static org.apache.commons.lang3.StringUtils.trim;
040
041public class LoincPartRelatedCodeMappingHandler extends BaseLoincHandler implements IZipContentsHandlerCsv {
042
043        public static final String LOINC_SCT_PART_MAP_ID = "loinc-parts-to-snomed-ct";
044        public static final String LOINC_SCT_PART_MAP_URI = "http://loinc.org/cm/loinc-parts-to-snomed-ct";
045        public static final String LOINC_TERM_TO_RPID_PART_MAP_ID = "loinc-to-radlex";
046        public static final String LOINC_TERM_TO_RPID_PART_MAP_URI = "http://loinc.org/cm/loinc-to-radlex";
047        public static final String LOINC_TERM_TO_RPID_PART_MAP_NAME = "LOINC Terms to RadLex RPIDs";
048        public static final String LOINC_PART_TO_RID_PART_MAP_ID = "loinc-parts-to-radlex";
049        public static final String LOINC_PART_TO_RID_PART_MAP_URI = "http://loinc.org/cm/loinc-parts-to-radlex";
050        public static final String LOINC_PART_TO_RID_PART_MAP_NAME = "LOINC Parts to RadLex RIDs";
051        private static final String LOINC_SCT_PART_MAP_NAME = "LOINC Part Map to SNOMED CT";
052        private static final String LOINC_RXNORM_PART_MAP_ID = "loinc-parts-to-rxnorm";
053        private static final String LOINC_RXNORM_PART_MAP_URI = "http://loinc.org/cm/loinc-parts-to-rxnorm";
054        private static final String LOINC_RXNORM_PART_MAP_NAME = "LOINC Part Map to RxNORM";
055
056        private static final String LOINC_PUBCHEM_PART_MAP_ID = "loinc-parts-to-pubchem";
057        private static final String LOINC_PUBCHEM_PART_MAP_URI = "http://loinc.org/cm/loinc-parts-to-pubchem";
058        private static final String LOINC_PUBCHEM_PART_MAP_NAME = "LOINC Part Map to PubChem";
059
060        private static final String CM_COPYRIGHT =
061                        "The LOINC Part File, LOINC/SNOMED CT Expression Association and Map Sets File, RELMA database and associated search index files include SNOMED Clinical Terms (SNOMED CT®) which is used by permission of the International Health Terminology Standards Development Organisation (IHTSDO) under license. All rights are reserved. SNOMED CT® was originally created by The College of American Pathologists. ?SNOMED? and ?SNOMED CT? are registered trademarks of the IHTSDO. Use of SNOMED CT content is subject to the terms and conditions set forth in the SNOMED CT Affiliate License Agreement.  It is the responsibility of those implementing this product to ensure they are appropriately licensed and for more information on the license, including how to register as an Affiliate Licensee, please refer to http://www.snomed.org/snomed-ct/get-snomed-ct or info@snomed.org. Under the terms of the Affiliate License, use of SNOMED CT in countries that are not IHTSDO Members is subject to reporting and fee payment obligations. However, IHTSDO agrees to waive the requirements to report and pay fees for use of SNOMED CT content included in the LOINC Part Mapping and LOINC Term Associations for purposes that support or enable more effective use of LOINC. This material includes content from the US Edition to SNOMED CT, which is developed and maintained by the U.S. National Library of Medicine and is available to authorized UMLS Metathesaurus Licensees from the UTS Downloads site at https://uts.nlm.nih.gov.";
062
063        public LoincPartRelatedCodeMappingHandler(
064                        Map<String, TermConcept> theCode2concept,
065                        List<ValueSet> theValueSets,
066                        List<ConceptMap> theConceptMaps,
067                        Properties theUploadProperties,
068                        String theCopyrightStatement) {
069                super(theCode2concept, theValueSets, theConceptMaps, theUploadProperties, theCopyrightStatement);
070        }
071
072        @Override
073        public void accept(CSVRecord theRecord) {
074
075                String partNumber = trim(theRecord.get("PartNumber"));
076                String partName = trim(theRecord.get("PartName"));
077                String extCodeId = trim(theRecord.get("ExtCodeId"));
078                // TODO: use hex code for ascii 160
079                extCodeId = extCodeId.replace(" ", "");
080                String extCodeDisplayName = trim(theRecord.get("ExtCodeDisplayName"));
081                String extCodeSystem = trim(theRecord.get("ExtCodeSystem"));
082                String mapType = trim(theRecord.get("Equivalence"));
083                String extCodeSystemVersion = trim(theRecord.get("ExtCodeSystemVersion"));
084                String extCodeSystemCopyrightNotice = trim(theRecord.get("ExtCodeSystemCopyrightNotice"));
085
086                // CodeSystem version from properties file
087                String codeSystemVersionId = myUploadProperties.getProperty(LOINC_CODESYSTEM_VERSION.getCode());
088
089                // ConceptMap version from properties files
090                String loincPartMapVersion;
091                if (codeSystemVersionId != null) {
092                        loincPartMapVersion =
093                                        myUploadProperties.getProperty(LOINC_CONCEPTMAP_VERSION.getCode()) + "-" + codeSystemVersionId;
094                } else {
095                        loincPartMapVersion = myUploadProperties.getProperty(LOINC_CONCEPTMAP_VERSION.getCode());
096                }
097
098                Enumerations.ConceptMapEquivalence equivalence;
099                switch (trim(defaultString(mapType))) {
100                        case "":
101                        case "equivalent":
102                                // 'equal' is more exact than 'equivalent' in the equivalence codes
103                                equivalence = Enumerations.ConceptMapEquivalence.EQUAL;
104                                break;
105                        case "narrower":
106                                equivalence = Enumerations.ConceptMapEquivalence.NARROWER;
107                                break;
108                        case "wider":
109                                equivalence = Enumerations.ConceptMapEquivalence.WIDER;
110                                break;
111                        case "relatedto":
112                                equivalence = Enumerations.ConceptMapEquivalence.RELATEDTO;
113                                break;
114                        default:
115                                throw new InternalErrorException(
116                                                Msg.code(916) + "Unknown equivalence '" + mapType + "' for PartNumber: " + partNumber);
117                }
118
119                String loincPartMapId;
120                String loincPartMapUri;
121                String loincPartMapName;
122                switch (extCodeSystem) {
123                        case ITermLoaderSvc.SCT_URI:
124                                loincPartMapId = LOINC_SCT_PART_MAP_ID;
125                                loincPartMapUri = LOINC_SCT_PART_MAP_URI;
126                                loincPartMapName = LOINC_SCT_PART_MAP_NAME;
127                                break;
128                        case "http://www.nlm.nih.gov/research/umls/rxnorm":
129                                loincPartMapId = LOINC_RXNORM_PART_MAP_ID;
130                                loincPartMapUri = LOINC_RXNORM_PART_MAP_URI;
131                                loincPartMapName = LOINC_RXNORM_PART_MAP_NAME;
132                                break;
133                        case "http://www.radlex.org":
134                                loincPartMapId = LOINC_PART_TO_RID_PART_MAP_ID;
135                                loincPartMapUri = LOINC_PART_TO_RID_PART_MAP_URI;
136                                loincPartMapName = LOINC_PART_TO_RID_PART_MAP_NAME;
137                                break;
138                        case "http://pubchem.ncbi.nlm.nih.gov":
139                                loincPartMapId = LOINC_PUBCHEM_PART_MAP_ID;
140                                loincPartMapUri = LOINC_PUBCHEM_PART_MAP_URI;
141                                loincPartMapName = LOINC_PUBCHEM_PART_MAP_NAME;
142                                break;
143                        default:
144                                loincPartMapId = extCodeSystem.replaceAll("[^a-zA-Z]", "");
145                                loincPartMapUri = extCodeSystem;
146                                loincPartMapName = "Unknown Mapping";
147                                break;
148                }
149                String conceptMapId;
150                if (codeSystemVersionId != null) {
151                        conceptMapId = loincPartMapId + "-" + codeSystemVersionId;
152                } else {
153                        conceptMapId = loincPartMapId;
154                }
155
156                addConceptMapEntry(
157                                new ConceptMapping()
158                                                .setConceptMapId(conceptMapId)
159                                                .setConceptMapUri(loincPartMapUri)
160                                                .setConceptMapVersion(loincPartMapVersion)
161                                                .setConceptMapName(loincPartMapName)
162                                                .setSourceCodeSystem(ITermLoaderSvc.LOINC_URI)
163                                                .setSourceCodeSystemVersion(codeSystemVersionId)
164                                                .setSourceCode(partNumber)
165                                                .setSourceDisplay(partName)
166                                                .setTargetCodeSystem(extCodeSystem)
167                                                .setTargetCode(extCodeId)
168                                                .setTargetDisplay(extCodeDisplayName)
169                                                .setTargetCodeSystemVersion(extCodeSystemVersion)
170                                                .setEquivalence(equivalence)
171                                                .setCopyright(extCodeSystemCopyrightNotice),
172                                myLoincCopyrightStatement + " " + CM_COPYRIGHT);
173        }
174}