001package org.hl7.fhir.convertors.misc;
002
003import java.io.File;
004import java.io.FileInputStream;
005import java.io.FileNotFoundException;
006import java.io.IOException;
007import java.util.ArrayList;
008import java.util.HashMap;
009import java.util.HashSet;
010import java.util.List;
011import java.util.Map;
012import java.util.Map.Entry;
013import java.util.Set;
014
015import javax.xml.parsers.ParserConfigurationException;
016
017import org.hl7.fhir.dstu2.model.ElementDefinition;
018import org.hl7.fhir.dstu2.model.StructureDefinition;
019import org.hl7.fhir.dstu2.model.StructureDefinition.StructureDefinitionSnapshotComponent;
020import org.hl7.fhir.exceptions.FHIRFormatError;
021import org.hl7.fhir.utilities.Utilities;
022import org.hl7.fhir.utilities.filesystem.ManagedFileAccess;
023import org.hl7.fhir.utilities.json.JsonTrackingParser;
024import org.xml.sax.SAXException;
025
026import com.google.gson.JsonArray;
027import com.google.gson.JsonElement;
028import com.google.gson.JsonObject;
029
030@SuppressWarnings("checkstyle:systemout")
031public class XVerPackegeFixer {
032  
033  public static class References {
034    private boolean modifier;
035    private boolean inherited;
036
037    public boolean getModifier() {
038      return modifier;
039    }
040
041    public void setModifier(boolean value) {
042      this.modifier = value;
043    }
044
045    public boolean getInherited() {
046      return inherited;
047    }
048
049    public void setInherited(boolean inherited) {
050      this.inherited = inherited;
051    }
052    
053  }
054
055
056  private static final String R5_FOLDER =  "/Users/grahamegrieve/work/packages/hl7.fhir.rX/hl7.fhir.r5.core/package";
057  private static final String R4_FOLDER =  "/Users/grahamegrieve/work/packages/hl7.fhir.rX/hl7.fhir.r4.core/package";
058  private static final String R3_FOLDER =  "/Users/grahamegrieve/work/packages/hl7.fhir.rX/hl7.fhir.r3.core/package";
059  private static final String R2B_FOLDER = "/Users/grahamegrieve/work/packages/hl7.fhir.rX/hl7.fhir.r2b.core/package";
060  private static final String R2_FOLDER =  "/Users/grahamegrieve/work/packages/hl7.fhir.rX/hl7.fhir.r2.core/package";
061  private static int modCount;
062  
063  private static Map<String, org.hl7.fhir.r5.model.StructureDefinition> map5 = new HashMap<>();
064  private static Map<String, org.hl7.fhir.r4.model.StructureDefinition> map4 = new HashMap<>();
065  private static Map<String, org.hl7.fhir.dstu3.model.StructureDefinition> map3 = new HashMap<>();
066  private static Map<String, org.hl7.fhir.dstu2.model.StructureDefinition> map2 = new HashMap<>();
067  private static Map<String, org.hl7.fhir.dstu2016may.model.StructureDefinition> map2b = new HashMap<>();
068
069  public static void main(String[] args) throws FileNotFoundException, ParserConfigurationException, SAXException, IOException {
070    modCount = 0;
071    for (File f : ManagedFileAccess.file(args[0]).listFiles()) {
072      if (f.getName().startsWith("xver-") && f.getName().contains("1.0")) {
073        JsonObject j = JsonTrackingParser.parseJson(f);
074        fixUp(j, f.getName());
075        JsonTrackingParser.write(j, f, true);
076      }
077    }
078    System.out.println("all done: "+modCount+" modifiers");
079  }
080
081  private static void fixUp(JsonObject j, String name) throws FHIRFormatError, FileNotFoundException, IOException {
082    name = name.replace(".json",  "");
083    System.out.println("Process "+name);
084    String version = name.substring(name.lastIndexOf("-")+1);
085    Set<String> pr = new HashSet<>();
086    
087    int i = 0;
088    for (Entry<String, JsonElement> e : j.entrySet()) {
089      if (i == 50) {
090        i = 0;
091        System.out.print(".");
092      }
093      i++;
094      String n = e.getKey();
095      JsonObject o = ((JsonObject) e.getValue());
096      // boolean ok = (o.has("types") && o.getAsJsonArray("types").size() > 0) || (o.has("elements") && o.getAsJsonArray("elements").size() > 0);
097//      if (!ok) {
098      if (o.has("types")) {
099        o.remove("types");
100      }
101      if (o.has("elements")) {
102        o.remove("elements");
103      }
104      if (o.has("modifier")) {
105        o.remove("modifier");
106      }
107        List<String> types = new ArrayList<>(); 
108        List<String> elements = new ArrayList<>();
109        References mod = new References();
110        getElementInfo(version, n, types, elements, mod);
111        if (mod.getInherited()) {
112          pr.add(n);
113        }
114        if (elements.size() > 0) {
115          JsonArray arr = o.getAsJsonArray("elements");
116          if (arr == null) {
117            arr = new JsonArray();
118            o.add("elements", arr);
119          }
120          for (String s : elements) {
121            arr.add(s);
122          }
123        } else if (types.size() > 0) {
124          JsonArray arr = o.getAsJsonArray("types");
125          if (arr == null) {
126            arr = new JsonArray();
127            o.add("types", arr);
128          }
129          for (String s : types) {
130            arr.add(s);
131          }
132        }
133        if (mod.getModifier()) {
134          o.addProperty("modifier", true);
135          modCount++;
136        }
137//      }
138    }    
139    for (String s : pr) {
140      j.remove(s);
141    }
142    System.out.println("done");
143  }
144
145  private static boolean getElementInfo(String version, String n, List<String> types, List<String> elements, References mod) throws FHIRFormatError, FileNotFoundException, IOException {
146//    if ("contained".equals(n.substring(n.indexOf(".")+1))) {
147//      return false;
148//    }
149    switch (version) {
150    case "4.6": return getElementInfoR5(n, types, elements, mod);
151    case "4.0": return getElementInfoR4(n, types, elements, mod);
152    case "3.0": return getElementInfoR3(n, types, elements, mod);
153    case "1.4": return getElementInfoR2B(n, types, elements, mod);
154    case "1.0": return getElementInfoR2(n, types, elements, mod);
155    }
156    return false;
157  }
158
159  private static String tail(String value) {
160    return value.contains("/") ? value.substring(value.lastIndexOf("/")+1) : value;
161  }
162
163  private static boolean getElementInfoR5(String n, List<String> types, List<String> elements, References mod) throws FHIRFormatError, FileNotFoundException, IOException {    
164    String tn = n.substring(0, n.indexOf("."));
165    org.hl7.fhir.r5.model.StructureDefinition sd = null;
166    if (map5.containsKey(tn)) {
167      sd = map5.get(tn);
168    } else {
169      sd = (org.hl7.fhir.r5.model.StructureDefinition) new org.hl7.fhir.r5.formats.JsonParser().parse(ManagedFileAccess.inStream(Utilities.path(R5_FOLDER, "StructureDefinition-"+tn+".json")));
170      map5.put(tn, sd);
171    }
172    for (org.hl7.fhir.r5.model.ElementDefinition ed : sd.getSnapshot().getElement()) {
173      if (ed.getPath().equals(n)) {
174        mod.setModifier(ed.getIsModifier());
175       List<org.hl7.fhir.r5.model.ElementDefinition> children = listChildrenR5(sd.getSnapshot().getElement(), ed);
176        if (children.size() > 0) {
177          for (org.hl7.fhir.r5.model.ElementDefinition c : children) {
178            String en = c.getPath().substring(ed.getPath().length()+1);
179            elements.add(en);
180          }
181        } else {
182          for (org.hl7.fhir.r5.model.ElementDefinition.TypeRefComponent t : ed.getType()) {
183            if (t.hasTargetProfile()) {
184              StringBuilder b = new StringBuilder();
185              b.append(t.getWorkingCode());
186              b.append("(");
187              boolean first = true;
188              for (org.hl7.fhir.r5.model.CanonicalType u : t.getTargetProfile()) {
189                if (first) first = false; else b.append("|");
190                b.append(tail(u.getValue()));
191              }
192              b.append(")");
193              types.add(b.toString());
194            } else {
195              types.add(t.getWorkingCode());
196            }
197          }
198        }
199      }
200    }
201    return false;
202  }
203
204
205  private static List<org.hl7.fhir.r5.model.ElementDefinition> listChildrenR5(List<org.hl7.fhir.r5.model.ElementDefinition> list, org.hl7.fhir.r5.model.ElementDefinition ed) {
206    List<org.hl7.fhir.r5.model.ElementDefinition> res = new ArrayList<>();
207    for (org.hl7.fhir.r5.model.ElementDefinition t : list) {
208      String p = t.getPath();
209      if (p.startsWith(ed.getPath()+".")) {
210        p = p.substring(ed.getPath().length()+1);
211        if (!p.contains(".")) {
212          res.add(t);
213        }
214      }
215    }
216    return res;
217  }
218  
219  private static boolean getElementInfoR4(String n, List<String> types, List<String> elements, References mod) throws FHIRFormatError, FileNotFoundException, IOException {    
220    String tn = n.substring(0, n.indexOf("."));
221    org.hl7.fhir.r4.model.StructureDefinition sd = null;
222    if (map4.containsKey(tn)) {
223      sd = map4.get(tn);
224    } else {
225      sd = (org.hl7.fhir.r4.model.StructureDefinition) new org.hl7.fhir.r4.formats.JsonParser().parse(ManagedFileAccess.inStream(Utilities.path(R4_FOLDER, "StructureDefinition-"+tn+".json")));
226      map4.put(tn, sd);
227    }
228    for (org.hl7.fhir.r4.model.ElementDefinition ed : sd.getSnapshot().getElement()) {
229      if (ed.getPath().equals(n)) {
230        mod.setModifier(ed.getIsModifier());
231        List<org.hl7.fhir.r4.model.ElementDefinition> children = listChildrenR4(sd.getSnapshot().getElement(), ed);
232        if (children.size() > 0) {
233          for (org.hl7.fhir.r4.model.ElementDefinition c : children) {
234            String en = c.getPath().substring(ed.getPath().length()+1);
235            elements.add(en);
236          }
237        } else {
238          for (org.hl7.fhir.r4.model.ElementDefinition.TypeRefComponent t : ed.getType()) {
239            if (t.hasTargetProfile()) {
240              StringBuilder b = new StringBuilder();
241              b.append(t.getWorkingCode());
242              b.append("(");
243              boolean first = true;
244              for (org.hl7.fhir.r4.model.CanonicalType u : t.getTargetProfile()) {
245                if (first) first = false; else b.append("|");
246                b.append(tail(u.getValue()));
247              }
248              b.append(")");
249              types.add(b.toString());
250            } else {
251              types.add(t.getWorkingCode());
252            }
253          }
254        }
255      }
256    }
257    return false;
258  }
259
260
261  private static List<org.hl7.fhir.r4.model.ElementDefinition> listChildrenR4(List<org.hl7.fhir.r4.model.ElementDefinition> list, org.hl7.fhir.r4.model.ElementDefinition ed) {
262    List<org.hl7.fhir.r4.model.ElementDefinition> res = new ArrayList<>();
263    for (org.hl7.fhir.r4.model.ElementDefinition t : list) {
264      String p = t.getPath();
265      if (p.startsWith(ed.getPath()+".")) {
266        p = p.substring(ed.getPath().length()+1);
267        if (!p.contains(".")) {
268          res.add(t);
269        }
270      }
271    }
272    return res;
273  }
274 
275
276  private static boolean getElementInfoR3(String n, List<String> types, List<String> elements, References mod) throws FHIRFormatError, FileNotFoundException, IOException {    
277    String tn = n.substring(0, n.indexOf("."));
278    org.hl7.fhir.dstu3.model.StructureDefinition sd = null;
279    if (map3.containsKey(tn)) {
280      sd = map3.get(tn);
281    } else {
282      sd = (org.hl7.fhir.dstu3.model.StructureDefinition) new org.hl7.fhir.dstu3.formats.JsonParser().parse(ManagedFileAccess.inStream(Utilities.path(R3_FOLDER, "StructureDefinition-"+tn+".json")));
283      map3.put(tn, sd);
284    }
285    for (org.hl7.fhir.dstu3.model.ElementDefinition ed : sd.getSnapshot().getElement()) {
286      if (ed.getPath().equals(n)) {
287        mod.setModifier(ed.getIsModifier());
288        List<org.hl7.fhir.dstu3.model.ElementDefinition> children = listChildrenR3(sd.getSnapshot().getElement(), ed);
289        if (children.size() > 0) {
290          for (org.hl7.fhir.dstu3.model.ElementDefinition c : children) {
291            String en = c.getPath().substring(ed.getPath().length()+1);
292            elements.add(en);
293          }
294        } else {
295          for (org.hl7.fhir.dstu3.model.ElementDefinition.TypeRefComponent t : ed.getType()) {
296            if (t.hasTargetProfile()) {
297              StringBuilder b = new StringBuilder();
298              b.append(t.getCode());
299              b.append("(");
300              b.append(tail(t.getTargetProfile()));
301              b.append(")");
302              types.add(b.toString());
303            } else {
304              types.add(t.getCode());
305            }
306          }
307        }
308      }
309    }
310    return false;
311  }
312
313
314  private static List<org.hl7.fhir.dstu3.model.ElementDefinition> listChildrenR3(List<org.hl7.fhir.dstu3.model.ElementDefinition> list, org.hl7.fhir.dstu3.model.ElementDefinition ed) {
315    List<org.hl7.fhir.dstu3.model.ElementDefinition> res = new ArrayList<>();
316    for (org.hl7.fhir.dstu3.model.ElementDefinition t : list) {
317      String p = t.getPath();
318      if (p.startsWith(ed.getPath()+".")) {
319        p = p.substring(ed.getPath().length()+1);
320        if (!p.contains(".")) {
321          res.add(t);
322        }
323      }
324    }
325    return res;
326  }
327  
328
329  private static boolean getElementInfoR2(String n, List<String> types, List<String> elements, References mod) throws FHIRFormatError, FileNotFoundException, IOException {    
330    String tn = n.substring(0, n.indexOf("."));
331    org.hl7.fhir.dstu2.model.StructureDefinition sd = null;
332    sd = loadType(tn);
333    mod.setInherited(isInherited(n, sd));
334    for (org.hl7.fhir.dstu2.model.ElementDefinition ed : sd.getSnapshot().getElement()) {
335      if (ed.getPath().equals(n)) {
336        mod.setModifier(ed.getIsModifier());
337        List<org.hl7.fhir.dstu2.model.ElementDefinition> children = listChildrenR2(sd.getSnapshot().getElement(), ed);
338        if (children.size() > 0) {
339          for (org.hl7.fhir.dstu2.model.ElementDefinition c : children) {
340            String en = c.getPath().substring(ed.getPath().length()+1);
341            elements.add(en);
342          }
343        } else {
344          boolean isReference = false;
345          StringBuilder r = new StringBuilder();
346          r.append("Reference(");
347          for (org.hl7.fhir.dstu2.model.ElementDefinition.TypeRefComponent t : ed.getType()) {
348            if (t.hasProfile()) {
349              if ("Reference".equals(t.getCode())) {
350                for (org.hl7.fhir.dstu2.model.UriType u : t.getProfile()) {
351                  if (isReference) 
352                    r.append("|");
353                  r.append(tail(u.getValue()));
354                  isReference = true;
355                }              
356              } else {
357                StringBuilder b = new StringBuilder();
358                b.append(t.getCode());
359                b.append("(");
360                boolean first = true;
361                for (org.hl7.fhir.dstu2.model.UriType u : t.getProfile()) {
362                  if (first) first = false; else b.append("|");
363                  b.append(tail(u.getValue()));
364                }
365                b.append(")");
366                types.add(b.toString());
367              }
368            } else {
369              types.add(t.getCode());
370            }
371          }
372          if (isReference) {
373            r.append(")");
374            types.add(r.toString());              
375          }
376        }
377      }
378    }
379    return false;
380  }
381
382  private static org.hl7.fhir.dstu2.model.StructureDefinition loadType(String tn)
383      throws IOException, FileNotFoundException {
384    org.hl7.fhir.dstu2.model.StructureDefinition sd;
385    if (map2.containsKey(tn)) {
386      sd = map2.get(tn);
387    } else {
388      sd = (org.hl7.fhir.dstu2.model.StructureDefinition) new org.hl7.fhir.dstu2.formats.JsonParser().parse(ManagedFileAccess.inStream(Utilities.path(R2_FOLDER, "StructureDefinition-"+tn+".json")));
389      map2.put(tn, sd);
390    }
391    return sd;
392  }
393
394
395  private static boolean isInherited(String n, StructureDefinition sd) throws FileNotFoundException, IOException {
396    String tail = n.substring(n.indexOf(".")+1);
397    while (sd != null) {
398      sd = sd.hasBase() ? loadType(tail(sd.getBase())) : null;
399      if (sd != null && hasPath(sd.getSnapshot(), sd.getName()+"."+tail)) {
400        return true;
401      }
402    }
403    return false;
404  }
405
406  private static boolean hasPath(StructureDefinitionSnapshotComponent snapshot, String path) {
407    for (ElementDefinition ed : snapshot.getElement()) {
408      if (ed.getPath().equals(path)) {
409        return true;
410      }
411    }
412    return false;
413  }
414
415  private static List<org.hl7.fhir.dstu2.model.ElementDefinition> listChildrenR2(List<org.hl7.fhir.dstu2.model.ElementDefinition> list, org.hl7.fhir.dstu2.model.ElementDefinition ed) {
416    List<org.hl7.fhir.dstu2.model.ElementDefinition> res = new ArrayList<>();
417    for (org.hl7.fhir.dstu2.model.ElementDefinition t : list) {
418      String p = t.getPath();
419      if (p.startsWith(ed.getPath()+".")) {
420        p = p.substring(ed.getPath().length()+1);
421        if (!p.contains(".")) {
422          res.add(t);
423        }
424      }
425    }
426    return res;
427  }
428  
429
430  private static boolean getElementInfoR2B(String n, List<String> types, List<String> elements, References mod) throws FHIRFormatError, FileNotFoundException, IOException {    
431    String tn = n.substring(0, n.indexOf("."));
432    org.hl7.fhir.dstu2016may.model.StructureDefinition sd = null;
433    if (map2b.containsKey(tn)) {
434      sd = map2b.get(tn);
435    } else {
436      sd = (org.hl7.fhir.dstu2016may.model.StructureDefinition) new org.hl7.fhir.dstu2016may.formats.JsonParser().parse(ManagedFileAccess.inStream(Utilities.path(R2B_FOLDER, "StructureDefinition-"+tn+".json")));
437      map2b.put(tn, sd);
438    }
439    for (org.hl7.fhir.dstu2016may.model.ElementDefinition ed : sd.getSnapshot().getElement()) {
440      if (ed.getPath().equals(n)) {
441        mod.setModifier(ed.getIsModifier());
442        List<org.hl7.fhir.dstu2016may.model.ElementDefinition> children = listChildrenR2B(sd.getSnapshot().getElement(), ed);
443        if (children.size() > 0) {
444          for (org.hl7.fhir.dstu2016may.model.ElementDefinition c : children) {
445            String en = c.getPath().substring(ed.getPath().length()+1);
446            elements.add(en);
447          }
448        } else {
449          for (org.hl7.fhir.dstu2016may.model.ElementDefinition.TypeRefComponent t : ed.getType()) {
450            if (t.hasProfile()) {
451              StringBuilder b = new StringBuilder();
452              b.append(t.getCode());
453              b.append("(");
454              boolean first = true;
455              for (org.hl7.fhir.dstu2016may.model.UriType u : t.getProfile()) {
456                if (first) first = false; else b.append("|");
457                b.append(tail(u.getValue()));
458              }              
459              b.append(")");
460              types.add(b.toString());
461            } else {
462              types.add(t.getCode());
463            }
464          }
465        }
466      }
467    }
468    return false;
469  }
470
471
472  private static List<org.hl7.fhir.dstu2016may.model.ElementDefinition> listChildrenR2B(List<org.hl7.fhir.dstu2016may.model.ElementDefinition> list, org.hl7.fhir.dstu2016may.model.ElementDefinition ed) {
473    List<org.hl7.fhir.dstu2016may.model.ElementDefinition> res = new ArrayList<>();
474    for (org.hl7.fhir.dstu2016may.model.ElementDefinition t : list) {
475      String p = t.getPath();
476      if (p.startsWith(ed.getPath()+".")) {
477        p = p.substring(ed.getPath().length()+1);
478        if (!p.contains(".")) {
479          res.add(t);
480        }
481      }
482    }
483    return res;
484  }
485  
486
487}