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