001package org.hl7.fhir.r4.utils.formats;
002
003/*
004  Copyright (c) 2011+, HL7, Inc.
005  All rights reserved.
006  
007  Redistribution and use in source and binary forms, with or without modification, 
008  are permitted provided that the following conditions are met:
009    
010   * Redistributions of source code must retain the above copyright notice, this 
011     list of conditions and the following disclaimer.
012   * Redistributions in binary form must reproduce the above copyright notice, 
013     this list of conditions and the following disclaimer in the documentation 
014     and/or other materials provided with the distribution.
015   * Neither the name of HL7 nor the names of its contributors may be used to 
016     endorse or promote products derived from this software without specific 
017     prior written permission.
018  
019  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
020  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
021  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
022  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
023  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
024  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
025  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
026  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
027  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
028  POSSIBILITY OF SUCH DAMAGE.
029  
030 */
031
032import java.io.ByteArrayOutputStream;
033import java.io.IOException;
034import java.io.OutputStream;
035import java.io.UnsupportedEncodingException;
036import java.util.ArrayList;
037import java.util.Enumeration;
038import java.util.List;
039
040import org.hl7.fhir.r4.formats.IParser.OutputStyle;
041import org.hl7.fhir.r4.formats.JsonParser;
042import org.hl7.fhir.r4.formats.XmlParser;
043import org.hl7.fhir.r4.model.Coding;
044import org.hl7.fhir.r4.model.ElementDefinition;
045import org.hl7.fhir.r4.model.ElementDefinition.ElementDefinitionConstraintComponent;
046import org.hl7.fhir.r4.model.ElementDefinition.ElementDefinitionMappingComponent;
047import org.hl7.fhir.r4.model.ElementDefinition.ElementDefinitionSlicingDiscriminatorComponent;
048import org.hl7.fhir.r4.model.ElementDefinition.TypeRefComponent;
049import org.hl7.fhir.r4.model.IdType;
050import org.hl7.fhir.r4.model.StringType;
051import org.hl7.fhir.r4.model.StructureDefinition;
052import org.hl7.fhir.r4.model.StructureDefinition.StructureDefinitionMappingComponent;
053import org.hl7.fhir.r4.model.Type;
054import org.hl7.fhir.r4.model.UriType;
055import org.hl7.fhir.utilities.TextStreamWriter;
056
057@Deprecated
058public class CSVWriter extends TextStreamWriter {
059
060  private StructureDefinition def;
061  private List<StructureDefinitionMappingComponent> mapKeys = new ArrayList<StructureDefinitionMappingComponent>();
062  private List<CSVLine> lines = new ArrayList<CSVLine>();
063  private XmlParser xml = new XmlParser();
064  private JsonParser json = new JsonParser();
065  private boolean asXml;
066
067  private class CSVLine {
068    private String line = "";
069
070    public void addString(String s) {
071      line = line + (line.equals("") ? "" : ",") + "\"" + csvEscape(s) + "\"";
072    }
073
074    public void addString(StringType s) {
075      addString(s == null ? "" : s.getValue());
076    }
077
078    public void addValue(String s) {
079      line = line + (line.equals("") ? "" : ",") + s;
080    }
081
082    public void addValue(int s) {
083      line = line + (line.equals("") ? "" : ",") + s;
084    }
085
086    public void addBoolean(boolean b) {
087      addValue(b ? "Y" : "");
088    }
089
090    protected String csvEscape(String s) {
091      if (s == null)
092        return "";
093      else if (s.contains("\""))
094        return s.substring(0, s.indexOf("\"")) + "\"\"" + csvEscape(s.substring(s.indexOf("\"") + 1));
095      else
096        return s;
097    }
098
099    public String toString() {
100      return line;
101    }
102  }
103
104  public CSVWriter(OutputStream out, StructureDefinition def, boolean asXml) throws UnsupportedEncodingException {
105    super(out);
106    this.asXml = asXml;
107    this.def = def;
108    CSVLine header = new CSVLine();
109    lines.add(header);
110    header.addString("Path"); // A
111    header.addString("Slice Name"); // B
112    header.addString("Alias(s)"); // C
113    header.addString("Label"); // D
114    header.addString("Min"); // E
115    header.addString("Max"); // F
116    header.addString("Must Support?"); // G
117    header.addString("Is Modifier?"); // H
118    header.addString("Is Summary?"); // I
119    header.addString("Type(s)"); // J
120    header.addString("Short"); // K
121    header.addString("Definition"); // L
122    header.addString("Comments"); // M
123    header.addString("Requirements"); // N
124    header.addString("Default Value"); // O
125    header.addString("Meaning When Missing"); // P
126    header.addString("Fixed Value"); // Q
127    header.addString("Pattern"); // R
128    header.addString("Example"); // S
129    header.addString("Minimum Value"); // T
130    header.addString("Maximum Value"); // U
131    header.addString("Maximum Length"); // V
132    header.addString("Binding Strength"); // W
133    header.addString("Binding Description"); // X
134    header.addString("Binding Value Set"); // Y
135    header.addString("Code"); // Z
136    header.addString("Slicing Discriminator");// AA
137    header.addString("Slicing Description"); // AB
138    header.addString("Slicing Ordered"); // AC
139    header.addString("Slicing Rules"); // AD
140    header.addString("Base Path"); // AE
141    header.addString("Base Min"); // AF
142    header.addString("Base Max"); // AG
143    header.addString("Condition(s)"); // AH
144    header.addString("Constraint(s)"); // AI
145    for (StructureDefinitionMappingComponent map : def.getMapping()) {
146      header.addString("Mapping: " + map.getName());
147    }
148  }
149
150  /*
151   * private void findMapKeys(StructureDefinition def,
152   * List<StructureDefinitionMappingComponent> maps, IWorkerContext context) {
153   * maps.addAll(def.getMapping()); if (def.getBaseDefinition()!=null) {
154   * StructureDefinition base = context.fetchResource(StructureDefinition.class,
155   * def.getBaseDefinition()); findMapKeys(base, maps, context); } }
156   */
157
158  public void processElement(ElementDefinition ed) throws Exception {
159    CSVLine line = new CSVLine();
160    lines.add(line);
161    line.addString(ed.getPath());
162    line.addString(ed.getSliceName());
163    line.addString(itemList(ed.getAlias()));
164    line.addString(ed.getLabel());
165    line.addValue(ed.getMin());
166    line.addValue(ed.getMax());
167    line.addString(ed.getMustSupport() ? "Y" : "");
168    line.addString(ed.getIsModifier() ? "Y" : "");
169    line.addString(ed.getIsSummary() ? "Y" : "");
170    line.addString(itemList(ed.getType()));
171    line.addString(ed.getShort());
172    line.addString(ed.getDefinition());
173    line.addString(ed.getComment());
174    line.addString(ed.getRequirements());
175    line.addString(ed.getDefaultValue() != null ? renderType(ed.getDefaultValue()) : "");
176    line.addString(ed.getMeaningWhenMissing());
177    line.addString(ed.hasFixed() ? renderType(ed.getFixed()) : "");
178    line.addString(ed.hasPattern() ? renderType(ed.getPattern()) : "");
179    line.addString(ed.hasExample() ? renderType(ed.getExample().get(0).getValue()) : ""); // todo...?
180    line.addString(ed.hasMinValue() ? renderType(ed.getMinValue()) : "");
181    line.addString(ed.hasMaxValue() ? renderType(ed.getMaxValue()) : "");
182    line.addValue((ed.hasMaxLength() ? Integer.toString(ed.getMaxLength()) : ""));
183    if (ed.hasBinding()) {
184      line.addString(ed.getBinding().getStrength() != null ? ed.getBinding().getStrength().toCode() : "");
185      line.addString(ed.getBinding().getDescription());
186      if (ed.getBinding().getValueSet() == null)
187        line.addString("");
188      else
189        line.addString(ed.getBinding().getValueSet());
190    } else {
191      line.addValue("");
192      line.addValue("");
193      line.addValue("");
194    }
195    line.addString(itemList(ed.getCode()));
196    if (ed.hasSlicing()) {
197      line.addString(itemList(ed.getSlicing().getDiscriminator()));
198      line.addString(ed.getSlicing().getDescription());
199      line.addBoolean(ed.getSlicing().getOrdered());
200      line.addString(ed.getSlicing().getRules() != null ? ed.getSlicing().getRules().toCode() : "");
201    } else {
202      line.addValue("");
203      line.addValue("");
204      line.addValue("");
205    }
206    if (ed.getBase() != null) {
207      line.addString(ed.getBase().getPath());
208      line.addValue(ed.getBase().getMin());
209      line.addValue(ed.getBase().getMax());
210    } else {
211      line.addValue("");
212      line.addValue("");
213      line.addValue("");
214    }
215    line.addString(itemList(ed.getCondition()));
216    line.addString(itemList(ed.getConstraint()));
217    for (StructureDefinitionMappingComponent mapKey : def.getMapping()) {
218      for (ElementDefinitionMappingComponent map : ed.getMapping()) {
219        if (map.getIdentity().equals(mapKey.getIdentity()))
220          line.addString(map.getMap());
221      }
222    }
223  }
224
225  private String itemList(List l) {
226    StringBuilder s = new StringBuilder();
227    for (int i = 0; i < l.size(); i++) {
228      Object o = l.get(i);
229      String val = "";
230      if (o instanceof StringType) {
231        val = ((StringType) o).getValue();
232      } else if (o instanceof UriType) {
233        val = ((UriType) o).getValue();
234      } else if (o instanceof IdType) {
235        val = ((IdType) o).getValue();
236      } else if (o instanceof Enumeration<?>) {
237        val = o.toString();
238      } else if (o instanceof TypeRefComponent) {
239        TypeRefComponent t = (TypeRefComponent) o;
240        val = t.getWorkingCode() + (t.getProfile() == null ? "" : " {" + t.getProfile() + "}")
241            + (t.getTargetProfile() == null ? "" : " {" + t.getTargetProfile() + "}")
242            + (t.getAggregation() == null || t.getAggregation().isEmpty() ? ""
243                : " (" + itemList(t.getAggregation()) + ")");
244      } else if (o instanceof Coding) {
245        Coding t = (Coding) o;
246        val = (t.getSystem() == null ? "" : t.getSystem()) + (t.getCode() == null ? "" : "#" + t.getCode())
247            + (t.getDisplay() == null ? "" : " (" + t.getDisplay() + ")");
248      } else if (o instanceof ElementDefinitionConstraintComponent) {
249        ElementDefinitionConstraintComponent c = (ElementDefinitionConstraintComponent) o;
250        val = c.getKey() + ":" + c.getHuman() + " {" + c.getExpression() + "}";
251      } else if (o instanceof ElementDefinitionSlicingDiscriminatorComponent) {
252        ElementDefinitionSlicingDiscriminatorComponent c = (ElementDefinitionSlicingDiscriminatorComponent) o;
253        val = c.getType().toCode() + ":" + c.getPath() + "}";
254
255      } else {
256        val = o.toString();
257        val = val.substring(val.indexOf("[") + 1);
258        val = val.substring(0, val.indexOf("]"));
259      }
260      s = s.append(val);
261      if (i == 0)
262        s.append("\n");
263    }
264    return s.toString();
265  }
266
267  private String renderType(Type value) throws Exception {
268    String s = null;
269    ByteArrayOutputStream bs = new ByteArrayOutputStream();
270    if (asXml) {
271      xml.setOutputStyle(OutputStyle.PRETTY);
272      xml.compose(bs, "", value);
273      bs.close();
274      s = bs.toString();
275      s = s.substring(s.indexOf("\n") + 2);
276    } else {
277      json.setOutputStyle(OutputStyle.PRETTY);
278      json.compose(bs, value, "");
279      bs.close();
280      s = bs.toString();
281    }
282    return s;
283  }
284
285  public void dump() throws IOException {
286    for (CSVLine l : lines)
287      ln(l.toString());
288
289    flush();
290    close();
291  }
292
293}