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;
022import org.hl7.fhir.utilities.filesystem.ManagedFileAccess;
023
024public class ICFImporter {
025
026  public static void main(String[] args) throws FHIRException, FileNotFoundException, IOException {
027    new ICFImporter().doImport(args[0], args[1]);
028
029  }
030
031  private void doImport(String src, String dst) throws FHIRException, FileNotFoundException, IOException {
032    CSVReader csv = new CSVReader(ManagedFileAccess.inStream(src));
033    csv.setDelimiter('\t');
034    csv.readHeaders();
035
036    CodeSystem cs = new CodeSystem();
037    cs.setId("icf");
038    cs.setUrl("http://id.who.int/icd/release/11/beta/icf");
039    cs.setVersion("2023-06");
040    cs.setName("WHOICF");
041    cs.setTitle("WHO ICF");
042    cs.setHierarchyMeaning(CodeSystemHierarchyMeaning.CLASSIFIEDWITH);
043    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");
044    
045    cs.addProperty().setCode("icd11-uri").setDescription("Entity URI to map to ICD_11").setType(PropertyType.CODE);
046    cs.addProperty().setCode("kind").setDescription("Whether concept is chapter, block, or category").setType(PropertyType.CODE);
047    cs.addProperty().setCode("IsResidual").setDescription("True if the concept is not completely defined by ICD-11").setType(PropertyType.BOOLEAN);
048    Map<String, ConceptDefinitionComponent> codes = new HashMap<>();
049    
050    int lastChapter = 0;
051    int lastBlock = 0;
052    while (csv.line()) {
053      String kind = csv.cell("ClassKind");
054      String code = csv.cell("Code");
055      if (Utilities.noString(code)) {
056        code = csv.cell("BlockId");
057      }
058      ConceptDefinitionComponent c = new ConceptDefinitionComponent();  
059      c.setCode(code);
060      c.setDisplay(fixDisplay(csv.cell("Title")));
061      c.addProperty().setCode("uri").setValue(new CodeType(csv.cell("Linearization (release) URI")));
062      c.addProperty().setCode("kind").setValue(new CodeType(kind));
063      String b = csv.cell("IsResidual").toLowerCase();
064      if (!"false".equals(b)) {
065        c.addProperty().setCode("IsResidual").setValue(new BooleanType(b));
066      }
067      int level = Integer.parseInt(csv.cell("DepthInKind"));
068      String id = kind+"-"+level;
069      String parentId = null;
070        switch (kind) {
071        case "chapter":
072          parentId = null;
073          lastChapter = level;
074          break;
075        case "block":
076          parentId = "chapter-"+lastChapter;
077          lastBlock = level;
078          break;
079        case "category":
080          parentId = "block-"+lastBlock;
081          break;
082        }
083      if (level > 1) {
084        parentId = kind+"-"+(level - 1);
085      }
086      System.out.println(code+" "+kind+" "+level+" "+id+" "+parentId+" ("+lastChapter+" "+lastBlock+")");
087      if (parentId == null) {
088        cs.getConcept().add(c);
089      } else {
090        ConceptDefinitionComponent p = codes.get(parentId);
091        p.getConcept().add(c);
092      }
093      codes.put(id, c);
094      for (int i = level + 1; i < 100; i++) {
095        if (codes.containsKey(i)) {
096          codes.remove(i);
097        }
098      }
099    
100    }
101    csv.close();
102    new JsonParser().setOutputStyle(OutputStyle.PRETTY).compose(ManagedFileAccess.outStream(dst), cs); 
103  }
104//
105//  private String processLink(String cell) {
106//    String[] p = cell.split("\\\"\\\"");
107//    return p[1];
108//  }
109
110  private String fixDisplay(String cell) {
111    int i = 0;
112    while (i < cell.length() && (cell.charAt(i) == ' ' || cell.charAt(i) == '-')) {
113      i++;
114    }
115    return cell.substring(i);
116  }
117
118}