001package org.hl7.fhir.r5.renderers.spreadsheets;
002
003import java.io.FileOutputStream;
004import java.io.IOException;
005import java.io.OutputStream;
006import java.util.List;
007
008import org.apache.poi.ss.usermodel.Row;
009import org.apache.poi.ss.usermodel.Sheet;
010import org.hl7.fhir.exceptions.DefinitionException;
011import org.hl7.fhir.r5.context.IWorkerContext;
012import org.hl7.fhir.r5.context.SimpleWorkerContext;
013import org.hl7.fhir.r5.model.CanonicalType;
014import org.hl7.fhir.r5.model.ElementDefinition;
015import org.hl7.fhir.r5.model.ValueSet;
016import org.hl7.fhir.r5.model.ValueSet.ConceptReferenceComponent;
017import org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent;
018import org.hl7.fhir.r5.model.ValueSet.ConceptSetFilterComponent;
019import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent;
020import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionParameterComponent;
021import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionMappingComponent;
022import org.hl7.fhir.utilities.i18n.I18nConstants;
023
024public class ValueSetSpreadsheetGenerator extends CanonicalSpreadsheetGenerator {
025
026  public ValueSetSpreadsheetGenerator(IWorkerContext context) {
027    super(context);
028  }
029
030  public boolean canGenerate(ValueSet vs) {
031    return true;
032  }
033
034  public ValueSetSpreadsheetGenerator renderValueSet(ValueSet vs) throws IOException {
035    if (vs == null) {
036      System.out.println("no valueset!");
037    }
038    addValueSetMetadata(renderCanonicalResource(vs, false), vs);
039    for (ConceptSetComponent inc : vs.getCompose().getInclude()) {
040      genInclude(vs, inc, "Include");
041    }
042    for (ConceptSetComponent exc : vs.getCompose().getExclude()) {
043      genInclude(vs, exc, "Exclude");
044    }   
045    if (vs.hasExpansion()) {
046      if (vs.getExpansion().hasParameter()) {
047        genExpansionParams(vs.getExpansion().getParameter());        
048      }
049      genExpansion(vs.getExpansion().getContains());
050    }
051    return this;
052  }
053
054  private void addValueSetMetadata(Sheet sheet, ValueSet vs) {
055    addMetadataRow(sheet, "Immutable", vs.getImmutableElement().toString());
056  }
057
058  private void genExpansionParams(List<ValueSetExpansionParameterComponent> params) {
059    Sheet sheet = makeSheet("Expansion Parameters");
060    addHeaders(sheet, "Parameter", "Value");
061    for (ValueSetExpansionParameterComponent p : params) {
062      addRow(sheet, p.getName(), dr.display(p.getValue()));          
063    }    
064  }
065
066  private void genExpansion(List<ValueSetExpansionContainsComponent> list) {
067    Sheet sheet = makeSheet("Expansion");
068    addHeaders(sheet, "Level", "System", "version", "Code", "Display", "Abstract", "Inactive");
069    genExpansionEntry(1, list, sheet);    
070  }
071
072  public void genExpansionEntry(int level, List<ValueSetExpansionContainsComponent> list, Sheet sheet) {
073    for (ValueSetExpansionContainsComponent p : list) {
074      addRow(sheet, Integer.toString(level), p.getSystem(), p.getVersion(), p.getCode(), p.getDisplay(), bool(p.getAbstract()), bool(p.getInactive()));  
075      if (p.hasContains()) {
076        genExpansionEntry(level + 1, p.getContains(), sheet);
077      }
078    }
079  }
080  
081  private String bool(boolean value) {    
082    return value ? "" : "false";
083  }
084
085  private void genInclude(ValueSet vs, ConceptSetComponent inc, String mode) {
086    if (inc.hasSystem()) {
087      genIncludeSystem(vs, inc, mode);
088    } else {
089      genIncludeValueSets(vs, inc, mode);      
090    }
091//    String subname = inc.hasSystem() ?  : "ValueSets";
092//    
093//
094//  Row headerRow = sheet.createRow(0);
095//  for (int i = 0; i < titles.length; i++) {
096//    addCell(headerRow, i, titles[i], styles.get("header"));
097//  }
098//  int i = titles.length - 1;
099//  for (StructureDefinitionMappingComponent map : sd.getMapping()) {
100//    i++;
101//    addCell(headerRow, i, "Mapping: " + map.getName(), styles.get("header"));
102//  }    
103//
104//  for (ElementDefinition child : sd.getSnapshot().getElement()) {
105//    processElement(sheet, sd, child);
106//  }
107//  configureSheet(sheet, sd);
108  }
109
110  private void genIncludeValueSets(ValueSet vs, ConceptSetComponent inc, String mode) {
111    Sheet sheet = makeSheet(mode+" ValueSets");
112    addValueSets(sheet, inc.getValueSet()); 
113    configureSheet(sheet);
114  }
115
116  private void genIncludeSystem(ValueSet vs, ConceptSetComponent inc, String mode) {
117    Sheet sheet = makeSheet(mode+" from "+dr.displaySystem(inc.getSystem()));
118    if (inc.hasValueSet()) {
119      addValueSets(sheet, inc.getValueSet());
120    }
121    if (inc.hasFilter()) {
122      addFilters(sheet, inc.getFilter());
123    }
124    if (inc.hasConcept()) {
125      addConcepts(sheet, inc.getConcept());
126    }
127    if (!inc.hasConcept() && !inc.hasFilter()) {
128      addAllCodes(sheet);
129    }
130    addRow(sheet, "", "");          
131    addRow(sheet, "System URI", inc.getSystem());          
132    
133    configureSheet(sheet);
134  }
135
136  private void addAllCodes(Sheet sheet) {
137    addHeaders(sheet, "Codes");     
138    addRow(sheet, "All codes");          
139  }
140
141  private void addValueSets(Sheet sheet, List<CanonicalType> valueSets) {
142    addHeaders(sheet, "ValueSet URL");
143    for (CanonicalType u : valueSets) {
144      addRow(sheet, u.getValue());
145    }
146  }
147
148  private void configureSheet(Sheet sheet) {
149    sheet.setColumnWidth(0, columnPixels(30));
150    sheet.setColumnWidth(1, columnPixels(40));
151    sheet.setColumnWidth(1, columnPixels(50));
152  }
153
154  private void addConcepts(Sheet sheet, List<ConceptReferenceComponent> concepts) {
155    addHeaders(sheet, "Concept", "Description"); // todo: designations    
156    for (ConceptReferenceComponent cd : concepts) {
157      addRow(sheet, cd.getCode(), cd.getDisplay());      
158    }    
159  }
160
161  private void addFilters(Sheet sheet, List<ConceptSetFilterComponent> filters) {
162    addHeaders(sheet, "Property", "Operation", "Value");    
163    for (ConceptSetFilterComponent f : filters) {
164      addRow(sheet, f.getProperty(), f.getOpElement().asStringValue(), f.getValue());
165    }
166  }
167
168}