001package org.hl7.fhir.r5.comparison;
002
003import java.io.IOException;
004import java.util.HashMap;
005import java.util.Map;
006import java.util.UUID;
007
008import org.hl7.fhir.exceptions.DefinitionException;
009import org.hl7.fhir.exceptions.FHIRException;
010import org.hl7.fhir.exceptions.FHIRFormatError;
011import org.hl7.fhir.r5.comparison.CapabilityStatementComparer.CapabilityStatementComparison;
012import org.hl7.fhir.r5.comparison.CodeSystemComparer.CodeSystemComparison;
013import org.hl7.fhir.r5.comparison.ProfileComparer.ProfileComparison;
014import org.hl7.fhir.r5.comparison.ResourceComparer.ResourceComparison;
015import org.hl7.fhir.r5.comparison.ValueSetComparer.ValueSetComparison;
016import org.hl7.fhir.r5.conformance.profile.ProfileKnowledgeProvider;
017import org.hl7.fhir.r5.conformance.profile.ProfileUtilities;
018import org.hl7.fhir.r5.context.IWorkerContext;
019import org.hl7.fhir.r5.model.CanonicalResource;
020import org.hl7.fhir.r5.model.CapabilityStatement;
021import org.hl7.fhir.r5.model.CodeSystem;
022import org.hl7.fhir.r5.model.Resource;
023import org.hl7.fhir.r5.model.StructureDefinition;
024import org.hl7.fhir.r5.model.ValueSet;
025
026public class ComparisonSession {
027
028  
029  private Map<String, ResourceComparison> compares = new HashMap<>();
030  private IWorkerContext contextLeft;
031  private IWorkerContext contextRight;
032  private String sessiondId;
033  private int count;
034  private boolean debug;
035  private String title;
036  private ProfileKnowledgeProvider pkpLeft;
037  private ProfileKnowledgeProvider pkpRight;
038  
039  public ComparisonSession(IWorkerContext contextLeft, IWorkerContext contextRight, String title, ProfileKnowledgeProvider pkpLeft, ProfileKnowledgeProvider pkpRight) {
040    super();
041    this.contextLeft = contextLeft;
042    this.contextRight = contextRight;
043    this.sessiondId = UUID.randomUUID().toString().toLowerCase();
044    this.title = title;
045    this.pkpLeft = pkpLeft;
046    this.pkpRight = pkpRight;
047    debug = false;
048  }
049  
050  public IWorkerContext getContextLeft() {
051    return contextLeft;
052  }
053  
054  public IWorkerContext getContextRight() {
055    return contextRight;
056  }
057  
058  public String getTitle() {
059    return title;
060  }
061
062  public ResourceComparison compare(String left, Resource leftSource, String right, Resource rightSource) throws DefinitionException, FHIRFormatError, IOException {
063    CanonicalResource l = (CanonicalResource) contextLeft.fetchResource(Resource.class, left, leftSource);
064    if (l == null) {
065      throw new DefinitionException("Unable to resolve "+left);
066    }
067    CanonicalResource r = (CanonicalResource) contextRight.fetchResource(Resource.class, right, rightSource);
068    if (r == null) {
069      throw new DefinitionException("Unable to resolve "+right);
070    }
071    return compare(l, r);
072  }
073
074  public ResourceComparison compare(CanonicalResource left, CanonicalResource right) throws DefinitionException, FHIRFormatError, IOException {
075    if (left != null && right != null) {
076      String key = key(left.getUrl(), left.getVersion(), right.getUrl(), right.getVersion());
077      if (compares.containsKey(key)) {
078        // if null then the comparison is in progress.
079        // this can happen when profiles refer to each other
080        return compares.get(key);
081      }
082      compares.put(key, null);
083      try {
084        if (left instanceof CodeSystem && right instanceof CodeSystem) {
085          CodeSystemComparer cs = new CodeSystemComparer(this);
086          CodeSystemComparison csc = cs.compare((CodeSystem) left, (CodeSystem) right);
087          compares.put(key, csc);
088          return csc;
089        } else if (left instanceof ValueSet && right instanceof ValueSet) {
090          ValueSetComparer cs = new ValueSetComparer(this);
091          ValueSetComparison csc = cs.compare((ValueSet) left, (ValueSet) right);
092          compares.put(key, csc);
093          return csc;
094        } else if (left instanceof StructureDefinition && right instanceof StructureDefinition) {
095          ProfileComparer cs = new ProfileComparer(this, new ProfileUtilities(contextLeft, null, pkpLeft), new ProfileUtilities(contextRight, null, pkpRight));
096          ProfileComparison csc = cs.compare((StructureDefinition) left, (StructureDefinition) right);
097          compares.put(key, csc);
098          return csc;
099        } else if (left instanceof CapabilityStatement && right instanceof CapabilityStatement) {
100          CapabilityStatementComparer cs = new CapabilityStatementComparer(this);
101          CapabilityStatementComparison csc = cs.compare((CapabilityStatement) left, (CapabilityStatement) right);
102          compares.put(key, csc);
103          return csc;
104        } else {
105          throw new FHIRException("Unable to compare resources of type "+left.fhirType()+" and "+right.fhirType());
106        }
107      } catch (Throwable e) {
108        if (debug) {
109          e.printStackTrace();
110        }
111        ResourceComparer.PlaceHolderComparison csc = new ResourceComparer.PlaceHolderComparison(left, right, e);
112        compares.put(key, csc);
113        return csc;      
114      }
115    } else if (left != null) {
116      String key = key(left.getUrl(), left.getVersion(), left.getUrl(), left.getVersion());
117      if (compares.containsKey(key)) {
118        return compares.get(key);
119      }
120      ResourceComparer.PlaceHolderComparison csc = new ResourceComparer.PlaceHolderComparison(left, right);
121      compares.put(key, csc);
122      return csc;      
123    } else {
124      String key = key(right.getUrl(), right.getVersion(), right.getUrl(), right.getVersion());
125      if (compares.containsKey(key)) {
126        return compares.get(key);
127      }
128      ResourceComparer.PlaceHolderComparison csc = new ResourceComparer.PlaceHolderComparison(left, right);
129      compares.put(key, csc);
130      return csc;      
131    }
132  }
133
134  private String key(String urlL, String verL, String urlR, String verR) {
135    return urlL+"|"+verL+"||"+urlR+"|"+verR;
136  }
137  
138  public void identify(CanonicalResource res) {
139    count++;
140    res.setId(sessiondId+"-"+count);
141    res.setUrl("http://hl7.org/fhir/comparison/"+res.fhirType()+"/"+res.getId());
142  }
143
144  public void identify(ResourceComparison res) {
145    count++;
146  }
147
148  public boolean isDebug() {
149    return debug;
150  }
151
152  public void setDebug(boolean debug) {
153    this.debug = debug;
154  }
155
156  public Map<String, ResourceComparison> getCompares() {
157    return compares;
158  }
159
160  public ProfileKnowledgeProvider getPkpLeft() {
161    return pkpLeft;
162  }
163  
164  public ProfileKnowledgeProvider getPkpRight() {
165    return pkpRight;
166  }
167}