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