001package org.hl7.fhir.r5.renderers;
002
003import java.io.IOException;
004import java.io.UnsupportedEncodingException;
005
006import org.hl7.fhir.exceptions.DefinitionException;
007import org.hl7.fhir.exceptions.FHIRFormatError;
008import org.hl7.fhir.r5.model.ActorDefinition;
009import org.hl7.fhir.r5.model.CanonicalResource;
010import org.hl7.fhir.r5.model.CanonicalType;
011import org.hl7.fhir.r5.model.CodeSystem;
012import org.hl7.fhir.r5.model.Enumeration;
013import org.hl7.fhir.r5.model.Library;
014import org.hl7.fhir.r5.model.Reference;
015import org.hl7.fhir.r5.model.Requirements;
016import org.hl7.fhir.r5.model.Requirements.ConformanceExpectation;
017import org.hl7.fhir.r5.model.Requirements.RequirementsStatementComponent;
018import org.hl7.fhir.r5.model.Resource;
019import org.hl7.fhir.r5.model.UrlType;
020import org.hl7.fhir.r5.renderers.utils.BaseWrappers.ResourceWrapper;
021import org.hl7.fhir.r5.renderers.utils.RenderingContext;
022import org.hl7.fhir.r5.renderers.utils.Resolver.ResourceContext;
023import org.hl7.fhir.r5.renderers.utils.Resolver.ResourceWithReference;
024import org.hl7.fhir.utilities.Utilities;
025import org.hl7.fhir.utilities.xhtml.XhtmlNode;
026
027public class RequirementsRenderer extends ResourceRenderer {
028
029  public RequirementsRenderer(RenderingContext context) {
030    super(context);
031  }
032
033  public RequirementsRenderer(RenderingContext context, ResourceContext rcontext) {
034    super(context, rcontext);
035  }
036  
037  public boolean render(XhtmlNode x, Resource dr) throws FHIRFormatError, DefinitionException, IOException {
038    return render(x, (Requirements) dr);
039  }
040
041  public boolean render(XhtmlNode x, Requirements req) throws FHIRFormatError, DefinitionException, IOException {
042    if (req.hasActor()) {
043      if (req.getActor().size() == 1) {
044        ActorDefinition acd = context.getWorker().fetchResource(ActorDefinition.class, req.getActor().get(0).getValue(), req);
045        XhtmlNode p = x.para();
046        p.tx("These requirements apply to the actor ");
047        if (acd == null) {
048          p.code(req.getActor().get(0).getValue());
049        } else {
050          p.ah(acd.getWebPath()).tx(acd.present());
051        }
052      } else {
053        x.para().tx("These requirements apply to the following actors:");
054        XhtmlNode ul = x.ul();
055        for (CanonicalType a : req.getActor()) {
056          ActorDefinition acd = context.getWorker().fetchResource(ActorDefinition.class, a.getValue(), req);
057          if (acd == null) {
058            ul.li().code(a.getValue());
059          } else {
060            ul.li().ah(acd.getWebPath()).tx(acd.present());
061          }
062        }
063      }
064    }
065    if (req.hasDerivedFrom()) {
066      if (req.getDerivedFrom().size() == 1) {
067        Requirements reqd = context.getWorker().fetchResource(Requirements.class, req.getDerivedFrom().get(0).getValue(), req);
068        XhtmlNode p = x.para();
069        p.tx("These requirements derive from ");
070        if (reqd == null) {
071          p.code(req.getDerivedFrom().get(0).getValue());
072        } else {
073          p.ah(reqd.getWebPath()).tx(reqd.present());
074        }
075      } else {
076        x.para().tx("These requirements are derived from the following requirements:");
077        XhtmlNode ul = x.ul();
078        for (CanonicalType a : req.getDerivedFrom()) {
079          Requirements reqd = context.getWorker().fetchResource(Requirements.class, a.getValue(), req);
080          if (reqd == null) {
081            ul.li().code(a.getValue());
082          } else {
083            ul.li().ah(reqd.getWebPath()).tx(reqd.present());
084          }
085        }
086      }
087    }
088    
089    XhtmlNode tbl = x.table("grid");
090    
091    for (RequirementsStatementComponent stmt : req.getStatement()) {
092      XhtmlNode tr = tbl.tr();
093      String lbl = stmt.hasLabel() ? stmt.getLabel() : stmt.getKey();
094      XhtmlNode td = tr.td();
095      td.b().an(stmt.getKey());
096      td.tx(lbl);
097      td = tr.td();
098      boolean first = true;
099      CodeSystem cs = context.getWorker().fetchCodeSystem("http://hl7.org/fhir/conformance-expectation");
100      for (Enumeration<ConformanceExpectation> t : stmt.getConformance()) {
101        if (first) first = false; else td.tx(", ");
102        if (cs != null) {
103          td.ah(cs.getWebPath()+"#conformance-expectation-"+t.asStringValue()).tx(t.asStringValue().toUpperCase());          
104        } else {
105          td.tx(t.asStringValue().toUpperCase());
106        }
107      }
108      td = tr.td();
109      addMarkdown(td, stmt.getRequirement());
110      if (stmt.hasDerivedFrom() || stmt.hasSatisfiedBy() || stmt.hasReference() || stmt.hasSource()) {
111        td.para().tx("Links:");
112        XhtmlNode ul = td.ul();
113        if (stmt.hasDerivedFrom()) {
114          XhtmlNode li = ul.li();
115          li.tx("Derived From: ");
116          String url = stmt.getDerivedFrom();
117          String key = url.contains("#") ? url.substring(url.indexOf("#")+1) : "";
118          if (url.contains("#")) { url = url.substring(0, url.indexOf("#")); };
119          Requirements reqr = context.getWorker().fetchResource(Requirements.class, url, req);
120          if (reqr != null) {
121            RequirementsStatementComponent stmtr = reqr.findStatement(key);
122            if (stmtr != null) {
123              li.ah(reqr.getWebPath()+"#"+key).tx(reqr.present() + " # " +(stmt.hasLabel() ? stmt.getLabel() : stmt.getKey()));
124            } else {
125              li.ah(reqr.getWebPath()+"#"+key).tx(reqr.present()+" # "+key);              
126            }
127          } else {
128            li.code(stmt.getDerivedFrom());
129          }
130        }
131        if (stmt.hasSatisfiedBy()) {
132          XhtmlNode li = ul.li();
133          li.tx("Satisfied By: ");
134          first = true;
135          for (UrlType c : stmt.getSatisfiedBy()) {
136            if (first) first = false; else li.tx(", ");
137            String url = c.getValue();
138            if (url.contains("#")) {
139              url = url.substring(0, url.indexOf("#"));
140            }
141            Resource r = context.getWorker().fetchResource(Resource.class, url, req);
142            if (r != null) {
143              String desc = getResourceDescription(r, null);
144              li.ah(c.getValue()).tx(desc);
145            } else {
146              li.ah(c.getValue()).tx(url);
147            }
148          }
149        }
150        if (stmt.hasReference()) {
151          XhtmlNode li = ul.li();
152          li.tx("References: ");
153          int i = 0;
154          for (UrlType c : stmt.getSatisfiedBy()) {
155            i++;
156            if (i>1) li.tx(", ");
157            String url = c.getValue();
158            if (url.contains("#")) {
159              url = url.substring(0, url.indexOf("#"));
160            }
161            li.ah(c.getValue()).tx(url);
162          }
163        }
164        if (stmt.hasSource()) {
165          XhtmlNode li = ul.li();
166          li.tx("Source: ");
167          first = true;
168          for (Reference c : stmt.getSource()) {
169            if (first) first = false; else li.tx(", ");
170            if (c.hasReference()) {
171              String url = c.getReference();
172              if (url.contains("#")) {
173                url = url.substring(0, url.indexOf("#"));
174              }
175              Resource r = context.getWorker().fetchResource(Resource.class, url, req);
176              ResourceWithReference t = null;
177              if (r == null && context.getResolver() != null) {
178                t = context.getResolver().resolve(context, url);                
179              }
180              if (r != null) {
181                String desc = getResourceDescription(r, c.getDisplay());
182                li.ah(c.getReference()).tx(desc);
183              } else if (t != null) {
184                String desc = getResourceDescription(t, c.getDisplay());
185                li.ah(t.getReference()).tx(desc);
186              } else {
187                li.ah(c.getReference()).tx(url);
188              }
189            } else if (c.hasDisplay()) {
190              li.tx(c.getDisplay());
191            } else {
192              li.tx("??");
193            }
194          }
195        }
196      }
197    }
198    return false;
199  }
200  
201  private String getResourceDescription(ResourceWithReference res, String display) throws UnsupportedEncodingException, IOException {
202    if (!Utilities.noString(display)) {
203      return display;
204    }
205    return RendererFactory.factory(res.getResource(), context).display(res.getResource());
206  }
207
208  private String getResourceDescription(Resource res, String display) throws UnsupportedEncodingException, IOException {
209    if (!Utilities.noString(display)) {
210      return display;
211    }
212    if (res instanceof CanonicalResource) {
213      return ((CanonicalResource) res).present();
214    }
215    return RendererFactory.factory(res, context).display(res);
216  }
217
218  public void describe(XhtmlNode x, Library lib) {
219    x.tx(display(lib));
220  }
221
222  public String display(Library lib) {
223    return lib.present();
224  }
225
226  @Override
227  public String display(Resource r) throws UnsupportedEncodingException, IOException {
228    return ((Library) r).present();
229  }
230
231  @Override
232  public String display(ResourceWrapper r) throws UnsupportedEncodingException, IOException {
233    if (r.has("title")) {
234      return r.children("title").get(0).getBase().primitiveValue();
235    }
236    return "??";
237  }
238  
239}