001package org.hl7.fhir.dstu3.utils.formats;
002
003import java.io.ByteArrayOutputStream;
004import java.io.IOException;
005import java.io.OutputStream;
006import java.io.UnsupportedEncodingException;
007import java.util.ArrayList;
008import java.util.Enumeration;
009import java.util.List;
010
011import org.hl7.fhir.dstu3.formats.IParser.OutputStyle;
012import org.hl7.fhir.dstu3.formats.JsonParser;
013import org.hl7.fhir.dstu3.formats.XmlParser;
014import org.hl7.fhir.dstu3.model.Coding;
015import org.hl7.fhir.dstu3.model.ElementDefinition;
016import org.hl7.fhir.dstu3.model.ElementDefinition.ElementDefinitionConstraintComponent;
017import org.hl7.fhir.dstu3.model.ElementDefinition.ElementDefinitionMappingComponent;
018import org.hl7.fhir.dstu3.model.ElementDefinition.ElementDefinitionSlicingDiscriminatorComponent;
019import org.hl7.fhir.dstu3.model.ElementDefinition.TypeRefComponent;
020import org.hl7.fhir.dstu3.model.IdType;
021import org.hl7.fhir.dstu3.model.Reference;
022import org.hl7.fhir.dstu3.model.StringType;
023import org.hl7.fhir.dstu3.model.StructureDefinition;
024import org.hl7.fhir.dstu3.model.StructureDefinition.StructureDefinitionMappingComponent;
025import org.hl7.fhir.dstu3.model.Type;
026import org.hl7.fhir.dstu3.model.UriType;
027import org.hl7.fhir.utilities.TextStreamWriter;
028
029
030public class CSVWriter  extends TextStreamWriter  {
031
032  private StructureDefinition def;
033  private List<StructureDefinitionMappingComponent> mapKeys = new ArrayList<StructureDefinitionMappingComponent>();
034  private List<CSVLine> lines = new ArrayList<CSVLine>();
035  private XmlParser xml = new XmlParser();
036  private JsonParser json = new JsonParser();
037  private boolean asXml;
038
039  private class CSVLine {
040    private String line = "";
041    
042    public void addString(String s) {
043      line = line + (line.equals("") ? "":",") + "\"" + csvEscape(s) + "\"";
044    }
045    
046    public void addString(StringType s) {
047      addString(s==null? "" : s.getValue());
048    }
049
050    public void addValue(String s) {
051      line = line + (line.equals("") ? "":",") + s;
052    }
053    
054    public void addValue(int s) {
055      line = line + (line.equals("") ? "":",") + s;
056    }
057
058    public void addBoolean(boolean b) {
059      addValue(b ? "Y" : "");
060    }
061
062    protected String csvEscape(String s) {
063      if (s==null)
064        return "";
065      else if (s.contains("\""))
066          return s.substring(0,s.indexOf("\"")) + "\"\"" + csvEscape(s.substring(s.indexOf("\"")+1));
067      else
068        return s;
069    }
070    
071    public String toString() {
072      return line;
073    }
074  }
075
076  public CSVWriter(OutputStream out, StructureDefinition def, boolean asXml) throws UnsupportedEncodingException {
077    super(out);
078    this.asXml = asXml;
079    this.def = def;
080    CSVLine header = new CSVLine();
081    lines.add(header);
082    header.addString("Path");                 //A
083    header.addString("Slice Name");           //B
084    header.addString("Alias(s)");             //C
085    header.addString("Label");                //D
086    header.addString("Min");                  //E
087    header.addString("Max");                  //F
088    header.addString("Must Support?");        //G
089    header.addString("Is Modifier?");         //H
090    header.addString("Is Summary?");          //I
091    header.addString("Type(s)");              //J
092    header.addString("Short");                //K
093    header.addString("Definition");           //L
094    header.addString("Comments");             //M
095    header.addString("Requirements");         //N
096    header.addString("Default Value");        //O
097    header.addString("Meaning When Missing"); //P
098    header.addString("Fixed Value");          //Q
099    header.addString("Pattern");              //R
100    header.addString("Example");              //S
101    header.addString("Minimum Value");        //T
102    header.addString("Maximum Value");        //U
103    header.addString("Maximum Length");       //V
104    header.addString("Binding Strength");     //W
105    header.addString("Binding Description");  //X
106    header.addString("Binding Value Set");    //Y
107    header.addString("Code");                 //Z
108    header.addString("Slicing Discriminator");//AA
109    header.addString("Slicing Description");  //AB
110    header.addString("Slicing Ordered");      //AC
111    header.addString("Slicing Rules");        //AD
112    header.addString("Base Path");            //AE
113    header.addString("Base Min");             //AF
114    header.addString("Base Max");             //AG
115    header.addString("Condition(s)");         //AH
116    header.addString("Constraint(s)");        //AI
117    for (StructureDefinitionMappingComponent map : def.getMapping()) {
118      header.addString("Mapping: " + map.getName());
119    }
120  }
121  
122/*  private void findMapKeys(StructureDefinition def, List<StructureDefinitionMappingComponent> maps, IWorkerContext context) {
123        maps.addAll(def.getMapping());
124        if (def.getBaseDefinition()!=null) {
125          StructureDefinition base = context.fetchResource(StructureDefinition.class, def.getBaseDefinition());
126          findMapKeys(base, maps, context);
127        }
128  }*/
129
130  public void processElement(ElementDefinition ed) throws Exception {
131    CSVLine line = new CSVLine();
132    lines.add(line);
133    line.addString(ed.getPath());
134    line.addString(ed.getSliceName());
135    line.addString(itemList(ed.getAlias()));
136    line.addString(ed.getLabel());
137    line.addValue(ed.getMin());
138    line.addValue(ed.getMax());
139    line.addString(ed.getMustSupport() ? "Y" : "");
140    line.addString(ed.getIsModifier() ? "Y" : "");
141    line.addString(ed.getIsSummary() ? "Y" : "");
142    line.addString(itemList(ed.getType()));
143    line.addString(ed.getShort());
144    line.addString(ed.getDefinition());
145    line.addString(ed.getComment());
146    line.addString(ed.getRequirements());
147    line.addString(ed.getDefaultValue()!=null ? renderType(ed.getDefaultValue()) : "");
148    line.addString(ed.getMeaningWhenMissing());
149    line.addString(ed.hasFixed() ? renderType(ed.getFixed()) : "");
150    line.addString(ed.hasPattern() ? renderType(ed.getPattern()) : "");
151    line.addString(ed.hasExample() ? renderType(ed.getExample().get(0).getValue()) : ""); // todo...?
152    line.addString(ed.hasMinValue() ? renderType(ed.getMinValue()) : "");
153    line.addString(ed.hasMaxValue() ? renderType(ed.getMaxValue()) : "");
154    line.addValue((ed.hasMaxLength() ? Integer.toString(ed.getMaxLength()) : ""));
155    if (ed.hasBinding()) {
156      line.addString(ed.getBinding().getStrength()!=null ? ed.getBinding().getStrength().toCode() : "");
157      line.addString(ed.getBinding().getDescription());
158      if (ed.getBinding().getValueSet()==null)
159        line.addString("");
160      else if (ed.getBinding().getValueSet() instanceof Reference)
161      line.addString(ed.getBinding().getValueSetReference().getReference());
162      else
163      line.addString(ed.getBinding().getValueSetUriType().getValue());
164    } else {
165      line.addValue("");
166      line.addValue("");
167      line.addValue("");
168    }
169    line.addString(itemList(ed.getCode()));
170    if (ed.hasSlicing()) {
171      line.addString(itemList(ed.getSlicing().getDiscriminator()));
172      line.addString(ed.getSlicing().getDescription());
173      line.addBoolean(ed.getSlicing().getOrdered());
174      line.addString(ed.getSlicing().getRules()!=null ? ed.getSlicing().getRules().toCode() : "");
175    } else {
176      line.addValue("");
177      line.addValue("");
178      line.addValue("");      
179    }
180    if (ed.getBase()!=null) {
181      line.addString(ed.getBase().getPath());
182      line.addValue(ed.getBase().getMin());
183      line.addValue(ed.getBase().getMax());
184    } else {
185      line.addValue("");
186      line.addValue("");
187      line.addValue("");      
188    }
189    line.addString(itemList(ed.getCondition()));
190    line.addString(itemList(ed.getConstraint()));
191    for (StructureDefinitionMappingComponent mapKey : def.getMapping()) {
192      for (ElementDefinitionMappingComponent map : ed.getMapping()) {
193        if (map.getIdentity().equals(mapKey.getIdentity()))
194                line.addString(map.getMap());
195      }
196    }
197  }
198
199
200  private String itemList(List l) {
201    StringBuilder s = new StringBuilder();
202    for (int i =0; i< l.size(); i++) {
203      Object o = l.get(i);
204      String val = "";
205      if (o instanceof StringType) {
206        val = ((StringType)o).getValue();
207      } else if (o instanceof UriType) {
208        val = ((UriType)o).getValue();
209      } else if (o instanceof IdType) {
210        val = ((IdType)o).getValue();
211      } else if (o instanceof Enumeration<?>) {
212        val = o.toString();
213      } else if (o instanceof TypeRefComponent) {
214        TypeRefComponent t = (TypeRefComponent)o;
215          val = t.getCode() + (t.getProfile() == null ? "" : " {" + t.getProfile() + "}") +(t.getTargetProfile() == null ? "" : " {" + t.getTargetProfile() + "}")  + (t.getAggregation() == null || t.getAggregation().isEmpty() ? "" : " (" + itemList(t.getAggregation()) + ")");
216      } else if (o instanceof Coding) {
217        Coding t = (Coding)o;
218        val = (t.getSystem()==null ? "" : t.getSystem()) + (t.getCode()==null ? "" : "#" + t.getCode()) + (t.getDisplay()==null ? "" : " (" + t.getDisplay() + ")");
219      } else if (o instanceof ElementDefinitionConstraintComponent) {
220        ElementDefinitionConstraintComponent c = (ElementDefinitionConstraintComponent)o;
221        val = c.getKey() + ":" + c.getHuman() + " {" + c.getExpression() + "}";
222      } else if (o instanceof ElementDefinitionSlicingDiscriminatorComponent) {
223        ElementDefinitionSlicingDiscriminatorComponent c = (ElementDefinitionSlicingDiscriminatorComponent)o;
224        val = c.getType().toCode() + ":" + c.getPath() + "}";
225        
226      } else {
227        val = o.toString();
228        val = val.substring(val.indexOf("[")+1);
229        val = val.substring(0, val.indexOf("]"));
230      }
231      s = s.append(val);
232      if (i == 0)
233        s.append("\n");
234    }
235    return s.toString();
236  }
237  
238  private String renderType(Type value) throws Exception {
239    String s = null;
240    ByteArrayOutputStream bs = new ByteArrayOutputStream();
241    if (asXml) {
242      xml.setOutputStyle(OutputStyle.PRETTY);
243      xml.compose(bs, "", value);
244      bs.close();
245      s = bs.toString();
246      s = s.substring(s.indexOf("\n")+2);
247    } else {
248      json.setOutputStyle(OutputStyle.PRETTY);
249      json.compose(bs, value, "");
250      bs.close();
251      s = bs.toString();
252        }
253    return s;
254  }
255
256  public void dump() throws IOException {
257    for (CSVLine l : lines)
258      ln(l.toString());
259    
260    flush();
261    close();
262  }
263
264}