001package org.hl7.fhir.r5.renderers;
002
003import java.util.Date;
004
005import org.hl7.fhir.r5.comparison.VersionComparisonAnnotation;
006import org.hl7.fhir.r5.context.IWorkerContext;
007import org.hl7.fhir.r5.model.Base;
008import org.hl7.fhir.r5.model.Enumeration;
009import org.hl7.fhir.r5.renderers.utils.RenderingContext;
010import org.hl7.fhir.r5.renderers.utils.RenderingContext.GenerationRules;
011import org.hl7.fhir.r5.renderers.utils.RenderingContext.KnownLinkType;
012import org.hl7.fhir.r5.renderers.utils.RenderingContext.ResourceRendererMode;
013import org.hl7.fhir.utilities.MarkDownProcessor;
014import org.hl7.fhir.utilities.StandardsStatus;
015import org.hl7.fhir.utilities.Utilities;
016import org.hl7.fhir.utilities.MarkDownProcessor.Dialect;
017import org.hl7.fhir.utilities.validation.ValidationOptions;
018import org.hl7.fhir.utilities.xhtml.NodeType;
019import org.hl7.fhir.utilities.xhtml.XhtmlNode;
020
021/**
022 * Rendering framework:
023 * 
024 *   * boolean render(DomainResource) : produce an HTML representation suitable for runtime / documentation, and insert it into the resource. Return true of any extensions encountered
025 *   * boolean render(XhtmlNode, Resource: produce an HTML representation, and fill out the provided node with it. Return true of any extensions encountered
026 *   * XhtmlNode build(DomainResource): same as render(DomainResource) but also return the XHtmlNode 
027 *   
028 *   * String display(Base) : produce a plan text concise representation that serves to describe the resource
029 *   * void display(XhtmlNode, Base) : produce a plan text concise representation that serves to describe the resource
030 *   
031 *   * void describe(XhtmlNode, Resource) : produce a short summary of the resource with key details presented (potentially more verbose than display, but still suitable for a single line)  
032 *   
033 * if not specific code for rendering a resource has been provided, and there's no liquid script to guide it, a generic rendering based onthe profile will be performed
034 *   
035 * @author graha
036 *
037 */
038public class Renderer  {
039
040  protected RenderingContext context;
041  
042  public Renderer(RenderingContext context) {
043    this.context = context;
044  }
045
046  public Renderer(IWorkerContext worker) {
047    this.context = new RenderingContext(worker, new MarkDownProcessor(Dialect.COMMON_MARK), ValidationOptions.defaults(), "http://hl7.org/fhir/R5", "", null, ResourceRendererMode.END_USER, GenerationRules.IG_PUBLISHER);
048  }
049
050
051  protected String formatPhrase(String theMessage, Object... theMessageArguments) {
052    return context.formatPhrase(theMessage, theMessageArguments);
053  }
054
055  public void genStandardsStatus(XhtmlNode td, StandardsStatus ss) {
056    if (ss != null) {
057      td.tx(" ");
058      XhtmlNode a = td.ah(Utilities.pathURL(context.getLink(KnownLinkType.SPEC), "versions.html#std-process"), (context.formatPhrase(RenderingContext.REND_STANDARDS, ss.toDisplay())));
059      a.style("padding-left: 3px; padding-right: 3px; border: 1px grey solid; font-weight: bold; color: black; background-color: "+ss.getColor());
060      a.tx(ss.getAbbrev());
061    }
062  }
063
064  protected XhtmlNode renderStatus(Base b, XhtmlNode x) {
065    if (b == null || context.getChangeVersion() == null) {
066      return x;
067    }
068    VersionComparisonAnnotation vca = (VersionComparisonAnnotation) b.getUserData(VersionComparisonAnnotation.USER_DATA_NAME);
069    if (vca == null) {
070      return x;
071    }
072    switch (vca.getType()) {
073    case Added:
074      XhtmlNode spanOuter = x.span("border: solid 1px #dddddd; margin: 2px; padding: 2px", null);
075      XhtmlNode spanInner = spanOuter.span("background-color: #fff2ff; border-left: solid 3px #ffa0ff; margin: 2px; padding: 2px", (context.formatPhrase(RenderingContext.REND_SINCE_ADDED, context.getChangeVersion())));
076      spanInner.img("icon-change-add.png", "icon");
077      spanInner.tx(" "+context.formatPhrase(RenderingContext.REND_ADDED));
078      return spanOuter;
079    case Changed:
080      spanOuter = x.span("border: solid 1px #dddddd; margin: 2px; padding: 2px", null);
081      spanInner = spanOuter.span("background-color: #fff2ff; border-left: solid 3px #ffa0ff; margin: 2px; padding: 2px", vca.getOriginal() == null ? context.formatPhrase(RenderingContext.REND_SINCE_CHANGED, context.getChangeVersion()) : context.formatPhrase(RenderingContext.REND_SINCE_CHANGED_WAS, context.getChangeVersion(), vca.getOriginal()));
082      spanInner.img("icon-change-edit.png", "icon");
083      spanInner.tx(" "+context.formatPhrase(RenderingContext.REND_CHANGED));
084      return spanOuter;
085    case Deleted:
086      spanOuter = x.span("border: solid 1px #dddddd; margin: 2px; padding: 2px", null);
087      spanInner = spanOuter.span("background-color: #fff2ff; border-left: solid 3px #ffa0ff; margin: 2px; padding: 2px", (context.formatPhrase(RenderingContext.GENERAL_REMOVED_SINCE, context.getChangeVersion())));
088      spanInner.img("icon-change-remove.png", "icon");
089      spanInner.tx(" "+context.formatPhrase(RenderingContext.REND_REMOVED));
090      return spanOuter.strikethrough();
091    default:
092      return x;
093    }
094  }
095
096  protected XhtmlNode renderStatusDiv(Base b, XhtmlNode x) {
097    if (b == null || context.getChangeVersion() == null) {
098      return x;
099    }
100    VersionComparisonAnnotation vca = (VersionComparisonAnnotation) b.getUserData(VersionComparisonAnnotation.USER_DATA_NAME);
101    if (vca == null) {
102      return x;
103    }
104    switch (vca.getType()) {
105    case Added:
106      XhtmlNode divOuter = x.div("border: solid 1px #dddddd; margin: 2px; padding: 2px");
107      XhtmlNode spanInner = divOuter.para().style("margin: 0").span("background-color: #fff2ff; border-left: solid 3px #ffa0ff; margin: 2px; padding: 2px", (context.formatPhrase(RenderingContext.REND_SINCE_ADDED, context.getChangeVersion())));
108      spanInner.img("icon-change-add.png", "icon");
109      spanInner.tx(" "+context.formatPhrase(RenderingContext.REND_ADDED));
110      return divOuter;
111    case Changed:
112      divOuter = x.div("border: solid 1px #dddddd; margin: 2px; padding: 2px");
113      spanInner = divOuter.para().style("margin: 0").span("background-color: #fff2ff; border-left: solid 3px #ffa0ff; margin: 2px; padding: 2px", vca.getOriginal() == null ? context.formatPhrase(RenderingContext.REND_SINCE_CHANGED, context.getChangeVersion()) : context.formatPhrase(RenderingContext.REND_SINCE_CHANGED_WAS, context.getChangeVersion(),  vca.getOriginal()));
114      spanInner.img("icon-change-edit.png", "icon");
115      spanInner.tx(" "+context.formatPhrase(RenderingContext.REND_CHANGED));
116      return divOuter;
117    case Deleted:
118      divOuter = x.div("border: solid 1px #dddddd; margin: 2px; padding: 2px");
119      spanInner = divOuter.para().style("margin: 0").span("background-color: #fff2ff; border-left: solid 3px #ffa0ff; margin: 2px; padding: 2px", (context.formatPhrase(RenderingContext.GENERAL_REMOVED_SINCE, context.getChangeVersion())));
120      spanInner.img("icon-change-remove.png", "icon");
121      spanInner.tx(" "+context.formatPhrase(RenderingContext.REND_REMOVED));
122      return divOuter.strikethrough();
123    default:
124      return x;
125    }
126  }
127  
128
129  protected XhtmlNode renderStatusRow(Base b, XhtmlNode tbl, XhtmlNode tr) {
130    if (b == null || context.getChangeVersion() == null) {
131      return tr.td();
132    }
133    VersionComparisonAnnotation vca = (VersionComparisonAnnotation) b.getUserData(VersionComparisonAnnotation.USER_DATA_NAME);
134    if (vca == null) {
135      return tr.td();
136    }
137    switch (vca.getType()) {
138    case Added:
139      if (tbl.isClass("grid")) {
140        tr.style("border: solid 1px #dddddd; margin: 2px; padding: 2px");
141      }
142      XhtmlNode td = tr.td();
143      XhtmlNode span = td.span("background-color: #fff2ff; border-left: solid 3px #ffa0ff; margin: 2px; padding: 2px", (context.formatPhrase(RenderingContext.REND_ROW_SINCE, context.getChangeVersion())));
144      span.img("icon-change-add.png", "icon");
145      span.tx(" "+ context.formatPhrase(RenderingContext.REND_ADDED));
146      XhtmlNode x = new XhtmlNode(NodeType.Element, "holder");
147      x.span("background-color: #fff2ff; border-left: solid 3px #ffa0ff; margin: 2px; padding: 2px", context.formatPhrase(RenderingContext.REND_ROW_SINCE, context.getChangeVersion())).tx(" ");
148      tr.styleCells(x);
149      return td;
150    case Changed:
151      td = tr.td();
152      span = td.span("background-color: #fff2ff; border-left: solid 3px #ffa0ff; margin: 2px; padding: 2px", context.formatPhrase(RenderingContext.REND_ROW_CHANGED_SINCE_WAS, context.getChangeVersion(), vca.getOriginal()));
153      span.img("icon-change-edit.png", "icon");
154      span.tx(" "+ context.formatPhrase(RenderingContext.REND_CHANGED));
155      return td;
156    case Deleted:
157      tr.style("text-decoration: line-through");
158      td = tr.td();
159      span = td.span("background-color: #fff2ff; border-left: solid 3px #ffa0ff; margin: 2px; padding: 2px", context.formatPhrase(RenderingContext.GENERAL_REMOVED_SINCE, context.getChangeVersion()));
160      span.img("icon-change-remove.png", "icon");
161      span.tx(" "+ context.formatPhrase(RenderingContext.REND_REMOVED));
162      x = new XhtmlNode(NodeType.Element, "holder");
163      x.span("background-color: #fff2ff; border-left: solid 3px #ffa0ff; margin: 2px; padding: 2px; text-decoration: none", context.formatPhrase(RenderingContext.REND_ROW_SINCE, context.getChangeVersion())).tx(" ");
164      tr.styleCells(x);
165      return td;
166    default:
167      return tr.td();
168    }
169  }
170
171  public static void renderStatusSummary(RenderingContext context, Base base, XhtmlNode x, String version, String... metadataFields) {
172    if (base.hasUserData(VersionComparisonAnnotation.USER_DATA_NAME)) {
173      VersionComparisonAnnotation self = (VersionComparisonAnnotation) base.getUserData(VersionComparisonAnnotation.USER_DATA_NAME);
174      switch (self.getType()) {
175      case Added:
176        XhtmlNode spanInner = x.span("background-color: #fff2ff; border-left: solid 3px #ffa0ff; margin: 2px; padding: 2px", context.formatPhrase(RenderingContext.REND_SINCE_ADDED, version));
177        spanInner.img("icon-change-add.png", "icon");
178        spanInner.tx(" "+context.formatPhrase(RenderingContext.REND_ADDED));
179        return;
180      case Changed:
181        if (self.getComp().noChangeOtherThanMetadata(metadataFields)) {
182          x.span("color: #eeeeee").tx("n/c");
183          return;
184        } else {
185          spanInner = x.span("background-color: #fff2ff; border-left: solid 3px #ffa0ff; margin: 2px; padding: 2px",
186              self.getOriginal() != null ? context.formatPhrase(RenderingContext.REND_SINCE_CHANGED_WAS, version, self.getOriginal()) : context.formatPhrase(RenderingContext.REND_SINCE_CHANGED, version));
187          spanInner.img("icon-change-edit.png", "icon");
188          spanInner.tx(" "+context.formatPhrase(RenderingContext.REND_CHANGED));
189        }
190        return;
191      case Deleted:
192        spanInner = x.span("background-color: #fff2ff; border-left: solid 3px #ffa0ff; margin: 2px; padding: 2px", context.formatPhrase(RenderingContext.GENERAL_REMOVED_SINCE, version));
193        spanInner.img("icon-change-remove.png", "icon");
194        spanInner.tx(" "+context.formatPhrase(RenderingContext.REND_REMOVED));
195        return;
196      default:
197        x.span("color: #eeeeee").tx("n/c");
198        return;
199      }
200    } else {
201      x.span("color: #eeeeee").tx("--");
202    }
203  }
204
205
206  public String egt(@SuppressWarnings("rawtypes") Enumeration<? extends Enum> value) {
207    if (value == null || !value.hasPrimitiveValue()) {
208      return null;
209    } else {
210      return (value == null || !value.hasPrimitiveValue()) ? null : value.asStringValue();
211    }
212  }
213
214  public String toStr(int value) {
215    return Integer.toString(value);
216  }
217  
218  public String toStr(Date value) {
219    return value.toString();
220  }
221}