001package org.hl7.fhir.convertors.misc;
002
003
004import java.io.FileInputStream;
005import java.io.FileNotFoundException;
006import java.io.FileOutputStream;
007import java.io.IOException;
008import java.util.HashMap;
009import java.util.Map;
010
011import org.fhir.ucum.Utilities;
012import org.hl7.fhir.exceptions.FHIRException;
013import org.hl7.fhir.r5.formats.IParser.OutputStyle;
014import org.hl7.fhir.r5.formats.JsonParser;
015import org.hl7.fhir.r5.model.BooleanType;
016import org.hl7.fhir.r5.model.CodeSystem;
017import org.hl7.fhir.r5.model.CodeSystem.CodeSystemHierarchyMeaning;
018import org.hl7.fhir.r5.model.CodeSystem.ConceptDefinitionComponent;
019import org.hl7.fhir.r5.model.CodeSystem.PropertyType;
020import org.hl7.fhir.r5.model.CodeType;
021import org.hl7.fhir.utilities.CSVReader;
022
023public class ICFImporter {
024
025  public static void main(String[] args) throws FHIRException, FileNotFoundException, IOException {
026    new ICFImporter().doImport(args[0], args[1]);
027
028  }
029
030  private void doImport(String src, String dst) throws FHIRException, FileNotFoundException, IOException {
031    CSVReader csv = new CSVReader(new FileInputStream(src));
032    csv.setDelimiter('\t');
033    csv.readHeaders();
034
035    CodeSystem cs = new CodeSystem();
036    cs.setId("icf");
037    cs.setUrl("http://id.who.int/icd/release/11/beta/icf");
038    cs.setVersion("2023-06");
039    cs.setName("WHOICF");
040    cs.setTitle("WHO ICF");
041    cs.setHierarchyMeaning(CodeSystemHierarchyMeaning.CLASSIFIEDWITH);
042    cs.setCopyright("© World Health Organization 2022\r\nSome rights reserved. This work is available under the Creative Commons Attribution-NoDerivatives 3.0 IGO license (CC BY-ND 3.0 IGO further specified at [[https://icd.who.int/en/docs/ICD11-license.pdf]]). \r\nUnder the terms of this license, you may copy and redistribute the work, provided the work is appropriately cited, as indicated below. In any use of this work, there should be no suggestion that WHO endorses any specific organization, products or services. The use of the WHO logo is not permitted. This license does not allow you to produce adaptations of the work (including translations) without permission from WHO.\r\nAny mediation relating to disputes arising under the license shall be conducted in accordance with the mediation rules of the World Intellectual Property Organization.\r\nThis FHIR version of ICD-11 was generated to support the FHIR Community. The definitive version of ICD-11 is available from [[https://icd.who.int/browse11/l-m/en]].\r\n");
043    
044    cs.addProperty().setCode("icd11-uri").setDescription("Entity URI to map to ICD_11").setType(PropertyType.CODE);
045    cs.addProperty().setCode("kind").setDescription("Whether concept is chapter, block, or category").setType(PropertyType.CODE);
046    cs.addProperty().setCode("IsResidual").setDescription("True if the concept is not completely defined by ICD-11").setType(PropertyType.BOOLEAN);
047    Map<String, ConceptDefinitionComponent> codes = new HashMap<>();
048    
049    int lastChapter = 0;
050    int lastBlock = 0;
051    while (csv.line()) {
052      String kind = csv.cell("ClassKind");
053      String code = csv.cell("Code");
054      if (Utilities.noString(code)) {
055        code = csv.cell("BlockId");
056      }
057      ConceptDefinitionComponent c = new ConceptDefinitionComponent();  
058      c.setCode(code);
059      c.setDisplay(fixDisplay(csv.cell("Title")));
060      c.addProperty().setCode("uri").setValue(new CodeType(csv.cell("Linearization (release) URI")));
061      c.addProperty().setCode("kind").setValue(new CodeType(kind));
062      String b = csv.cell("IsResidual").toLowerCase();
063      if (!"false".equals(b)) {
064        c.addProperty().setCode("IsResidual").setValue(new BooleanType(b));
065      }
066      int level = Integer.parseInt(csv.cell("DepthInKind"));
067      String id = kind+"-"+level;
068      String parentId = null;
069        switch (kind) {
070        case "chapter":
071          parentId = null;
072          lastChapter = level;
073          break;
074        case "block":
075          parentId = "chapter-"+lastChapter;
076          lastBlock = level;
077          break;
078        case "category":
079          parentId = "block-"+lastBlock;
080          break;
081        }
082      if (level > 1) {
083        parentId = kind+"-"+(level - 1);
084      }
085      System.out.println(code+" "+kind+" "+level+" "+id+" "+parentId+" ("+lastChapter+" "+lastBlock+")");
086      if (parentId == null) {
087        cs.getConcept().add(c);
088      } else {
089        ConceptDefinitionComponent p = codes.get(parentId);
090        p.getConcept().add(c);
091      }
092      codes.put(id, c);
093      for (int i = level + 1; i < 100; i++) {
094        if (codes.containsKey(i)) {
095          codes.remove(i);
096        }
097      }
098    
099    }
100    csv.close();
101    new JsonParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(dst), cs); 
102  }
103//
104//  private String processLink(String cell) {
105//    String[] p = cell.split("\\\"\\\"");
106//    return p[1];
107//  }
108
109  private String fixDisplay(String cell) {
110    int i = 0;
111    while (i < cell.length() && (cell.charAt(i) == ' ' || cell.charAt(i) == '-')) {
112      i++;
113    }
114    return cell.substring(i);
115  }
116
117}