001package org.hl7.fhir.convertors.analytics;
002
003import java.io.IOException;
004import java.util.ArrayList;
005import java.util.Collections;
006import java.util.HashMap;
007import java.util.HashSet;
008import java.util.List;
009import java.util.Map;
010import java.util.Set;
011
012import javax.xml.parsers.ParserConfigurationException;
013
014import org.hl7.fhir.convertors.analytics.PackageVisitor.IPackageVisitorProcessor;
015import org.hl7.fhir.dstu2.model.SearchParameter;
016import org.hl7.fhir.exceptions.FHIRException;
017import org.hl7.fhir.exceptions.FHIRFormatError;
018import org.hl7.fhir.r5.model.Bundle.BundleEntryComponent;
019import org.hl7.fhir.utilities.Utilities;
020import org.hl7.fhir.utilities.VersionUtilities;
021import org.xml.sax.SAXException;
022
023public class SearchParameterAnalysis implements IPackageVisitorProcessor {
024
025  public static class SearchParameterTypeUsage {
026    private Set<String> coreUsage = new HashSet<>(); 
027    private Set<String> igUsage = new HashSet<>();
028    public String summary() {
029      return ""+coreUsage.size()+" / "+igUsage.size();
030    }
031  }
032  
033  public static class SearchParameterType {
034    private Map<String, SearchParameterTypeUsage> usages = new HashMap<>();
035    public void seeUsage(boolean core, String usage, String url) {
036      if (!usages.containsKey(usage)) {
037        usages.put(usage, new SearchParameterTypeUsage());       
038      }
039      SearchParameterTypeUsage tu = usages.get(usage);
040      if (core) {
041        tu.coreUsage.add(url);
042      } else {
043        tu.igUsage.add(url);
044      }
045      
046    } 
047  }
048  
049  public static class SearchParameterVersionAnalysis {
050    private Map<String, SearchParameterType> types = new HashMap<>();
051    private String version;
052    
053    public void seeUsage(boolean core, String type, String usage, String url) {
054//      System.out.println("v"+version+" "+Utilities.padRight(url, ' ', 60)+" "+type+"/"+usage);
055      if (type == null) {
056        type = "n/a";
057      }
058      if (usage == null) {
059        usage = "n/a";
060      }
061      if (!types.containsKey(type)) {
062        types.put(type, new SearchParameterType());
063      }
064      SearchParameterType tu = types.get(type);
065      tu.seeUsage(core, usage, url);
066    }
067
068    public void printSummary() {
069      Set<String> usages = new HashSet<>();
070      for (SearchParameterType tu : types.values()) {
071        usages.addAll(tu.usages.keySet());
072      }
073      List<String> ul = new ArrayList<String>();
074      ul.addAll(usages);
075      Collections.sort(ul);
076      System.out.print(Utilities.padRight("", ' ', 10));
077      for (String u : ul) {
078        System.out.print(Utilities.padRight(u, ' ', 10));        
079      }
080      System.out.println();
081      for (String t : types.keySet()) {
082        System.out.print(Utilities.padRight(t, ' ', 10));
083        SearchParameterType tu = types.get(t);
084        for (String u : ul) {
085          SearchParameterTypeUsage uu = tu.usages.get(u);
086          if (uu == null) {
087            System.out.print(Utilities.padRight("0 / 0", ' ', 10));
088          } else {
089            System.out.print(Utilities.padRight(uu.summary(), ' ', 10));            
090          }
091        }
092        System.out.println();
093      }
094      
095    }
096    
097  }
098  
099  private Map<String, SearchParameterVersionAnalysis> versions = new HashMap<String, SearchParameterAnalysis.SearchParameterVersionAnalysis>();
100  
101  @Override
102  public void processResource(String pid, String version, String type, byte[] content) throws FHIRException {
103//    System.out.println("v"+version+" "+type+" from "+pid);    
104    boolean core = pid.startsWith("hl7.fhir.r") && (pid.contains(".core") || pid.contains(".examples"));
105    version = VersionUtilities.getMajMin(version);
106    if (!versions.containsKey(version)) {
107      versions.put(version, new SearchParameterVersionAnalysis());
108      versions.get(version).version = version;
109    }
110    try {
111    if (VersionUtilities.isR5Ver(version)) {
112      processR5SP(core, versions.get(version), content);
113    } else if (VersionUtilities.isR4BVer(version)) {
114      processR4SP(core, versions.get(version), content);
115    } else if (VersionUtilities.isR4Ver(version)) {
116      processR4SP(core, versions.get(version), content);
117    } else if (VersionUtilities.isR3Ver(version)) {
118      processR3SP(core, versions.get(version), content);
119    } else if (VersionUtilities.isR2Ver(version)) {
120      processR2SP(core, versions.get(version), content);
121    } 
122    } catch (IOException e) {
123      throw new FHIRException(e);
124    }
125  }
126
127  private void processR5SP(boolean core, SearchParameterVersionAnalysis analysis, byte[] content) throws FHIRFormatError, IOException {
128    org.hl7.fhir.r5.model.Resource res = new org.hl7.fhir.r5.formats.JsonParser().parse(content);
129    if (res instanceof org.hl7.fhir.r5.model.Bundle) {
130      for (org.hl7.fhir.r5.model.Bundle.BundleEntryComponent bnd : ((org.hl7.fhir.r5.model.Bundle) res).getEntry()) {
131        if (bnd.getResource() != null && bnd.getResource() instanceof org.hl7.fhir.r5.model.SearchParameter) {
132          org.hl7.fhir.r5.model.SearchParameter sp = (org.hl7.fhir.r5.model.SearchParameter) bnd.getResource();
133          analysis.seeUsage(core, sp.getTypeElement().primitiveValue(), sp.getXpathUsageElement().primitiveValue(), sp.getUrl());          
134        }
135      }
136    } else {
137      org.hl7.fhir.r5.model.SearchParameter sp = (org.hl7.fhir.r5.model.SearchParameter) res;
138      analysis.seeUsage(core, sp.getTypeElement().primitiveValue(), sp.getXpathUsageElement().primitiveValue(), sp.getUrl());
139    }
140  }
141
142  private void processR4SP(boolean core, SearchParameterVersionAnalysis analysis, byte[] content) throws FHIRFormatError, IOException {
143    org.hl7.fhir.r4.model.Resource res = new org.hl7.fhir.r4.formats.JsonParser().parse(content);
144    if (res instanceof org.hl7.fhir.r4.model.Bundle) {
145      for (org.hl7.fhir.r4.model.Bundle.BundleEntryComponent bnd : ((org.hl7.fhir.r4.model.Bundle) res).getEntry()) {
146        if (bnd.getResource() != null && bnd.getResource() instanceof org.hl7.fhir.r4.model.SearchParameter) {
147          org.hl7.fhir.r4.model.SearchParameter sp = (org.hl7.fhir.r4.model.SearchParameter) bnd.getResource();
148          analysis.seeUsage(core, sp.getTypeElement().primitiveValue(), sp.getXpathUsageElement().primitiveValue(), sp.getUrl());          
149        }
150      }
151    } else {
152      org.hl7.fhir.r4.model.SearchParameter sp = (org.hl7.fhir.r4.model.SearchParameter) res;
153      analysis.seeUsage(core, sp.getTypeElement().primitiveValue(), sp.getXpathUsageElement().primitiveValue(), sp.getUrl());
154    }
155  }
156
157  private void processR3SP(boolean core, SearchParameterVersionAnalysis analysis, byte[] content) throws FHIRFormatError, IOException {
158    org.hl7.fhir.dstu3.model.Resource res = new org.hl7.fhir.dstu3.formats.JsonParser().parse(content);
159    if (res instanceof org.hl7.fhir.dstu3.model.Bundle) {
160      for (org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent bnd : ((org.hl7.fhir.dstu3.model.Bundle) res).getEntry()) {
161        if (bnd.getResource() != null && bnd.getResource() instanceof org.hl7.fhir.dstu3.model.SearchParameter) {
162          org.hl7.fhir.dstu3.model.SearchParameter sp = (org.hl7.fhir.dstu3.model.SearchParameter) bnd.getResource();
163          analysis.seeUsage(core, sp.getTypeElement().primitiveValue(), sp.getXpathUsageElement().primitiveValue(), sp.getUrl());          
164        }
165      }
166    } else {
167      org.hl7.fhir.dstu3.model.SearchParameter sp = (org.hl7.fhir.dstu3.model.SearchParameter) res;
168      analysis.seeUsage(core, sp.getTypeElement().primitiveValue(), sp.getXpathUsageElement().primitiveValue(), sp.getUrl());
169    }
170  }
171
172  private void processR2SP(boolean core, SearchParameterVersionAnalysis analysis, byte[] content) throws FHIRFormatError, IOException {
173    org.hl7.fhir.dstu2.model.Resource res = new org.hl7.fhir.dstu2.formats.JsonParser().parse(content);
174    if (res instanceof org.hl7.fhir.dstu2.model.Bundle) {
175      for (org.hl7.fhir.dstu2.model.Bundle.BundleEntryComponent bnd : ((org.hl7.fhir.dstu2.model.Bundle) res).getEntry()) {
176        if (bnd.getResource() != null && bnd.getResource() instanceof org.hl7.fhir.dstu2.model.SearchParameter) {
177          org.hl7.fhir.dstu2.model.SearchParameter sp = (org.hl7.fhir.dstu2.model.SearchParameter) bnd.getResource();
178          analysis.seeUsage(core, sp.getTypeElement().primitiveValue(), sp.getXpathUsageElement().primitiveValue(), sp.getUrl());          
179        }
180      }
181    } else {
182      org.hl7.fhir.dstu2.model.SearchParameter sp = (org.hl7.fhir.dstu2.model.SearchParameter) res;
183      analysis.seeUsage(core, sp.getTypeElement().primitiveValue(), sp.getXpathUsageElement().primitiveValue(), sp.getUrl());
184    }
185  }
186
187  public static void main(String[] args) throws Exception {
188    new SearchParameterAnalysis().execute();
189  }
190
191  private void execute() throws IOException, ParserConfigurationException, SAXException {
192    PackageVisitor pv = new PackageVisitor();
193    pv.getResourceTypes().add("SearchParameter");
194    pv.getResourceTypes().add("Bundle");
195    pv.setOldVersions(false);
196    pv.setCorePackages(true);
197    pv.setProcessor(this);
198    pv.visitPackages();
199
200    printSummary();
201  }
202
203  private void printSummary() {
204      for (String v : versions.keySet()) {
205        System.out.println("-- v"+v+"---------------------");
206        versions.get(v).printSummary();
207        System.out.println("");
208      }
209      
210  }
211}