001package org.hl7.fhir.convertors.misc;
002
003import java.io.IOException;
004import java.util.ArrayList;
005import java.util.List;
006
007import javax.xml.parsers.ParserConfigurationException;
008
009import org.hl7.fhir.convertors.analytics.PackageVisitor;
010import org.hl7.fhir.convertors.analytics.PackageVisitor.IPackageVisitorProcessor;
011import org.hl7.fhir.convertors.analytics.PackageVisitor.PackageContext;
012import org.hl7.fhir.exceptions.FHIRException;
013import org.hl7.fhir.r5.utils.EOperationOutcome;
014import org.hl7.fhir.utilities.FileUtilities;
015import org.hl7.fhir.utilities.Utilities;
016import org.hl7.fhir.utilities.json.model.JsonObject;
017import org.hl7.fhir.utilities.json.parser.JsonParser;
018import org.hl7.fhir.utilities.npm.NpmPackage;
019import org.hl7.fhir.utilities.npm.PackageServer;
020import org.xml.sax.SAXException;
021
022@SuppressWarnings("checkstyle:systemout")
023public class MustSupportSlicingFinder implements IPackageVisitorProcessor {
024
025
026  public class Issue {
027    private String pvid;
028    private String url;
029    private String path;
030    private String ref;
031    private boolean ms;
032    private boolean smsOne;
033    private boolean smsAll;
034    private int sliceCount;
035    public Issue(String pvid, String url, String path, String ref, boolean ms, int sliceCount, boolean smsOne, boolean smsAll) {
036      super();
037      this.pvid = pvid;
038      this.url = url;
039      this.path = path;
040      this.ref = ref;
041      this.ms = ms;
042      this.sliceCount = sliceCount;
043      this.smsOne = smsOne;
044      this.smsAll = smsAll;
045    }
046    public String summary() {
047      return url+"#"+path+": "+meaning()+" from "+pvid+" @ "+ref;
048    }
049
050    public String meaning() {
051      if (!ms) {
052        if (sliceCount == 1) {
053          count1++;
054          return "slicer MustSupport = false, but the only slice is must-support";          
055        } else if (sliceCount > 1) {
056          if (smsAll) {
057            count2++;
058            return "slicer MustSupport = false, but all "+sliceCount+" slices are must-support";
059          } else {
060            count3++;
061            return "slicer MustSupport = false, but some of "+sliceCount+" slices are must-support";            
062          }
063        } else {
064          count4++;
065          return "slicer MustSupport = false, and there are no slices"; 
066        }
067      } else if (!smsOne) {
068        if (sliceCount == 0) {
069          count5++;
070          return "slicer MustSupport = true, no slices";
071        } else if (sliceCount == 1) {
072          count6++;
073          return "slicer MustSupport = true, but the slice is not must-support";
074        } else {
075          count7++;
076          return "slicer MustSupport = true, but all "+sliceCount+" slices are not must-support";
077        }
078      } else {
079        if (sliceCount == 1) {
080          count8++;
081          return "slicer MustSupport = true, and the slice is must-support";
082        } else {
083          count9++;
084          return "slicer MustSupport = true, and some of  "+sliceCount+" slices are must-support";
085        }        
086      }
087    }
088  }
089
090  public static void main(String[] args) throws FHIRException, IOException, ParserConfigurationException, SAXException, EOperationOutcome {
091    new MustSupportSlicingFinder().execute();
092  }
093
094  List<Issue> issues = new ArrayList<>();
095  public int count1 = 0;
096  public int count2 = 0;
097  public int count3 = 0;
098  public int count4 = 0;
099  public int count5 = 0;
100  public int count6 = 0;
101  public int count7 = 0;
102  public int count8 = 0;
103  public int count9 = 0;
104  
105
106  private void execute() throws FHIRException, IOException, ParserConfigurationException, SAXException, EOperationOutcome {
107    PackageVisitor pv = new PackageVisitor();
108    pv.setCorePackages(false);
109    pv.setClientPackageServer(PackageServer.primaryServer());
110    pv.setResourceTypes("StructureDefinition", "Patient", "RelatedPerson", "Practitioner", "Person");
111    pv.setProcessor(this);
112    pv.visitPackages();
113    for (Issue s : issues) {
114      System.out.println(s.summary());
115    }
116
117    System.out.println("slicer MustSupport = false, but the only slice is must-support: "+count1);          
118    System.out.println("slicer MustSupport = false, but all N slices are must-support: "+count2);  
119    System.out.println("slicer MustSupport = false, but some of N slices are must-support: "+count3);           
120    System.out.println("slicer MustSupport = false, and there are no slices: "+count4);  
121    System.out.println("slicer MustSupport = true, no slices: "+count5);  
122    System.out.println("slicer MustSupport = true, but the slice is not must-support: "+count6);  
123    System.out.println("slicer MustSupport = true, but all N slices are not must-support: "+count7);  
124    System.out.println("slicer MustSupport = true, and the slice is must-support: "+count8);  
125    System.out.println("slicer MustSupport = true, and some of  N slices are must-support: "+count9);  
126  }
127
128  @Override
129  public Object startPackage(PackageContext context) throws FHIRException, IOException, EOperationOutcome {
130    if (isUS(context.getNpm())) {
131      System.out.println(context.getPid()+" is a US Realm package");
132      return this;
133    } else {
134      return null;
135    }
136  }
137
138  private boolean isUS(NpmPackage npm) {
139    if (npm != null) {
140      return npm.name().contains("hl7.fhir.us");
141    }
142    return false;
143  }
144
145  @Override
146  public void processResource(PackageContext context, Object clientContext, String type, String id, byte[] content)
147      throws FHIRException, IOException, EOperationOutcome {
148    if (clientContext != null && "StructureDefinition".equals(type)) {
149      JsonObject r = JsonParser.parseObject(content);
150      for (JsonObject ed : r.forceObject("snapshot").forceArray("element").asJsonObjects()) {
151        if (ed.has("slicing")) {
152          boolean smsOne = false;
153          boolean smsAll = true;
154          int count = 0;
155          String eid = ed.asString("id");
156          for (JsonObject slice : r.forceObject("snapshot").forceArray("element").asJsonObjects()) {
157            if (slice.has("sliceName") && slice.has("id") && slice.asString("id").equals(eid+":"+slice.asString("sliceName"))) {
158              count++;
159              smsOne = smsOne || slice.asBoolean("mustSupport");
160              smsAll = smsAll && slice.asBoolean("mustSupport");
161            }
162          }
163          
164          if (count > 0 && (ed.asBoolean("mustSupport") || smsOne)) {
165            issues.add(new Issue(context.getPid()+"#"+context.getPid(), r.asString("url")+"|"+r.asString("version"), ed.asString("path"), context.getNpm().getWebLocation(),
166                ed.asBoolean("mustSupport"), count, smsOne, smsAll));
167          }
168        }
169      }
170    }
171  }
172
173
174  @Override
175  public void finishPackage(PackageContext context) throws FHIRException, IOException, EOperationOutcome {    
176  }
177
178  @Override
179  public void alreadyVisited(String pid) throws FHIRException, IOException, EOperationOutcome {
180  }
181
182}