001package org.hl7.fhir.r5.renderers.utils;
002
003import org.hl7.fhir.r5.model.Bundle;
004import org.hl7.fhir.r5.model.Bundle.BundleEntryComponent;
005import org.hl7.fhir.r5.model.DomainResource;
006import org.hl7.fhir.r5.model.Parameters;
007import org.hl7.fhir.r5.model.Parameters.ParametersParameterComponent;
008import org.hl7.fhir.r5.model.Resource;
009import org.hl7.fhir.r5.renderers.utils.BaseWrappers.ResourceWrapper;
010import org.hl7.fhir.r5.renderers.utils.Resolver.ResourceReferenceKind;
011import org.w3c.dom.Element;
012
013public class Resolver {
014
015
016  public interface IReferenceResolver {
017    ResourceWithReference resolve(RenderingContext context, String url);
018    
019    // returns null if contained resource is inlined 
020    String urlForContained(RenderingContext context, String containingType, String containingId, String containedType, String containedId);
021
022    /**
023     * returns the correct literal URL for the specified logical uri
024     * @param context
025     * @param value
026     * @return
027     */
028    String resolveUri(RenderingContext context, String uri);
029  }
030
031  public static class ResourceContext {
032    private ResourceContext container;
033
034    Resource resource;
035    org.hl7.fhir.r5.elementmodel.Element element;
036
037    public ResourceContext(ResourceContext container, Resource dr) {
038      super();
039      this.container = container;
040      this.resource = dr;
041    }
042
043    public ResourceContext(ResourceContext container, org.hl7.fhir.r5.elementmodel.Element dr) {
044      super();
045      this.container = container;
046      this.element = dr;
047    }
048
049    
050//    public ResourceContext(Object bundle, Element doc) {
051//      // TODO Auto-generated constructor stub
052//    }
053
054//    public Bundle getBundleResource() {
055//      return containerResource;
056//    }
057
058
059    public ResourceContext(ResourceContext container, ResourceWrapper rw) {
060      super();
061      this.container = container;
062      // todo: howto do this better?
063      
064      if (rw instanceof DirectWrappers.ResourceWrapperDirect) {
065        this.resource = ((DirectWrappers.ResourceWrapperDirect) rw).getResource();
066      } else if (rw instanceof ElementWrappers.ResourceWrapperMetaElement) {
067        this.element = ((ElementWrappers.ResourceWrapperMetaElement) rw).getElement();
068      } else {
069        // this is not supported for now... throw new Error("Not supported yet");
070      }
071    }
072
073    public ResourceContext getContainer() {
074      return container;
075    }
076
077    public void setContainer(ResourceContext container) {
078      this.container = container;
079    }
080
081    //    public org.hl7.fhir.r5.elementmodel.Element getBundleElement() {
082//      return containerElement;
083//    }
084//
085    public Resource getResource() {
086      return resource;
087    }
088
089    public org.hl7.fhir.r5.elementmodel.Element getElement() {
090      return element;
091    }
092
093    public BundleEntryComponent resolve(String value) {
094      if (value.startsWith("#")) {
095        if (resource instanceof DomainResource) {
096          DomainResource dr = (DomainResource) resource;
097          for (Resource r : dr.getContained()) {
098            if (r.getId().equals(value.substring(1))) {
099              BundleEntryComponent be = new BundleEntryComponent();
100              be.setResource(r);
101              return be;
102            }
103          }
104        }
105        return null;
106      }
107      
108      if (resource instanceof Bundle) {
109        Bundle b = (Bundle) resource;
110        for (BundleEntryComponent be : b.getEntry()) {
111          if (be.hasFullUrl() && be.getFullUrl().equals(value))
112            return be;
113          if (value.equals(be.getResource().fhirType()+"/"+be.getResource().getId()))
114            return be;
115        }
116      } 
117
118      if (resource instanceof Parameters) {
119        Parameters pp = (Parameters) resource;
120        for (ParametersParameterComponent p : pp.getParameter()) {
121          if (p.getResource() != null && value.equals(p.getResource().fhirType()+"/"+p.getResource().getId())) {
122            BundleEntryComponent be = new BundleEntryComponent();
123            be.setResource(p.getResource());
124            return be;
125
126          }
127        }
128      } 
129
130      return container != null ? container.resolve(value) : null;
131    }
132
133    public org.hl7.fhir.r5.elementmodel.Element resolveElement(String value, String version) {
134      if (value.startsWith("#")) {
135        if (element != null) {
136          for (org.hl7.fhir.r5.elementmodel.Element r : element.getChildrenByName("contained")) {
137            if (r.getChildValue("id").equals(value.substring(1)))
138              return r;
139          }          
140        }
141        return null;
142      }
143      if (element != null) {
144        if (element.fhirType().equals("Bundle")) {
145          for (org.hl7.fhir.r5.elementmodel.Element be : element.getChildren("entry")) {
146            org.hl7.fhir.r5.elementmodel.Element res = be.getNamedChild("resource");
147            if (res != null) { 
148              if (value.equals(be.getChildValue("fullUrl"))) {
149                if (checkVersion(version, res)) {
150                  return be;
151                }
152              }
153              if (value.equals(res.fhirType()+"/"+res.getChildValue("id"))) {
154                if (checkVersion(version, res)) {
155                  return be;
156                }
157              }
158            }
159          }
160        }
161        if (element.fhirType().equals("Parameters")) {
162          for (org.hl7.fhir.r5.elementmodel.Element p : element.getChildren("parameter")) {
163            org.hl7.fhir.r5.elementmodel.Element res = p.getNamedChild("resource");
164            if (res != null && value.equals(res.fhirType()+"/"+res.getChildValue("id"))) {
165              if (checkVersion(version, res)) {
166                return p;
167              }
168            }
169          }
170        }
171      }
172      return container != null ? container.resolveElement(value, version) : null;
173    }
174
175    private boolean checkVersion(String version, org.hl7.fhir.r5.elementmodel.Element res) {
176      if (version == null) {
177        return true;
178      } else if (!res.hasChild("meta")) {
179        return false;
180      } else {
181        org.hl7.fhir.r5.elementmodel.Element meta = res.getNamedChild("meta");
182        return version.equals(meta.getChildValue("version"));
183      }
184    }
185  }
186
187
188  public enum ResourceReferenceKind {
189    CONTAINED, BUNDLE, EXTERNAL, UNKNOWN
190
191  }
192  
193  public static class ResourceWithReference {
194
195    private ResourceReferenceKind kind;
196    private String reference;
197    private ResourceWrapper resource;
198
199    public ResourceWithReference(ResourceReferenceKind kind, String reference, ResourceWrapper resource) {
200      super();
201      this.kind = kind;
202      this.reference = reference;
203      this.resource = resource;
204    }
205
206    public ResourceReferenceKind getKind() {
207      return kind;
208    }
209
210    public String getReference() {
211      return reference;
212    }
213
214    public ResourceWrapper getResource() {
215      return resource;
216    }
217  }
218
219
220
221}