001package org.hl7.fhir.convertors.misc;
002
003import java.io.FileInputStream;
004import java.io.FileOutputStream;
005import java.io.IOException;
006import java.util.ArrayList;
007import java.util.Collections;
008import java.util.HashMap;
009import java.util.HashSet;
010import java.util.List;
011import java.util.Map;
012import java.util.Set;
013
014/*
015  Copyright (c) 2011+, HL7, Inc.
016  All rights reserved.
017  
018  Redistribution and use in source and binary forms, with or without modification, 
019  are permitted provided that the following conditions are met:
020    
021   * Redistributions of source code must retain the above copyright notice, this 
022     list of conditions and the following disclaimer.
023   * Redistributions in binary form must reproduce the above copyright notice, 
024     this list of conditions and the following disclaimer in the documentation 
025     and/or other materials provided with the distribution.
026   * Neither the name of HL7 nor the names of its contributors may be used to 
027     endorse or promote products derived from this software without specific 
028     prior written permission.
029  
030  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
031  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
032  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
033  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
034  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
035  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
036  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
037  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
038  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
039  POSSIBILITY OF SUCH DAMAGE.
040  
041 */
042
043
044import org.fhir.ucum.UcumEssenceService;
045import org.fhir.ucum.UcumService;
046import org.hl7.fhir.dstu3.formats.IParser.OutputStyle;
047import org.hl7.fhir.dstu3.formats.XmlParser;
048import org.hl7.fhir.dstu3.model.CodeSystem;
049import org.hl7.fhir.dstu3.model.CodeSystem.CodeSystemContentMode;
050import org.hl7.fhir.dstu3.model.CodeSystem.ConceptDefinitionComponent;
051import org.hl7.fhir.dstu3.model.CodeSystem.PropertyType;
052import org.hl7.fhir.dstu3.model.CodeType;
053import org.hl7.fhir.dstu3.model.Coding;
054import org.hl7.fhir.dstu3.model.ConceptMap;
055import org.hl7.fhir.dstu3.model.ConceptMap.ConceptMapGroupComponent;
056import org.hl7.fhir.dstu3.model.ConceptMap.SourceElementComponent;
057import org.hl7.fhir.dstu3.model.ConceptMap.TargetElementComponent;
058import org.hl7.fhir.dstu3.model.ContactDetail;
059import org.hl7.fhir.dstu3.model.ContactPoint;
060import org.hl7.fhir.dstu3.model.ContactPoint.ContactPointSystem;
061import org.hl7.fhir.dstu3.model.DateTimeType;
062import org.hl7.fhir.dstu3.model.Enumerations.ConceptMapEquivalence;
063import org.hl7.fhir.dstu3.model.Enumerations.PublicationStatus;
064import org.hl7.fhir.dstu3.model.Identifier;
065import org.hl7.fhir.dstu3.model.StringType;
066import org.hl7.fhir.dstu3.model.UriType;
067import org.hl7.fhir.exceptions.FHIRException;
068import org.hl7.fhir.utilities.CSVReader;
069import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
070import org.hl7.fhir.utilities.Utilities;
071
072public class IEEE11073Convertor {
073
074  public static final String UCUM_PATH = "c:\\work\\org.hl7.fhir\\build\\implementations\\java\\org.hl7.fhir.convertors\\samples\\ucum-essence.xml";
075  private static final String MDC_ALL_VALUES = "http://????";
076
077  /**
078   * argument 1: path to the rosetta csv file
079   * argument 2: basePath to produce files to
080   *
081   * @param args
082   * @throws Exception
083   */
084  public static void main(String[] args) throws Exception {
085    UcumService ucum = new UcumEssenceService(UCUM_PATH);
086
087    CodeSystem mdc = generateMDC(args[0], args[1], ucum);
088    ConceptMap loinc = generateLoincMdcMap(mdc, args[1], args[2]);
089  }
090
091  private static ConceptMap generateLoincMdcMap(CodeSystem mdc, String dst, String src) throws IOException, FHIRException {
092    ConceptMap cm = new ConceptMap();
093    cm.setId("loinc-mdc");
094    cm.setUrl("http:/???/fhir/ConceptMap/loinc-mdc");
095    cm.setVersion("[todo]");
096    cm.setName("LoincMdcCrossMap");
097    cm.setTitle("Cross Map between LOINC and MDC");
098    cm.setStatus(PublicationStatus.DRAFT);
099    cm.setExperimental(true);
100    cm.setDateElement(new DateTimeType());
101    cm.setPublisher("HL7, Inc");
102    ContactDetail cd = cm.addContact();
103    cd.setName("LOINC + IEEE");
104    ContactPoint cp = cd.addTelecom();
105    cp.setSystem(ContactPointSystem.URL);
106    cp.setValue("http://loinc.org");
107    cm.setDescription("A Cross Map between the LOINC and MDC Code systems");
108    cm.setPurpose("To implementers map between medical device codes and LOINC codes");
109    cm.setCopyright("This content LOINC \u00ae is copyright \u00a9 1995 Regenstrief Institute, Inc. and the LOINC Committee, and available at no cost under the license at http://loinc.org/terms-of-use");
110    cm.setSource(new UriType("http://loinc.org/vs"));
111    cm.setTarget(new UriType(MDC_ALL_VALUES));
112    ConceptMapGroupComponent g = cm.addGroup();
113    g.setSource("urn:iso:std:iso:11073:10101");
114    g.setTarget("http://loinc.org");
115
116    CSVReader csv = new CSVReader(new FileInputStream(src));
117    csv.readHeaders();
118    while (csv.line()) {
119      SourceElementComponent e = g.addElement();
120      e.setCode(csv.cell("IEEE_CF_CODE10"));
121      e.setDisplay(csv.cell("IEEE_DESCRIPTION"));
122      TargetElementComponent t = e.addTarget();
123      t.setEquivalence(ConceptMapEquivalence.EQUIVALENT);
124      t.setCode(csv.cell("LOINC_NUM"));
125      t.setDisplay(csv.cell("LOINC_LONG_COMMON_NAME"));
126    }
127    new XmlParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path(dst, "conceptmap-" + cm.getId() + ".xml")), cm);
128    System.out.println("Done");
129    return cm;
130  }
131
132  public static CodeSystem generateMDC(String src, String dst, UcumService ucum) throws IOException, FHIRException {
133    CSVReader csv = new CSVReader(new FileInputStream(src));
134    csv.readHeaders();
135    CodeSystem cs = new CodeSystem();
136    Map<String, String> ucumIssues = new HashMap<String, String>();
137
138    int errorCount = 0;
139    cs.setId("MDC");
140    cs.setUrl("urn:iso:std:iso:11073:10101");
141    cs.setVersion("[todo]");
142    cs.setName("11073:10101 codes for the FHIR community");
143    cs.setStatus(PublicationStatus.ACTIVE);
144    cs.setExperimental(false);
145    cs.setDateElement(new DateTimeType());
146    cs.setPublisher("HL7 (FHIR Project)");
147    ContactDetail cd = cs.addContact();
148    ContactPoint cp = cd.addTelecom();
149    cp.setSystem(ContactPointSystem.URL);
150    cp.setValue("http://ieee?");
151    cs.setDescription("1073 Codes for the FHIR community (generated from the Rosetta data");
152    Identifier i = new Identifier();
153    cs.setIdentifier(i);
154    i.setSystem("urn:ietf:rfc:3986");
155    i.setValue("urn:oid:2.16.840.1.113883.6.24");
156    cs.setCaseSensitive(false);
157    cs.setContent(CodeSystemContentMode.COMPLETE);
158    cs.addProperty().setCode("ucum").setDescription("UCUM units associated with Concept").setType(PropertyType.STRING);
159    cs.addProperty().setCode("unit").setDescription("MDC units associated with Concept").setType(PropertyType.STRING);
160    cs.addProperty().setCode("refid").setDescription("MDC Reference Id for Concept").setType(PropertyType.CODE);
161    Set<String> codes = new HashSet<String>();
162    while (csv.line()) {
163      if (csv.has("CF_CODE10")) {
164        String code = csv.cell("CF_CODE10");
165        if (codes.contains(code))
166          System.out.println("Duplicate Code " + code);
167        else {
168          codes.add(code);
169          ConceptDefinitionComponent c = cs.addConcept();
170          c.setCode(code);
171          c.setDisplay(csv.cell("Common Term"));
172          c.setDefinition(csv.cell("Term Description"));
173          String vd = csv.cell("Vendor_Description");
174          if (!c.hasDefinition())
175            c.setDefinition(vd);
176          if (!c.hasDisplay())
177            c.setDisplay(vd);
178          String refid = csv.cell("REFID");
179          c.addProperty().setCode("refid").setValue(new CodeType().setValue(refid));
180          if (csv.has("Synonym"))
181            c.addDesignation().setValue(csv.cell("Synonym")).setUse(new Coding().setSystem("http://hl7.org/fhir/designation-use").setCode("synonym"));
182          if (csv.has("Acronym"))
183            c.addDesignation().setValue(csv.cell("Acronym")).setUse(new Coding().setSystem("http://hl7.org/fhir/designation-use").setDisplay("acronym"));
184          if (csv.has("Systematic Name")) {
185            String sysName = csv.cell("Systematic Name");
186            if (!c.hasDefinition())
187              c.setDefinition(sysName);
188            c.addDesignation().setValue(sysName).setUse(new Coding().setSystem("http://hl7.org/fhir/designation-use").setCode("structured-name"));
189          }
190          if (csv.has("UOM_MDC"))
191            c.addProperty().setCode("unit").setValue(new StringType().setValue(csv.cell("UOM_MDC")));
192          if (csv.has("UOM_UCUM")) {
193            CommaSeparatedStringBuilder ul = new CommaSeparatedStringBuilder();
194            for (String u : csv.cell("UOM_UCUM").split(" ")) {
195              String msg = ucum.validate(u);
196              if (msg != null) {
197                errorCount++;
198                ucumIssues.put(u, msg);
199              } else
200                ul.append(u);
201            }
202            if (ul.length() > 0)
203              c.addProperty().setCode("ucum").setValue(new StringType().setValue(ul.toString()));
204          }
205        }
206      }
207    }
208    csv.close();
209    new XmlParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path(dst, "codesystem-" + cs.getId() + ".xml")), cs);
210    System.out.println(errorCount + "UCUM errors");
211
212    for (String u : sorted(ucumIssues.keySet()))
213      System.out.println("Invalid UCUM code: " + u + " because " + ucumIssues.get(u));
214
215    return cs;
216  }
217
218  private static List<String> sorted(Set<String> keySet) {
219    List<String> names = new ArrayList<>();
220    names.addAll(keySet);
221    Collections.sort(names);
222    return names;
223  }
224
225
226}