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;
071import org.hl7.fhir.utilities.filesystem.ManagedFileAccess;
072
073public class IEEE11073Convertor {
074
075  public static final String UCUM_PATH = "c:\\work\\org.hl7.fhir\\build\\implementations\\java\\org.hl7.fhir.convertors\\samples\\ucum-essence.xml";
076  private static final String MDC_ALL_VALUES = "http://????";
077
078  /**
079   * argument 1: path to the rosetta csv file
080   * argument 2: basePath to produce files to
081   *
082   * @param args
083   * @throws Exception
084   */
085  public static void main(String[] args) throws Exception {
086    UcumService ucum = new UcumEssenceService(UCUM_PATH);
087
088    CodeSystem mdc = generateMDC(args[0], args[1], ucum);
089    ConceptMap loinc = generateLoincMdcMap(mdc, args[1], args[2]);
090  }
091
092  private static ConceptMap generateLoincMdcMap(CodeSystem mdc, String dst, String src) throws IOException, FHIRException {
093    ConceptMap cm = new ConceptMap();
094    cm.setId("loinc-mdc");
095    cm.setUrl("http:/???/fhir/ConceptMap/loinc-mdc");
096    cm.setVersion("[todo]");
097    cm.setName("LoincMdcCrossMap");
098    cm.setTitle("Cross Map between LOINC and MDC");
099    cm.setStatus(PublicationStatus.DRAFT);
100    cm.setExperimental(true);
101    cm.setDateElement(new DateTimeType());
102    cm.setPublisher("HL7, Inc");
103    ContactDetail cd = cm.addContact();
104    cd.setName("LOINC + IEEE");
105    ContactPoint cp = cd.addTelecom();
106    cp.setSystem(ContactPointSystem.URL);
107    cp.setValue("http://loinc.org");
108    cm.setDescription("A Cross Map between the LOINC and MDC Code systems");
109    cm.setPurpose("To implementers map between medical device codes and LOINC codes");
110    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");
111    cm.setSource(new UriType("http://loinc.org/vs"));
112    cm.setTarget(new UriType(MDC_ALL_VALUES));
113    ConceptMapGroupComponent g = cm.addGroup();
114    g.setSource("urn:iso:std:iso:11073:10101");
115    g.setTarget("http://loinc.org");
116
117    CSVReader csv = new CSVReader(ManagedFileAccess.inStream(src));
118    csv.readHeaders();
119    while (csv.line()) {
120      SourceElementComponent e = g.addElement();
121      e.setCode(csv.cell("IEEE_CF_CODE10"));
122      e.setDisplay(csv.cell("IEEE_DESCRIPTION"));
123      TargetElementComponent t = e.addTarget();
124      t.setEquivalence(ConceptMapEquivalence.EQUIVALENT);
125      t.setCode(csv.cell("LOINC_NUM"));
126      t.setDisplay(csv.cell("LOINC_LONG_COMMON_NAME"));
127    }
128    new XmlParser().setOutputStyle(OutputStyle.PRETTY).compose(ManagedFileAccess.outStream(Utilities.path(dst, "conceptmap-" + cm.getId() + ".xml")), cm);
129    System.out.println("Done");
130    return cm;
131  }
132
133  public static CodeSystem generateMDC(String src, String dst, UcumService ucum) throws IOException, FHIRException {
134    CSVReader csv = new CSVReader(ManagedFileAccess.inStream(src));
135    csv.readHeaders();
136    CodeSystem cs = new CodeSystem();
137    Map<String, String> ucumIssues = new HashMap<String, String>();
138
139    int errorCount = 0;
140    cs.setId("MDC");
141    cs.setUrl("urn:iso:std:iso:11073:10101");
142    cs.setVersion("[todo]");
143    cs.setName("11073:10101 codes for the FHIR community");
144    cs.setStatus(PublicationStatus.ACTIVE);
145    cs.setExperimental(false);
146    cs.setDateElement(new DateTimeType());
147    cs.setPublisher("HL7 (FHIR Project)");
148    ContactDetail cd = cs.addContact();
149    ContactPoint cp = cd.addTelecom();
150    cp.setSystem(ContactPointSystem.URL);
151    cp.setValue("http://ieee?");
152    cs.setDescription("1073 Codes for the FHIR community (generated from the Rosetta data");
153    Identifier i = new Identifier();
154    cs.setIdentifier(i);
155    i.setSystem("urn:ietf:rfc:3986");
156    i.setValue("urn:oid:2.16.840.1.113883.6.24");
157    cs.setCaseSensitive(false);
158    cs.setContent(CodeSystemContentMode.COMPLETE);
159    cs.addProperty().setCode("ucum").setDescription("UCUM units associated with Concept").setType(PropertyType.STRING);
160    cs.addProperty().setCode("unit").setDescription("MDC units associated with Concept").setType(PropertyType.STRING);
161    cs.addProperty().setCode("refid").setDescription("MDC Reference Id for Concept").setType(PropertyType.CODE);
162    Set<String> codes = new HashSet<String>();
163    while (csv.line()) {
164      if (csv.has("CF_CODE10")) {
165        String code = csv.cell("CF_CODE10");
166        if (codes.contains(code))
167          System.out.println("Duplicate Code " + code);
168        else {
169          codes.add(code);
170          ConceptDefinitionComponent c = cs.addConcept();
171          c.setCode(code);
172          c.setDisplay(csv.cell("Common Term"));
173          c.setDefinition(csv.cell("Term Description"));
174          String vd = csv.cell("Vendor_Description");
175          if (!c.hasDefinition())
176            c.setDefinition(vd);
177          if (!c.hasDisplay())
178            c.setDisplay(vd);
179          String refid = csv.cell("REFID");
180          c.addProperty().setCode("refid").setValue(new CodeType().setValue(refid));
181          if (csv.has("Synonym"))
182            c.addDesignation().setValue(csv.cell("Synonym")).setUse(new Coding().setSystem("http://hl7.org/fhir/designation-use").setCode("synonym"));
183          if (csv.has("Acronym"))
184            c.addDesignation().setValue(csv.cell("Acronym")).setUse(new Coding().setSystem("http://hl7.org/fhir/designation-use").setDisplay("acronym"));
185          if (csv.has("Systematic Name")) {
186            String sysName = csv.cell("Systematic Name");
187            if (!c.hasDefinition())
188              c.setDefinition(sysName);
189            c.addDesignation().setValue(sysName).setUse(new Coding().setSystem("http://hl7.org/fhir/designation-use").setCode("structured-name"));
190          }
191          if (csv.has("UOM_MDC"))
192            c.addProperty().setCode("unit").setValue(new StringType().setValue(csv.cell("UOM_MDC")));
193          if (csv.has("UOM_UCUM")) {
194            CommaSeparatedStringBuilder ul = new CommaSeparatedStringBuilder();
195            for (String u : csv.cell("UOM_UCUM").split(" ")) {
196              String msg = ucum.validate(u);
197              if (msg != null) {
198                errorCount++;
199                ucumIssues.put(u, msg);
200              } else
201                ul.append(u);
202            }
203            if (ul.length() > 0)
204              c.addProperty().setCode("ucum").setValue(new StringType().setValue(ul.toString()));
205          }
206        }
207      }
208    }
209    csv.close();
210    new XmlParser().setOutputStyle(OutputStyle.PRETTY).compose(ManagedFileAccess.outStream(Utilities.path(dst, "codesystem-" + cs.getId() + ".xml")), cs);
211    System.out.println(errorCount + "UCUM errors");
212
213    for (String u : sorted(ucumIssues.keySet()))
214      System.out.println("Invalid UCUM code: " + u + " because " + ucumIssues.get(u));
215
216    return cs;
217  }
218
219  private static List<String> sorted(Set<String> keySet) {
220    List<String> names = new ArrayList<>();
221    names.addAll(keySet);
222    Collections.sort(names);
223    return names;
224  }
225
226
227}