001package org.hl7.fhir.r5.renderers;
002
003import java.io.IOException;
004import java.io.UnsupportedEncodingException;
005import java.util.List;
006
007import org.hl7.fhir.exceptions.DefinitionException;
008import org.hl7.fhir.exceptions.FHIRException;
009import org.hl7.fhir.exceptions.FHIRFormatError;
010import org.hl7.fhir.r5.model.ActorDefinition;
011import org.hl7.fhir.r5.model.CanonicalResource;
012import org.hl7.fhir.r5.model.CodeSystem;
013import org.hl7.fhir.r5.model.Library;
014import org.hl7.fhir.r5.model.Requirements;
015import org.hl7.fhir.r5.model.Requirements.RequirementsStatementComponent;
016import org.hl7.fhir.r5.model.Resource;
017import org.hl7.fhir.r5.renderers.utils.RenderingContext;
018import org.hl7.fhir.r5.renderers.utils.Resolver.ResourceWithReference;
019import org.hl7.fhir.r5.renderers.utils.ResourceWrapper;
020import org.hl7.fhir.r5.utils.EOperationOutcome;
021import org.hl7.fhir.utilities.Utilities;
022import org.hl7.fhir.utilities.xhtml.XhtmlNode;
023
024public class RequirementsRenderer extends ResourceRenderer {
025
026  public RequirementsRenderer(RenderingContext context) { 
027    super(context); 
028  } 
029
030  @Override
031  public String buildSummary(ResourceWrapper r) throws UnsupportedEncodingException, IOException {
032    return canonicalTitle(r);
033  }
034
035  @Override
036  public void buildNarrative(RenderingStatus status, XhtmlNode x, ResourceWrapper req) throws FHIRFormatError, DefinitionException, IOException, FHIRException, EOperationOutcome {
037    renderResourceTechDetails(req, x);
038    genSummaryTable(status, x, (CanonicalResource) req.getResourceNative());
039
040    if (req.has("actor")) {
041      List<ResourceWrapper> actors = req.children("actor");
042      if (actors.size() == 1) {
043        ActorDefinition acd = context.getWorker().fetchResource(ActorDefinition.class, actors.get(0).primitiveValue(), req.getResourceNative());
044        XhtmlNode p = x.para();
045        p.tx(context.formatPhrase(RenderingContext.REQ_ACTOR)+" ");
046        renderCanonical(status, p, ActorDefinition.class, actors.get(0));
047      } else {
048        x.para().tx(context.formatPhrase(RenderingContext.REQ_FOLLOWING_ACTOR)+" ");
049        XhtmlNode ul = x.ul();
050        for (ResourceWrapper a : actors) {
051          renderCanonical(status, ul.li(), ActorDefinition.class, a);
052        }
053      }
054    }
055    if (req.has("derivedFrom")) {
056      List<ResourceWrapper> list = req.children("derivedFrom");
057      if (list.size() == 1) {
058        XhtmlNode p = x.para();
059        p.tx(context.formatPhrase(RenderingContext.REQ_DERIVE)+" ");
060        renderCanonical(status, p, Requirements.class, list.get(0));
061      } else {
062        x.para().tx(context.formatPhrase(RenderingContext.REQ_FOLLOWING_REQ)+" ");
063        XhtmlNode ul = x.ul();
064        for (ResourceWrapper a : list) {
065          renderCanonical(status, ul.li(), Requirements.class, a);
066        }
067      }
068    }
069    if (req.has("reference")) {
070      XhtmlNode p = x.para();
071      p.tx(context.formatPhrase(RenderingContext.GENERAL_REFS)+" ");
072      int i = 0;
073      for (ResourceWrapper c : req.children("reference")) {
074        i++;
075        if (i>1) p.tx(", ");
076        String url = c.primitiveValue();
077        if (url.contains("#")) {
078          url = url.substring(0, url.indexOf("#"));
079        }
080        p.ah(context.prefixLocalHref(c.primitiveValue())).tx(url);
081      }
082    }
083    XhtmlNode tbl = x.table("grid");
084
085    for (ResourceWrapper stmt : req.children("statement")) {
086      XhtmlNode tr = tbl.tr();
087      String lbl = stmt.has("label") ? stmt.primitiveValue("label") : stmt.primitiveValue("key");
088      XhtmlNode td = tr.td();
089      td.b().an(context.prefixAnchor(stmt.primitiveValue("key")));
090      td.tx(lbl);
091      td = tr.td();
092      boolean first = true;
093      CodeSystem cs = context.getWorker().fetchCodeSystem("http://hl7.org/fhir/conformance-expectation");
094      for (ResourceWrapper t : stmt.children("conformance")) {
095        if (first) first = false; else td.tx(", ");
096        if (cs != null) {
097          td.ah(context.prefixLocalHref(cs.getWebPath()+"#conformance-expectation-"+t.primitiveValue())).tx(t.primitiveValue().toUpperCase());          
098        } else {
099          td.tx(t.primitiveValue().toUpperCase());
100        }
101      }
102      td = tr.td();
103      addMarkdown(td, stmt.primitiveValue("requirement"));
104      if (stmt.has("derivedFrom") || stmt.has("satisfiedBy") || stmt.has("reference") || stmt.has("source")) {
105        td.para().tx(context.formatPhrase(RenderingContext.REQ_LINKS)+" ");
106        XhtmlNode ul = td.ul();
107        if (stmt.has("derivedFrom")) {
108          XhtmlNode li = ul.li();
109          li.tx(context.formatPhrase(RenderingContext.REQ_DERIVED)+" ");
110          String url = stmt.primitiveValue("derivedFrom");
111          String key = url.contains("#") ? url.substring(url.indexOf("#")+1) : "";
112          if (url.contains("#")) { url = url.substring(0, url.indexOf("#")); };
113          Requirements reqr = context.getWorker().fetchResource(Requirements.class, url, req.getResourceNative());
114          if (reqr != null) {
115            RequirementsStatementComponent stmtr = reqr.findStatement(key);
116            if (stmtr != null) {
117              li.ah(context.prefixLocalHref(reqr.getWebPath()+"#"+key)).tx(reqr.present() + " # " +(stmt.has("label") ? stmt.primitiveValue("label") : stmt.primitiveValue("key")));
118            } else {
119              li.ah(context.prefixLocalHref(reqr.getWebPath()+"#"+key)).tx(reqr.present()+" # "+key);              
120            }
121          } else {
122            li.code(stmt.primitiveValue("derivedFrom"));
123          }
124        }
125        if (stmt.has("satisfiedBy")) {
126          XhtmlNode li = ul.li();
127          li.tx(context.formatPhrase(RenderingContext.REQ_SATISFIED)+" ");
128          first = true;
129          for (ResourceWrapper c : stmt.children("satisfiedBy")) {
130            if (first) first = false; else li.tx(", ");
131            String url = c.primitiveValue();
132            if (url.contains("#")) {
133              url = url.substring(0, url.indexOf("#"));
134            }
135            Resource r = context.getWorker().fetchResource(Resource.class, url, req.getResourceNative());
136            if (r != null) {
137              String desc = getResourceDescription(r, null);
138              li.ah(context.prefixLocalHref(c.primitiveValue())).tx(desc);
139            } else {
140              li.ah(context.prefixLocalHref(c.primitiveValue())).tx(url);
141            }
142          }
143        }
144        if (stmt.has("reference")) {
145          XhtmlNode li = ul.li();
146          li.tx(context.formatPhrase(RenderingContext.GENERAL_REFS)+" ");
147          int i = 0;
148          for (ResourceWrapper c : stmt.children("reference")) {
149            i++;
150            if (i>1) li.tx(", ");
151            String url = c.primitiveValue();
152            if (url.contains("#")) {
153              url = url.substring(0, url.indexOf("#"));
154            }
155            li.ah(context.prefixLocalHref(c.primitiveValue())).tx(url);
156          }
157        }
158        if (stmt.has("source")) {
159          XhtmlNode li = ul.li();
160          li.tx(context.formatPhrase(RenderingContext.GENERAL_SRC)+" ");
161          first = true;
162          for (ResourceWrapper c : stmt.children("source")) {
163            if (first) first = false; else li.tx(", ");
164            if (c.has("reference")) {
165              String url = c.primitiveValue("reference");
166              if (url.contains("#")) {
167                url = url.substring(0, url.indexOf("#"));
168              }
169              Resource r = context.getWorker().fetchResource(Resource.class, url, req.getResourceNative());
170              ResourceWithReference t = null;
171              if (r == null && context.getResolver() != null) {
172                t = context.getResolver().resolve(context, url, null);                
173              }
174              if (r != null) {
175                String desc = getResourceDescription(r, c.primitiveValue("display"));
176                li.ah(context.prefixLocalHref(c.primitiveValue("reference"))).tx(desc);
177              } else if (t != null) {
178                String desc = getResourceDescription(t, c.primitiveValue("display"));
179                li.ah(context.prefixLocalHref(t.getWebPath())).tx(desc);
180              } else {
181                li.ah(context.prefixLocalHref(c.primitiveValue("reference"))).tx(url);
182              }
183            } else if (c.has("display")) {
184              li.tx(c.primitiveValue("display"));
185            } else {
186              li.tx("??");
187            }
188          }
189        }
190      }
191    }
192  }
193
194  private String getResourceDescription(ResourceWithReference res, String display) throws UnsupportedEncodingException, IOException {
195    if (!Utilities.noString(display)) {
196      return display;
197    }
198    return RendererFactory.factory(res.getResource(), context.forContained()).buildSummary(res.getResource());
199  }
200
201  private String getResourceDescription(Resource res, String display) throws UnsupportedEncodingException, IOException {
202    if (!Utilities.noString(display)) {
203      return display;
204    }
205    if (res instanceof CanonicalResource) {
206      return ((CanonicalResource) res).present();
207    }
208    return RendererFactory.factory(res, context.forContained()).buildSummary(wrap(res));
209  }
210
211  public void describe(XhtmlNode x, Library lib) {
212    x.tx(display(lib));
213  }
214
215  public String display(Library lib) {
216    return lib.present();
217  }
218
219}