001package org.hl7.fhir.r5.renderers; 
002
003import java.io.IOException;
004import java.io.UnsupportedEncodingException;
005import java.util.ArrayList;
006import java.util.List;
007
008import javax.annotation.Nonnull;
009
010import org.hl7.fhir.exceptions.DefinitionException;
011import org.hl7.fhir.exceptions.FHIRException;
012import org.hl7.fhir.exceptions.FHIRFormatError;
013import org.hl7.fhir.r5.context.ContextUtilities;
014import org.hl7.fhir.r5.model.CanonicalResource;
015import org.hl7.fhir.r5.model.Resource;
016import org.hl7.fhir.r5.model.StructureDefinition;
017import org.hl7.fhir.r5.model.ValueSet;
018import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent;
019import org.hl7.fhir.r5.renderers.utils.RenderingContext;
020import org.hl7.fhir.r5.renderers.utils.RenderingContext.GenerationRules;
021import org.hl7.fhir.r5.renderers.utils.RenderingContext.KnownLinkType;
022import org.hl7.fhir.r5.renderers.utils.ResourceWrapper;
023import org.hl7.fhir.r5.terminologies.expansion.ValueSetExpansionOutcome;
024import org.hl7.fhir.r5.utils.EOperationOutcome;
025import org.hl7.fhir.r5.utils.ToolingExtensions;
026import org.hl7.fhir.utilities.MarkedToMoveToAdjunctPackage;
027import org.hl7.fhir.utilities.Utilities;
028import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator;
029import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.Cell;
030import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.Piece;
031import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.Row;
032import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.TableModel;
033import org.hl7.fhir.utilities.xhtml.NodeType;
034import org.hl7.fhir.utilities.xhtml.XhtmlNode; 
035
036@MarkedToMoveToAdjunctPackage
037public class QuestionnaireRenderer extends TerminologyRenderer { 
038
039  public QuestionnaireRenderer(RenderingContext context) { 
040    super(context); 
041  } 
042
043  @Override
044  public String buildSummary(ResourceWrapper r) throws UnsupportedEncodingException, IOException {
045    return canonicalTitle(r);
046  }
047
048  @Override
049  public void buildNarrative(RenderingStatus status, XhtmlNode x, ResourceWrapper q) throws FHIRFormatError, DefinitionException, IOException, FHIRException, EOperationOutcome {
050    renderResourceTechDetails(q, x);
051    genSummaryTable(status, x, (CanonicalResource) q.getResourceNative());
052    switch (context.getQuestionnaireMode()) { 
053    case FORM:
054      renderForm(status, x, q);
055      break;
056    case LINKS: 
057      renderLinks(status, x, q);
058      break;
059    case LOGIC: 
060      renderLogic(status, x, q);
061      break;
062    case DEFNS: 
063      renderDefns(status, x, q);
064      break;
065    case TREE:  
066      renderTree(status, x, q);
067      break;
068    default: 
069      throw new Error("Unknown questionnaire Renderer Mode"); 
070    } 
071
072    boolean first = true;
073    for (ResourceWrapper cont : q.children("contained")) {
074      if (first) {
075        x.h2().tx("Contained Resources");
076        first = false;
077      }
078      x.hr();
079      RendererFactory.factory(cont, context.forContained()).setInner(true).buildNarrative(status, x, cont);
080    }
081  } 
082
083  public void renderTree(RenderingStatus status, XhtmlNode x, ResourceWrapper q) throws UnsupportedEncodingException, IOException { 
084    boolean hasFlags = checkForFlags(q.children("item")); 
085    boolean doOpts = context.getDefinitionsTarget() == null && hasAnyOptions(q.children("item"));  
086
087    if (doOpts) { 
088      x.b().tx(context.formatPhrase(RenderingContext.QUEST_STRUCT)); 
089    } 
090    HierarchicalTableGenerator gen = new HierarchicalTableGenerator(context, context.getDestDir(), context.isInlineGraphics(), true, ""); 
091    TableModel model = gen.new TableModel("qtree="+q.getId(), context.getRules() == GenerationRules.IG_PUBLISHER);     
092    model.setAlternating(true); 
093    if (context.getRules() == GenerationRules.VALID_RESOURCE || context.isInlineGraphics()) { 
094      model.setDocoImg(HierarchicalTableGenerator.help16AsData());     
095    } else { 
096      model.setDocoImg(Utilities.pathURL(context.getLink(KnownLinkType.SPEC), "help16.png")); 
097    } 
098    model.setDocoRef(context.getLink(KnownLinkType.SPEC)+"formats.html#table"); 
099    model.getTitles().add(gen.new Title(null, model.getDocoRef(), (context.formatPhrase(RenderingContext.QUEST_LINKID)), (context.formatPhrase(RenderingContext.QUEST_LINK)), null, 0)); 
100    model.getTitles().add(gen.new Title(null, model.getDocoRef(), (context.formatPhrase(RenderingContext.QUEST_TEXT)), (context.formatPhrase(RenderingContext.QUEST_TEXTFOR)), null, 0)); 
101    model.getTitles().add(gen.new Title(null, model.getDocoRef(), (context.formatPhrase(RenderingContext.GENERAL_CARDINALITY)), (context.formatPhrase(RenderingContext.QUEST_TIMES)), null, 0)); 
102    model.getTitles().add(gen.new Title(null, model.getDocoRef(), (context.formatPhrase(RenderingContext.GENERAL_TYPE)), (context.formatPhrase(RenderingContext.QUEST_TYPE_ITEM)), null, 0)); 
103    if (hasFlags) { 
104      model.getTitles().add(gen.new Title(null, model.getDocoRef(), (context.formatPhrase(RenderingContext.GENERAL_FLAGS)), (context.formatPhrase(RenderingContext.QUEST_ATTRIBUTES)), null, 0)); 
105    } 
106    model.getTitles().add(gen.new Title(null, model.getDocoRef(), (context.formatPhrase(RenderingContext.GENERAL_DESC_CONST)), (context.formatPhrase(RenderingContext.QUEST_ADD_INFO)), null, 0)); 
107 
108    // first we add a root for the questionaire itself 
109    Row row = addTreeRoot(gen, model.getRows(), q, hasFlags); 
110    for (ResourceWrapper i : q.children("item")) { 
111      renderTreeItem(status, gen, row.getSubRows(), q, i, hasFlags); 
112    } 
113    XhtmlNode xn = gen.generate(model, context.getLocalPrefix(), 1, null); 
114    x.addChildNode(xn); 
115    if (doOpts) { 
116      renderOptions(q, x); 
117    } 
118  } 
119
120  private void renderOptions(ResourceWrapper q, XhtmlNode x) { 
121    if (hasAnyOptions(q.children("item"))) { 
122      x.hr(); 
123      x.para().b().tx(context.formatPhrase(RenderingContext.QUEST_OPT)); 
124      renderOptions(q.children("item"), x); 
125    }     
126  } 
127
128  private void renderOptions(List<ResourceWrapper> items, XhtmlNode x) {     
129    for (ResourceWrapper i : items) { 
130      renderItemOptionsList(x, i); 
131      renderOptions(i.children("item"), x); 
132    }     
133  } 
134
135  public void renderItemOptions(XhtmlNode x, ResourceWrapper i) { 
136    if (i.has("answerOption")) { 
137      for (ResourceWrapper opt : i.children("answerOption")) { 
138        String value = "??";
139        String text = "??";
140        ResourceWrapper v = opt.child("value");
141        if (v.isPrimitive()) {
142          value = v.primitiveValue();
143          text = v.primitiveValue();
144        } else if (v.fhirType().equals("Coding")) {
145          if (v.has("system")) {
146            value = v.primitiveValue("system")+"#"+v.primitiveValue("code");
147          } else {
148            value = v.primitiveValue("code");
149          }
150          if (v.has("display")) { 
151            text = v.primitiveValue("display");
152          } else {
153            text = v.primitiveValue("code");
154          }
155        }
156        if (value == null) {
157          value = "??";
158        }
159        if (text == null) {
160          text = "??";
161        }
162        boolean selected = "true".equals(opt.primitiveValue("initialSelected"));
163        x.option(value, text, selected);
164      } 
165    } 
166  }  
167  
168  public void renderItemOptionsList(XhtmlNode x, ResourceWrapper i) { 
169    if (i.has("answerOption")) { 
170      x.an(context.prefixAnchor("opt-item."+i.primitiveValue("linkId"))); 
171      x.para().b().tx(context.formatPhrase(RenderingContext.QUEST_ANSW, i.primitiveValue("linkId"))+" "); 
172      XhtmlNode ul = x.ul(); 
173      for (ResourceWrapper opt : i.children("answerOption")) { 
174        XhtmlNode li = ul.li(); 
175        li.style("font-size: 11px"); 
176        ResourceWrapper v = opt.child("value");
177        if (v.isPrimitive()) { 
178          li.tx(v.primitiveValue()); 
179        } else if (v.fhirType().equals("Coding")) { 
180          String link = v.has("system") ? new ContextUtilities(context.getWorker()).getLinkForUrl(context.getLink(KnownLinkType.SPEC), v.primitiveValue("system")) : null; 
181          if (link == null) { 
182            li.tx(v.primitiveValue("system")+"#"+v.primitiveValue("code")); 
183          } else { 
184            li.ah(link).tx(displaySystem(v.primitiveValue("system"))); 
185            li.tx(": "+v.primitiveValue("code"));               
186          } 
187          if (v.has("display")) { 
188            li.tx(" (\""+v.primitiveValue("display")+"\")");               
189          } 
190        } else { 
191          li.tx("??");             
192        } 
193      } 
194    } 
195  } 
196
197  private boolean hasAnyOptions(List<ResourceWrapper> items) { 
198    for (ResourceWrapper i : items) { 
199      if (i.has("answerOption")) { 
200        return true; 
201      } 
202      if (hasAnyOptions(i.children("item"))) { 
203        return true; 
204      } 
205    } 
206    return false; 
207  } 
208
209  private boolean checkForFlags(List<ResourceWrapper> items) { 
210    for (ResourceWrapper i : items) { 
211      if (checkForFlags(i)) { 
212        return true; 
213      } 
214    } 
215    return false; 
216  } 
217
218  private boolean checkForFlags(ResourceWrapper i) { 
219    if (i.has("readOnly")) { 
220      return true; 
221    } 
222    if ("true".equals(i.extensionString(ToolingExtensions.EXT_Q_IS_SUBJ))) { 
223      return true; 
224    } 
225    if ("true".equals(i.extensionString(ToolingExtensions.EXT_Q_HIDDEN))) { 
226      return true; 
227    } 
228    if ("true".equals(i.extensionString(ToolingExtensions.EXT_Q_OTP_DISP))) { 
229      return true; 
230    } 
231    if (i.hasExtension(ToolingExtensions.EXT_O_LINK_PERIOD)) { 
232      return true; 
233    } 
234    if (i.hasExtension(ToolingExtensions.EXT_Q_CHOICE_ORIENT)) { 
235      return true; 
236    } 
237    if (i.hasExtension(ToolingExtensions.EXT_Q_DISPLAY_CAT)) { 
238      return true; 
239    } 
240    return checkForFlags(i.children("item")); 
241  } 
242
243
244
245  private Row addTreeRoot(HierarchicalTableGenerator gen, List<Row> rows, ResourceWrapper q, boolean hasFlags) throws IOException { 
246    Row r = gen.new Row(); 
247    rows.add(r); 
248
249    r.setIcon("icon_q_root.gif", context.formatPhrase(RenderingContext.QUEST_ROOT)); 
250    r.getCells().add(gen.new Cell(null, null, q.primitiveValue("name"), null, null)); 
251    r.getCells().add(gen.new Cell(null, null, q.primitiveValue("description"), null, null)); 
252    r.getCells().add(gen.new Cell(null, null, "", null, null)); 
253    r.getCells().add(gen.new Cell(null, null, context.formatPhrase(RenderingContext.QUEST_QUEST), null, null)); 
254    if (hasFlags) { 
255      r.getCells().add(gen.new Cell(null, null, "", null, null)); 
256    } 
257    r.getCells().add(gen.new Cell(null, null, q.has("url") ? q.has("version") ? q.primitiveValue("url")+"#"+q.primitiveValue("version") : q.primitiveValue("url") : "", null, null)); 
258    return r;     
259  } 
260
261  private String getSpecLink(String path) { 
262    return Utilities.pathURL(context.getLink(KnownLinkType.SPEC), path); 
263  } 
264
265  private String getSDCLink(String url, String path) { 
266    StructureDefinition sd = context.getContext().fetchResource(StructureDefinition.class, url); 
267    if (sd == null) { 
268      sd = context.getContext().fetchResource(StructureDefinition.class, path); 
269    } 
270    if (sd != null && sd.hasWebPath()) { 
271      return sd.getWebPath(); 
272    } else if (Utilities.isAbsoluteUrl(path)) { 
273      return path.replace("StructureDefinition/", "StructureDefinition-")+".html"; 
274    } else if ("http://hl7.org/fhir/uv/sdc".equals(context.getPkp().getCanonicalForDefaultContext())) {
275      return Utilities.pathURL(path); // for now? 
276    } else {
277      return Utilities.pathURL("http://hl7.org/fhir/uv/sdc", path); // for now? 
278    } 
279  } 
280
281  private void renderTreeItem(RenderingStatus status, HierarchicalTableGenerator gen, List<Row> rows, ResourceWrapper q, ResourceWrapper i, boolean hasFlags) throws IOException { 
282    Row r = gen.new Row(); 
283    rows.add(r); 
284    String type = i.primitiveValue("type");
285
286    r.setIcon("icon-q-"+type.toLowerCase()+".png", type); 
287    Cell c1 = gen.new Cell(null, context.getDefinitionsTarget() == null ? "" : context.getDefinitionsTarget()+"#item."+i.primitiveValue("linkId"), i.primitiveValue("linkId"), null, null); 
288    c1.setId("item."+i.primitiveValue("linkId")); 
289    r.getCells().add(c1); 
290    String txt = (i.has("prefix") ? i.primitiveValue("prefix") + ". " : "") + i.primitiveValue("text"); 
291    r.getCells().add(gen.new Cell(null, null, txt, null, null)); 
292    r.getCells().add(gen.new Cell(null, null, ("true".equals(i.primitiveValue("required")) ? "1" : "0")+".."+("true".equals(i.primitiveValue("repeats")) ? "*" : "1"), null, null)); 
293    if (i.child("type").hasExtension(ToolingExtensions.EXT_QUESTIONNAIRE_ITEM_TYPE_ORIGINAL)) { 
294      status.setExtensions(true);
295      String t = i.child("type").extensionString(ToolingExtensions.EXT_QUESTIONNAIRE_ITEM_TYPE_ORIGINAL); 
296      r.getCells().add(gen.new Cell(null, context.getLink(KnownLinkType.SPEC)+"codesystem-item-type.html#item-type-"+t, t, null, null)); 
297    } else { 
298      r.getCells().add(gen.new Cell(null, context.getLink(KnownLinkType.SPEC)+"codesystem-item-type.html#item-type-"+type, type, null, null)); 
299    } 
300
301    if (hasFlags) { 
302      // flags: 
303      Cell flags = gen.new Cell(); 
304      r.getCells().add(flags); 
305      if ("true".equals(i.primitiveValue("readOnly"))) { 
306        flags.addPiece(gen.new Piece(Utilities.pathURL(context.getLink(KnownLinkType.SPEC), "questionnaire-definitions.html#Questionnaire.item.readOnly"), null, context.formatPhrase(RenderingContext.QUEST_READONLY)).addHtml(new XhtmlNode(NodeType.Element, "img").attribute("alt", "icon").attribute("src", getImgPath("icon-qi-readonly.png")))); 
307      } 
308      if ("true".equals(i.extensionString("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-isSubject"))) { 
309        status.setExtensions(true);
310        flags.addPiece(gen.new Piece(getSDCLink("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-isSubject", "StructureDefinition-sdc-questionnaire-isSubject.html"), null, context.formatPhrase(RenderingContext.QUEST_SUBJECT)).addHtml(new XhtmlNode(NodeType.Element, "img").attribute("alt", "icon").attribute("src", getImgPath("icon-qi-subject.png")))); 
311      } 
312      if ("true".equals(i.extensionString(ToolingExtensions.EXT_Q_HIDDEN))) { 
313        status.setExtensions(true);
314        flags.addPiece(gen.new Piece(getSpecLink("extension-questionnaire-hidden.html"), null, context.formatPhrase(RenderingContext.QUEST_HIDDEN)).addHtml(new XhtmlNode(NodeType.Element, "img").attribute("alt", "icon").attribute("src", getImgPath("icon-qi-hidden.png")))); 
315      } 
316      if ("true".equals(i.extensionString(ToolingExtensions.EXT_Q_OTP_DISP))) { 
317        status.setExtensions(true);
318        flags.addPiece(gen.new Piece(getSDCLink("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-optionalDisplay", "StructureDefinition-sdc-questionnaire-optionalDisplay.html"), null, context.formatPhrase(RenderingContext.QUEST_DISPLAY)).addHtml(new XhtmlNode(NodeType.Element, "img").attribute("alt", "icon").attribute("src", getImgPath("icon-qi-optional.png")))); 
319      } 
320      if (i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-observationLinkPeriod")) { 
321        status.setExtensions(true);
322        flags.addPiece(gen.new Piece(getSDCLink("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-observationLinkPeriod", "StructureDefinition-sdc-questionnaire-observationLinkPeriod.html"), null, context.formatPhrase(RenderingContext.QUEST_LINKED)).addHtml(new XhtmlNode(NodeType.Element, "img").attribute("alt", "icon").attribute("src", getImgPath("icon-qi-observation.png")))); 
323      } 
324      if (i.hasExtension(ToolingExtensions.EXT_Q_CHOICE_ORIENT)) { 
325        status.setExtensions(true);
326        String code = i.extensionString(ToolingExtensions.EXT_Q_CHOICE_ORIENT); 
327        flags.addPiece(gen.new Piece(getSpecLink("extension-questionnaire-choiceorientation.html"), null, context.formatPhrase(RenderingContext.QUEST_ORIENTATION, code)+" ").addHtml(new XhtmlNode(NodeType.Element, "img").attribute("alt", "icon").attribute("src", getImgPath("icon-qi-" + code + ".png")))); 
328      } 
329      if (i.hasExtension(ToolingExtensions.EXT_Q_DISPLAY_CAT)) { 
330        status.setExtensions(true);
331        ResourceWrapper cc = i.extensionValue(ToolingExtensions.EXT_Q_DISPLAY_CAT); 
332        String code = getCodeFromCC(cc, "http://hl7.org/fhir/questionnaire-display-category"); 
333        flags.addPiece(gen.new Piece("https://hl7.org/fhir/R4/extension-questionnaire-displayCategory.html", null, context.formatPhrase(RenderingContext.QUEST_CAT, code)+" ").addHtml(new XhtmlNode(NodeType.Element, "img").attribute("alt", "icon").attribute("src", getImgPath("icon-qi-" + code + ".png")))); 
334      } 
335    }     
336    Cell defn = gen.new Cell(); 
337    r.getCells().add(defn); 
338
339    if (i.has("maxLength")) { 
340      defn.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.GENERAL_MAX_LENGTH)+" "), null)); 
341      defn.getPieces().add(gen.new Piece(null, i.primitiveValue("maxLength"), null)); 
342    } 
343    if (i.has("definition")) { 
344      if (!defn.getPieces().isEmpty()) defn.addPiece(gen.new Piece("br")); 
345      defn.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.GENERAL_DEFINITION_COLON)+" "), null)); 
346      genDefinitionLink(gen, i, defn, q);       
347    } 
348    if (i.has("enableWhen")) { 
349      if (!defn.getPieces().isEmpty()) defn.addPiece(gen.new Piece("br")); 
350      Piece p = gen.new Piece(null, (context.formatPhrase(RenderingContext.QUEST_ENABLE)+" "), null); 
351      defn.getPieces().add(p); 
352      if (i.children("enableWhen").size() == 1) { 
353        XhtmlNode x = new XhtmlNode(NodeType.Element, "span"); 
354        p.getChildren().add(x); 
355        renderEnableWhen(x, i.firstChild("enableWhen"));         
356      } else { 
357        XhtmlNode x = new XhtmlNode(NodeType.Element, "ul"); 
358        p.getChildren().add(x); 
359        for (ResourceWrapper qi : i.children("enableWhen")) { 
360          renderEnableWhen(x.li(), qi); 
361        } 
362      } 
363    } 
364    if (i.has("answerValueSet")) { 
365      if (!defn.getPieces().isEmpty()) defn.addPiece(gen.new Piece("br")); 
366      defn.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.QUEST_VALUE)+" "), null)); 
367      if (i.hasPrimitiveValue("answerValueSet") && i.primitiveValue("answerValueSet").startsWith("#")) { 
368        ResourceWrapper vs = q.getContained(i.primitiveValue("answerValueSet").substring(1)); 
369        if (vs == null) { 
370          defn.getPieces().add(gen.new Piece(null, i.primitiveValue("answerValueSet"), null));                     
371        } else { 
372          defn.getPieces().add(gen.new Piece(vs.getWebPath(), RendererFactory.factory(vs, context.forContained()).buildSummary(vs), null));                               
373        } 
374      } else { 
375        ValueSet vs = context.getWorker().findTxResource(ValueSet.class, i.primitiveValue("answerValueSet")); 
376        if (vs == null  || !vs.hasWebPath()) { 
377          defn.getPieces().add(gen.new Piece(null, i.primitiveValue("answerValueSet"), null));                     
378        } else { 
379          defn.getPieces().add(gen.new Piece(vs.getWebPath(), vs.present(), null));                     
380        }              
381      } 
382    } 
383    if (i.has("answerOption")) { 
384      if (!defn.getPieces().isEmpty()) defn.addPiece(gen.new Piece("br")); 
385      defn.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.QUEST_OPTIONS)+" "), null)); 
386      if (context.getDefinitionsTarget() == null) { 
387        // if we don't have a definitions target, we'll add them below.  
388        defn.getPieces().add(gen.new Piece("#"+context.prefixAnchor("opt-item."+i.primitiveValue("linkId")), Integer.toString(i.children("answerOption").size())+" "+Utilities.pluralize("option", i.children("answerOption").size()), null)); 
389      } else { 
390        defn.getPieces().add(gen.new Piece(context.getDefinitionsTarget()+"#item."+i.primitiveValue("linkId"), Integer.toString(i.children("answerOption").size())+" "+Utilities.pluralize("option", i.children("answerOption").size()), null)); 
391      } 
392    } 
393    if (i.has("initial")) { 
394      for (ResourceWrapper v : i.children("initial")) { 
395        ResourceWrapper vv = v.child("value");
396        if (!defn.getPieces().isEmpty()) defn.addPiece(gen.new Piece("br")); 
397        defn.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.QUEST_INITIAL)+" "), null)); 
398        defn.getPieces().add(gen.new Piece(null, vv.fhirType(), null)); 
399        defn.getPieces().add(gen.new Piece(null, " = ", null));
400        if (vv.isPrimitive()) { 
401          defn.getPieces().add(gen.new Piece(null, vv.primitiveValue(), null)); 
402        } else if (vv.fhirType().equals("Coding")) { 
403          renderCoding(gen, defn.getPieces(), vv);           
404        } else if (vv.fhirType().equals("Quantity")) { 
405          renderQuantity(gen, defn.getPieces(), vv, false);         
406        } else if (vv.fhirType().equals("Reference")) { 
407          renderReference(q, gen, defn.getPieces(), vv, true);        
408        } else if (vv.fhirType().equals("Attachment")) { 
409          // renderAttachment(gen, defn.getPieces(), vv);           
410        } 
411      } 
412    } 
413    // still todo 
414
415    // 
416    //http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-choiceColumn 
417    // 
418    //http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-width 
419    //http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-observationLinkPeriod 
420    //http://hl7.org/fhir/StructureDefinition/Questionnaire-itemControl 
421    //http://hl7.org/fhir/StructureDefinition/Questionnaire-sliderStepValue 
422
423    if (i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-enableWhenExpression") || i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-itemContext") || i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-calculatedExpression") || i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-contextExpression") || i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-candidateExpression") || i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-initialExpression")) { 
424      if (!defn.getPieces().isEmpty()) defn.addPiece(gen.new Piece("br")); 
425      defn.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.QUEST_EXP)+" "), null)); 
426      Piece p = gen.new Piece("ul"); 
427      defn.getPieces().add(p); 
428      for (ResourceWrapper e : i.extensions("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-initialExpression")) { 
429        addExpression(p, e.child("value"), context.formatPhrase(RenderingContext.QUEST_INT), "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-initialExpression"); 
430      } 
431      for (ResourceWrapper e : i.extensions("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-contextExpression")) { 
432        addExpression(p, e.child("value"), context.formatPhrase(RenderingContext.QUEST_CONT), "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-contextExpression"); 
433      } 
434      for (ResourceWrapper e : i.extensions("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-itemContext")) { 
435        addExpression(p, e.child("value"), context.formatPhrase(RenderingContext.QUEST_ITEM_CONT), "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-itemContext"); 
436      } 
437      for (ResourceWrapper e : i.extensions("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-enableWhenExpression")) { 
438        addExpression(p, e.child("value"), context.formatPhrase(RenderingContext.QUEST_EN), "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-enableWhenExpression"); 
439      } 
440      for (ResourceWrapper e : i.extensions("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-calculatedExpression")) { 
441        addExpression(p, e.child("value"), context.formatPhrase(RenderingContext.QUEST_CALC), "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-calculatedExpression"); 
442      } 
443      for (ResourceWrapper e : i.extensions("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-candidateExpression")) { 
444        addExpression(p, e.child("value"), context.formatPhrase(RenderingContext.QUEST_CAND), "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-candidateExpression"); 
445      }  
446    } 
447
448    for (ResourceWrapper c : i.children("item")) { 
449      renderTreeItem(status, gen, r.getSubRows(), q, c, hasFlags); 
450    }      
451  } 
452
453  private String getCodeFromCC(ResourceWrapper cc, String system) {
454    for (ResourceWrapper coding : cc.children("coding")) {
455      if (system.equals(coding.primitiveValue("system"))) {
456        return coding.primitiveValue("code");
457      }      
458    }
459    return null;
460    
461  }
462
463  public void genDefinitionLink(HierarchicalTableGenerator gen, ResourceWrapper i, Cell defn, ResourceWrapper q) { 
464    // can we resolve the definition?  
465    String path = null; 
466    String d = i.primitiveValue("definition"); 
467    if (d.contains("#")) { 
468      path = d.substring(d.indexOf("#")+1); 
469      d = d.substring(0, d.indexOf("#")); 
470    } 
471    StructureDefinition sd = context.getWorker().fetchResource(StructureDefinition.class, d, q.getResourceNative()); 
472    if (sd != null) { 
473      String url = sd.getWebPath(); 
474      if (url != null) { 
475        defn.getPieces().add(gen.new Piece(url+"#"+path, path, null));           
476      } else { 
477        defn.getPieces().add(gen.new Piece(null, i.primitiveValue("definition"), null)); 
478      } 
479    } else { 
480      defn.getPieces().add(gen.new Piece(null, i.primitiveValue("definition"), null)); 
481    } 
482  } 
483
484  public void genDefinitionLink(XhtmlNode x, ResourceWrapper i, ResourceWrapper q) { 
485    // can we resolve the definition?  
486    String path = null; 
487    String d = i.primitiveValue("definition"); 
488    if (d.contains("#")) { 
489      path = d.substring(d.indexOf("#")+1); 
490      d = d.substring(0, d.indexOf("#")); 
491    } 
492    StructureDefinition sd = context.getWorker().fetchResource(StructureDefinition.class, d, q.getResourceNative()); 
493    if (sd != null) { 
494      String url = sd.getWebPath(); 
495      if (url != null) { 
496        x.ah(url+"#"+path).tx(path);           
497      } else { 
498        x.tx(i.primitiveValue("definition")); 
499      } 
500    } else { 
501      x.tx(i.primitiveValue("definition")); 
502    } 
503  } 
504
505  private void addExpression(Piece p, ResourceWrapper exp, String label, String url) { 
506    XhtmlNode x = new XhtmlNode(NodeType.Element, "li").style("font-size: 11px"); 
507    p.addHtml(x); 
508    CanonicalResource cr = (CanonicalResource) context.getContext().fetchResource(Resource.class, url); 
509    if (cr != null && cr.hasWebPath()) { 
510      x.ah(cr.getWebPath()).tx(label); 
511    } else { 
512      x.ah(url).tx(label); 
513    } 
514    x.tx(": "); 
515    x.code(exp.primitiveValue("expression")); 
516  } 
517
518  private void renderLogic(RenderingStatus status, XhtmlNode x, ResourceWrapper q) throws FHIRException, IOException { 
519    HierarchicalTableGenerator gen = new HierarchicalTableGenerator(context, context.getDestDir(), context.isInlineGraphics(), true, ""); 
520    TableModel model = gen.new TableModel("qtree="+q.getId(), true);     
521    model.setAlternating(true); 
522    if (context.getRules() == GenerationRules.VALID_RESOURCE || context.isInlineGraphics()) { 
523      model.setDocoImg(HierarchicalTableGenerator.help16AsData());     
524    } else { 
525      model.setDocoImg(Utilities.pathURL(context.getLink(KnownLinkType.SPEC), "help16.png")); 
526    } 
527    model.setDocoRef(context.getLink(KnownLinkType.SPEC)+"formats.html#table"); 
528    model.getTitles().add(gen.new Title(null, model.getDocoRef(), context.formatPhrase(RenderingContext.QUEST_LINKID), context.formatPhrase(RenderingContext.QUEST_LINK), null, 0)); 
529    model.getTitles().add(gen.new Title(null, model.getDocoRef(), context.formatPhrase(RenderingContext.GENERAL_DESC_CONST), context.formatPhrase(RenderingContext.QUEST_ADD_INFO), null, 0)); 
530
531    if (!q.has("item")) { 
532      gen.emptyRow(model, 2); 
533    } else { 
534      for (ResourceWrapper i : q.children("item")) { 
535        renderLogicItem(status, gen, model.getRows(), q, i); 
536      } 
537    } 
538    XhtmlNode xn = gen.generate(model, context.getLocalPrefix(), 1, null); 
539    x.addChildNode(xn); 
540  } 
541
542  private void renderLogicItem(RenderingStatus status, HierarchicalTableGenerator gen, List<Row> rows, ResourceWrapper q, ResourceWrapper i) throws IOException { 
543    Row r = gen.new Row(); 
544    rows.add(r); 
545    String type = i.primitiveValue("type");
546
547    r.setIcon("icon-q-"+type.toLowerCase()+".png", type); 
548    r.getCells().add(gen.new Cell(null, context.getDefinitionsTarget() == null ? "" : context.getDefinitionsTarget()+"#item."+i.primitiveValue("linkId"), i.primitiveValue("linkId"), null, null)); 
549    Cell defn = gen.new Cell(); 
550    r.getCells().add(defn); 
551
552    if (i.has("maxLength")) { 
553      defn.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.GENERAL_MAX_LENGTH)+" "), null)); 
554      defn.getPieces().add(gen.new Piece(null, i.primitiveValue("maxLength"), null)); 
555    } 
556    if (i.has("definition")) { 
557      if (!defn.getPieces().isEmpty()) defn.addPiece(gen.new Piece("br")); 
558      defn.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.GENERAL_DEFINITION_COLON)+" "), null)); 
559      genDefinitionLink(gen, i, defn, q);             
560    } 
561    if (i.has("enableWhen")) { 
562      if (!defn.getPieces().isEmpty()) defn.addPiece(gen.new Piece("br")); 
563      defn.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.QUEST_ENABLE)+" "), null)); 
564      defn.getPieces().add(gen.new Piece(null, context.formatPhrase(RenderingContext.GENERAL_TODO), null));       
565    } 
566    if (i.has("answerValueSet")) { 
567      if (!defn.getPieces().isEmpty()) defn.addPiece(gen.new Piece("br")); 
568      defn.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.QUEST_VALUE)+" "), null)); 
569      if (Utilities.noString(i.primitiveValue("answerValueSet")) && i.primitiveValue("answerValueSet").startsWith("#")) {
570        ResourceWrapper vs = q.getContained(i.primitiveValue("answerValueSet").substring(1)); 
571        if (vs == null) { 
572          defn.getPieces().add(gen.new Piece(null, i.primitiveValue("answerValueSet"), null));                     
573        } else { 
574          defn.getPieces().add(gen.new Piece(vs.getWebPath(), RendererFactory.factory(vs, context.forContained()).buildSummary(vs), null));                               
575        } 
576      } else { 
577        ValueSet vs = context.getWorker().findTxResource(ValueSet.class, i.primitiveValue("answerValueSet"), q.getResourceNative()); 
578        if (vs == null  || !vs.hasWebPath()) { 
579          defn.getPieces().add(gen.new Piece(null, i.primitiveValue("answerValueSet"), null));                     
580        } else { 
581          defn.getPieces().add(gen.new Piece(vs.getWebPath(), vs.present(), null));                     
582        }              
583      } 
584    } 
585    if (i.has("answerOption")) { 
586      if (!defn.getPieces().isEmpty()) defn.addPiece(gen.new Piece("br")); 
587      defn.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.QUEST_OPTIONS)+" "), null)); 
588      defn.getPieces().add(gen.new Piece(context.getDefinitionsTarget()+"#item."+i.primitiveValue("linkId"), Integer.toString(i.children("answerOption").size())+" "+Utilities.pluralize("option", i.children("answerOption").size()), null));             
589    } 
590    if (i.has("initial")) { 
591      for (ResourceWrapper v : i.children("initial")) { 
592        if (!defn.getPieces().isEmpty()) defn.addPiece(gen.new Piece("br"));
593        ResourceWrapper vv = v.child("value"); 
594        defn.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.QUEST_INITIAL)+" "), null)); 
595        defn.getPieces().add(gen.new Piece(null, vv.fhirType(), null)); 
596        defn.getPieces().add(gen.new Piece(null, " = ", null)); 
597        if (vv.isPrimitive()) { 
598          defn.getPieces().add(gen.new Piece(null, vv.primitiveValue(), null)); 
599        } else if (vv.fhirType().equals("Coding")) { 
600          renderCoding(gen, defn.getPieces(), vv);        
601        } else if (vv.fhirType().equals("Coding")) { 
602          renderQuantity(gen, defn.getPieces(), vv, false); 
603        } else if (vv.fhirType().equals("Coding")) { 
604          renderReference(q, gen, defn.getPieces(), vv, false);           
605          //        } else if (v.hasValueAttachment()) { 
606          //          renderAttachment(gen, defn.getPieces(), v.getValueAttachment());           
607        } 
608      } 
609    } 
610    // still todo 
611
612    // 
613    //http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-choiceColumn 
614    // 
615    //http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-width 
616    //http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-observationLinkPeriod 
617    //http://hl7.org/fhir/StructureDefinition/Questionnaire-itemControl 
618    //http://hl7.org/fhir/StructureDefinition/Questionnaire-sliderStepValue 
619
620    if (i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-enableWhenExpression") || i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-itemContext") || i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-calculatedExpression") || i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-contextExpression") || i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-candidateExpression") || i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-initialExpression")) { 
621      if (!defn.getPieces().isEmpty()) defn.addPiece(gen.new Piece("br")); 
622      defn.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.QUEST_EXP)+" "), null)); 
623      Piece p = gen.new Piece("ul"); 
624      defn.getPieces().add(p); 
625      for (ResourceWrapper e : i.extensions("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-initialExpression")) { 
626        addExpression(p, e.child("value"), context.formatPhrase(RenderingContext.QUEST_INT), "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-initialExpression"); 
627      } 
628      for (ResourceWrapper e : i.extensions("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-contextExpression")) { 
629        addExpression(p, e.child("value"), context.formatPhrase(RenderingContext.QUEST_CONT), "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-contextExpression"); 
630      } 
631      for (ResourceWrapper e : i.extensions("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-itemContext")) { 
632        addExpression(p, e.child("value"), context.formatPhrase(RenderingContext.QUEST_ITEM_CONT), "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-itemContext"); 
633      } 
634      for (ResourceWrapper e : i.extensions("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-enableWhenExpression")) { 
635        addExpression(p, e.child("value"), context.formatPhrase(RenderingContext.QUEST_EN), "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-enableWhenExpression"); 
636      } 
637      for (ResourceWrapper e : i.extensions("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-calculatedExpression")) { 
638        addExpression(p, e.child("value"), context.formatPhrase(RenderingContext.QUEST_CALC), "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-calculatedExpression"); 
639      } 
640      for (ResourceWrapper e : i.extensions("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-candidateExpression")) { 
641        addExpression(p, e.child("value"), context.formatPhrase(RenderingContext.QUEST_CAND), "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-candidateExpression"); 
642      }  
643    } 
644
645    for (ResourceWrapper c : i.children("item")) { 
646      renderLogicItem(status, gen, r.getSubRows(), q, c); 
647    }  
648
649  } 
650
651
652  public void renderForm(RenderingStatus status, XhtmlNode x, ResourceWrapper q) throws UnsupportedEncodingException, IOException {
653    XhtmlNode d = x.div(); 
654    boolean hasPrefix = false; 
655    for (ResourceWrapper c : q.children("item")) { 
656      hasPrefix = hasPrefix || doesItemHavePrefix(c); 
657    } 
658    int i = 1; 
659    for (ResourceWrapper c : q.children("item")) { 
660      renderFormItem(status, d, q, c, hasPrefix ? null : Integer.toString(i), 0); 
661      i++; 
662    }   
663  } 
664
665  private boolean doesItemHavePrefix(ResourceWrapper i) { 
666    if (i.has("prefix")) { 
667      return true; 
668    } 
669    for (ResourceWrapper c : i.children("item")) { 
670      if (doesItemHavePrefix(c)) { 
671        return true; 
672      } 
673    } 
674    return false; 
675  } 
676
677  private void renderFormItem(RenderingStatus status, XhtmlNode x, ResourceWrapper q, ResourceWrapper i, String pfx, int indent) throws IOException { 
678    boolean hasExt = false; 
679    XhtmlNode d = x.div().style("width: "+Integer.toString(900-indent*10)+"px; border-top: 1px #eeeeee solid"); 
680    if (indent > 0) { 
681      d.style("margin-left: "+Integer.toString(10*indent)+"px"); 
682    } 
683    XhtmlNode display = d.div().style("display: inline-block; width: "+Integer.toString(500-indent*10)+"px"); 
684    XhtmlNode details = d.div().style("border: 1px #ccccff solid; padding: 2px; display: inline-block; background-color: #fefce7; width: 380px"); 
685    XhtmlNode p = display.para(); 
686
687    String type = i.primitiveValue("type");
688    String typeT = getTranslatedCode(i.child("type"));
689    if ("group".equals(type)) { 
690      p = p.b(); 
691    } 
692    if (i.has("prefix")) { 
693      p.tx(i.primitiveValue("prefix")); 
694      p.tx(": "); 
695    } 
696    p.span(null, "linkId: "+i.primitiveValue("linkId")).tx(i.primitiveValue("text")); 
697    if ("true".equals(i.primitiveValue("required"))) { 
698      p.span("color: red", context.formatPhrase(RenderingContext.QUEST_MAND)).tx("*"); 
699    } 
700
701    XhtmlNode input = null; 
702    switch (type) { 
703    case "string": 
704      p.tx(" "); 
705      input = p.input(i.primitiveValue("linkId"), "text", typeT, 60); 
706      break; 
707    case "attachment": 
708      break; 
709    case "boolean": 
710      p.tx(" "); 
711      input = p.input(i.primitiveValue("linkId"), "checkbox", typeT, 1); 
712      break; 
713    case "coding": 
714      input = p.select(i.primitiveValue("linkId")); 
715      listOptions(q, i, input); 
716      break; 
717    case "date": 
718      p.tx(" "); 
719      input = p.input(i.primitiveValue("linkId"), "date", typeT, 10); 
720      break; 
721    case "dateTime": 
722      p.tx(" "); 
723      input = p.input(i.primitiveValue("linkId"), "datetime-local", typeT, 25); 
724      break; 
725    case "decimal": 
726      p.tx(" "); 
727      input = p.input(i.primitiveValue("linkId"), "number", typeT, 15); 
728      break; 
729    case "display": 
730      break; 
731    case "group": 
732      break; 
733    case "integer": 
734      p.tx(" "); 
735      input = p.input(i.primitiveValue("linkId"), "number", typeT, 10); 
736      break; 
737    case "qantity": 
738      p.tx(" "); 
739      input = p.input(i.primitiveValue("linkId"), "number", "value", 15); 
740      p.tx(" "); 
741      input = p.input(i.primitiveValue("linkId"), "unit", "unit", 10); 
742      break; 
743    case "question": 
744      break; 
745    case "reference": 
746      break; 
747    case "text": 
748      break; 
749    case "time": 
750      break; 
751    case "url": 
752      break; 
753    default: 
754      break; 
755    } 
756    if (input != null) { 
757      if ("true".equals(i.primitiveValue("readOnly"))) { 
758        input.attribute("readonly", "1"); 
759        input.style("background-color: #eeeeee"); 
760      } 
761    } 
762
763    //  if (i.hasExtension(ToolingExtensions.EXT_Q_CHOICE_ORIENT)) { 
764    //  String code = ToolingExtensions.readStringExtension(i,  ToolingExtensions.EXT_Q_CHOICE_ORIENT); 
765    //  flags.addPiece(gen.new Piece("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-observationLinkPeriod", null, "Orientation: "+code).addHtml(new XhtmlNode(NodeType.Element, "img").attribute("alt", "icon").attribute("src", Utilities.path(context.getLocalPrefix(), "icon-qi-"+code+".png")))); 
766    //} 
767
768
769    XhtmlNode ul = details.ul(); 
770    boolean hasFlag = false;  
771    XhtmlNode flags = item(ul, "Flags"); 
772    item(ul, "linkId", i.primitiveValue("linkId")); 
773
774    if ("true".equals(i.extensionString("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-isSubject"))) { 
775      hasFlag = true; 
776      flags.ah(getSDCLink("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-isSubject", "StructureDefinition-sdc-questionnaire-isSubject.html"), context.formatPhrase(RenderingContext.QUEST_SUBJECT)).img(getImgPath("icon-qi-subject.png"), "icon"); 
777    } 
778    if ("true".equals(i.extensionString(ToolingExtensions.EXT_Q_HIDDEN))) { 
779      hasFlag = true; 
780      flags.ah(Utilities.pathURL(context.getLink(KnownLinkType.SPEC), "extension-questionnaire-hidden.html"), context.formatPhrase(RenderingContext.QUEST_HIDDEN)).img(getImgPath("icon-qi-hidden.png"), "icon"); 
781      d.style("background-color: #eeeeee"); 
782    } 
783    if ("true".equals(i.extensionString(ToolingExtensions.EXT_Q_OTP_DISP))) { 
784      hasFlag = true; 
785      flags.ah(getSDCLink("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-optionalDisplay", "StructureDefinition-sdc-questionnaire-optionalDisplay.html"), context.formatPhrase(RenderingContext.QUEST_DISPLAY)).img(getImgPath("icon-qi-optional.png"), "icon"); 
786    } 
787    if (i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-observationLinkPeriod")) { 
788      hasFlag = true; 
789      flags.ah(getSDCLink("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-observationLinkPeriod", "StructureDefinition-sdc-questionnaire-observationLinkPeriod.html"), context.formatPhrase(RenderingContext.QUEST_LINKED)).img(getImgPath("icon-qi-observation.png"), "icon"); 
790    } 
791    if (i.hasExtension(ToolingExtensions.EXT_Q_DISPLAY_CAT)) { 
792      ResourceWrapper cc = i.extension(ToolingExtensions.EXT_Q_DISPLAY_CAT).child("value"); 
793      String code = getCodeFromCC(cc, "http://hl7.org/fhir/questionnaire-display-category"); 
794      hasFlag = true; 
795      flags.ah("https://hl7.org/fhir/R4/extension-questionnaire-displayCategory.html", (context.formatPhrase(RenderingContext.QUEST_CAT, code)+" ")).img(getImgPath("icon-qi-" + code + ".png"), "icon"); 
796    } 
797
798    if (i.has("maxLength")) { 
799      item(ul, context.formatPhrase(RenderingContext.GENERAL_MAX_LENGTH), i.primitiveValue("maxLength")); 
800    } 
801    if (i.has("definition")) { 
802      genDefinitionLink(item(ul, context.formatPhrase(RenderingContext.GENERAL_DEFINITION_COLON)), i, q);       
803    } 
804    if (i.has("enableWhen")) { 
805      item(ul, context.formatPhrase(RenderingContext.QUEST_EN), "todo"); 
806    } 
807    if (i.has("answerValueSet")) { 
808      XhtmlNode ans = item(ul, context.formatPhrase(RenderingContext.QUEST_ANSWERS)); 
809      if (!Utilities.noString(i.primitiveValue("answerValueSet")) && i.primitiveValue("answerValueSet").startsWith("#")) { 
810        ResourceWrapper vs = q.getContained(i.primitiveValue("answerValueSet").substring(1)); 
811        if (vs == null) {
812          ans.tx(i.primitiveValue("answerValueSet"));
813        } else if (vs.getWebPath() == null) {                     
814          ans.ah(context.prefixLocalHref("#hc"+vs.getScopedId())).tx(RendererFactory.factory(vs, context.forContained()).buildSummary(vs));                               
815        } else { 
816          ans.ah(context.prefixLocalHref(vs.getWebPath())).tx(RendererFactory.factory(vs, context.forContained()).buildSummary(vs));                               
817        } 
818      } else { 
819        ValueSet vs = context.getWorker().findTxResource(ValueSet.class, i.primitiveValue("answerValueSet"), q.getResourceNative()); 
820        if (vs == null  || !vs.hasWebPath()) { 
821          ans.tx(i.primitiveValue("answerValueSet"));                     
822        } else { 
823          ans.ah(vs.getWebPath()).tx(vs.present());                               
824        }              
825      } 
826    } 
827    if (i.has("answerOption")) { 
828      item(ul, context.formatPhrase(RenderingContext.QUEST_ANSWERS), Integer.toString(i.children("answerOption").size())+" "+Utilities.pluralize("option", i.children("answerOption").size()), context.getDefinitionsTarget()+"#item."+i.primitiveValue("linkId")); 
829    } 
830    if (i.has("initial")) { 
831      XhtmlNode vi = item(ul, context.formatPhrase(RenderingContext.QUEST_INT)); 
832      boolean first = true; 
833      for (ResourceWrapper v : i.children("initial")) { 
834        if (first) first = false; else vi.tx(", "); 
835        ResourceWrapper vv = v.child("value");
836        if (vv.isPrimitive()) { 
837          vi.tx(vv.primitiveValue()); 
838        } else if (vv.fhirType().equals("Coding")) { 
839          renderCoding(status, vi, vv);            
840        } else if (vv.fhirType().equals("Reference")) { 
841          renderReference(status, vi, vv);            
842        } else if (vv.fhirType().equals("Quantity")) { 
843          renderQuantity(status, vi, vv);            
844          //        } else if (v.hasValueAttachment()) { 
845          //          renderAttachment(vi, v.getValueAttachment());            
846        } 
847      } 
848    } 
849    if (!hasFlag) { 
850      ul.remove(flags); 
851    } 
852    //    if (i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-enableWhenExpression") || i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-itemContext") || i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-calculatedExpression") || i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-contextExpression") || i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-candidateExpression") || i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-initialExpression")) { 
853    //      if (!defn.getPieces().isEmpty()) defn.addPiece(gen.new Piece("br")); 
854    //      defn.getPieces().add(gen.new Piece(null, "Expressions: ", null)); 
855    //      Piece p = gen.new Piece("ul"); 
856    //      defn.getPieces().add(p); 
857    //      for (Extension e : i.getExtensionsByUrl("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-initialExpression")) { 
858    //        addExpression(p, e.getValueExpression(), "Initial Value", "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-initialExpression"); 
859    //      } 
860    //      for (Extension e : i.getExtensionsByUrl("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-contextExpression")) { 
861    //        addExpression(p, e.getValueExpression(), "Context", "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-contextExpression"); 
862    //      } 
863    //      for (Extension e : i.getExtensionsByUrl("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-itemContext")) { 
864    //        addExpression(p, e.getValueExpression(), "Item Context", "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-itemContext"); 
865    //      } 
866    //      for (Extension e : i.getExtensionsByUrl("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-enableWhenExpression")) { 
867    //        addExpression(p, e.getValueExpression(), "Enable When", "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-enableWhenExpression"); 
868    //      } 
869    //      for (Extension e : i.getExtensionsByUrl("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-calculatedExpression")) { 
870    //        addExpression(p, e.getValueExpression(), "Calculated Value", "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-calculatedExpression"); 
871    //      } 
872    //      for (Extension e : i.getExtensionsByUrl("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-candidateExpression")) { 
873    //        addExpression(p, e.getValueExpression(), "Candidates", "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-candidateExpression"); 
874    //      }  
875    //    } 
876    // 
877
878    int t = 1; 
879    for (ResourceWrapper c : i.children("item")) { 
880      renderFormItem(status, x, q, c, pfx == null ? null : pfx+"."+Integer.toString(t), indent+1); 
881      t++; 
882    }   
883  } 
884
885  @Nonnull 
886  private String getImgPath(String code) throws IOException { 
887    return context.getLocalPrefix().length() > 0 
888        ? Utilities.path(context.getLocalPrefix(), code) 
889            : Utilities.path(code); 
890  } 
891
892  private void item(XhtmlNode ul, String name, String value, String valueLink) { 
893    if (!Utilities.noString(value)) { 
894      ul.li().style("font-size: 10px").ah(context.prefixLocalHref(valueLink)).tx(name+": "+value); 
895    } 
896  } 
897
898  private void item(XhtmlNode ul, String name, String value) { 
899    if (!Utilities.noString(value)) { 
900      ul.li().style("font-size: 10px").tx(name+": "+value); 
901    } 
902  } 
903  private XhtmlNode item(XhtmlNode ul, String name) { 
904    XhtmlNode li = ul.li(); 
905    li.style("font-size: 10px").tx(name+": "); 
906    return li; 
907  } 
908
909
910  private void listOptions(ResourceWrapper q, ResourceWrapper i, XhtmlNode select) { 
911    if (i.has("answerValueSet")) { 
912      ValueSet vs = null; 
913      if (!Utilities.noString(i.primitiveValue("answerValueSet")) && i.primitiveValue("answerValueSet").startsWith("#")) { 
914        ResourceWrapper contained = q.getContained(i.primitiveValue("answerValueSet").substring(1));
915        vs = contained == null ? null : (ValueSet) contained.getResourceNative(); 
916        if (vs != null && !vs.hasUrl()) { 
917          vs = vs.copy(); 
918          vs.setUrl(q.primitiveValue("url")+"--"+contained); 
919        } 
920      } else { 
921        vs = context.getContext().findTxResource(ValueSet.class, i.primitiveValue("answerValueSet"), q.getResourceNative()); 
922      } 
923      if (vs != null) { 
924        ValueSetExpansionOutcome exp = context.getContext().expandVS(vs, true, false); 
925        if (exp.getValueset() != null) { 
926          for (ValueSetExpansionContainsComponent cc : exp.getValueset().getExpansion().getContains()) { 
927            select.option(cc.getCode(), cc.hasDisplay() ? cc.getDisplay() : cc.getCode(), false);     
928          } 
929          return; 
930        } 
931      } 
932    } else if (i.has("answerOption")) { 
933      renderItemOptions(select, i);  
934    }  
935    select.option("a", "??", false);     
936  } 
937
938  private void renderLinks(RenderingStatus status, XhtmlNode x, ResourceWrapper q) { 
939    x.para().tx(context.formatPhrase(RenderingContext.QUEST_TRY)); 
940    XhtmlNode ul = x.ul(); 
941    ul.li().ah("http://todo.nlm.gov/path?mode=ig&src="+Utilities.pathURL(context.getLink(KnownLinkType.SELF), "package.tgz")+"&q="+q.getId()+".json").tx(context.formatPhrase(RenderingContext.QUEST_NLM)); 
942  } 
943
944  private void renderDefns(RenderingStatus status, XhtmlNode x, ResourceWrapper q) throws IOException { 
945    XhtmlNode tbl = x.table("dict", false); 
946    renderRootDefinition(status, tbl, q, new ArrayList<>()); 
947    for (ResourceWrapper qi : q.children("item")) { 
948      renderDefinition(status, tbl, q, qi, new ArrayList<>()); 
949    } 
950  } 
951
952  private void renderRootDefinition(RenderingStatus status, XhtmlNode tbl, ResourceWrapper q, List<ResourceWrapper> parents) throws IOException { 
953    boolean ext = false; 
954    XhtmlNode td = tbl.tr().td("structure").colspan("2").span(null, null).attribute("class", "self-link-parent"); 
955    td.an(context.prefixAnchor(q.getId())); 
956    td.img(getImgPath("icon_q_root.gif"), "icon"); 
957    td.tx(" "+(context.formatPhrase(RenderingContext.QUEST_QUEST)+" ")); 
958    td.b().tx(q.getId()); 
959
960    // general information 
961    defn(tbl, context.formatPhrase(RenderingContext.GENERAL_URL), q.primitiveValue("url")); 
962    defn(tbl, context.formatPhrase(RenderingContext.GENERAL_VER), q.primitiveValue("version")); 
963    defn(tbl, context.formatPhrase(RenderingContext.GENERAL_NAME), q.primitiveValue("name")); 
964    defn(tbl, context.formatPhrase(RenderingContext.GENERAL_TITLE), q.primitiveValue("title")); 
965    if (q.has("derivedFrom")) { 
966      td = defn(tbl, context.formatPhrase(RenderingContext.QUEST_DERIVED)); 
967      boolean first = true; 
968      for (ResourceWrapper c : q.children("derivedFrom")) { 
969        if (first) first = false; else td.tx(", "); 
970        td.tx(c.primitiveValue()); // todo: make these a reference 
971      } 
972    } 
973    defn(tbl, context.formatPhrase(RenderingContext.GENERAL_STATUS), q.primitiveValue("status")); 
974    defn(tbl, context.formatPhrase(RenderingContext.GENERAL_EXPER), q.primitiveValue("experimental")); 
975    defn(tbl, context.formatPhrase(RenderingContext.QUEST_PUB), q.primitiveValue("date")); 
976    defn(tbl, context.formatPhrase(RenderingContext.QUEST_APP), q.primitiveValue("approvalDate")); 
977    defn(tbl, context.formatPhrase(RenderingContext.QUEST_REV_DATE), q.primitiveValue("lastReviewDate")); 
978    if (q.has("effectivePeriod")) { 
979      renderPeriod(status, defn(tbl, context.formatPhrase(RenderingContext.QUEST_EFF_PERIOD)), q.child("effectivePeriod")); 
980    } 
981
982    if (q.has("subjectType")) { 
983      td = defn(tbl, context.formatPhrase(RenderingContext.QUEST_SUB_TYPE)); 
984      boolean first = true; 
985      for (ResourceWrapper c : q.children("subjectType")) { 
986        if (first) first = false; else td.tx(", "); 
987        td.tx(c.primitiveValue()); 
988      } 
989    } 
990    defn(tbl, context.formatPhrase(RenderingContext.GENERAL_DESC), q.primitiveValue("description")); 
991    defn(tbl, context.formatPhrase(RenderingContext.GENERAL_PURPOSE), q.primitiveValue("purpose")); 
992    defn(tbl, context.formatPhrase(RenderingContext.GENERAL_COPYRIGHT), q.primitiveValue("copyright")); 
993    if (q.has("code")) { 
994      td = defn(tbl, Utilities.pluralize("Code", q.children("code").size())); 
995      boolean first = true; 
996      for (ResourceWrapper c : q.children("code")) { 
997        if (first) first = false; else td.tx(", "); 
998        renderCodingWithDetails(status, td,  c); 
999      } 
1000    } 
1001  } 
1002
1003  private void renderDefinition(RenderingStatus status, XhtmlNode tbl, ResourceWrapper q, ResourceWrapper qi, List<ResourceWrapper> parents) throws IOException { 
1004    XhtmlNode td = tbl.tr().td("structure").colspan("2").span(null, null).attribute("class", "self-link-parent"); 
1005    td.an(context.prefixAnchor("item."+qi.primitiveValue("linkId"))); 
1006    for (ResourceWrapper p : parents) { 
1007      td.ah(context.prefixLocalHref("#item."+p.primitiveValue("linkId"))).img(getImgPath("icon_q_item.png"), "icon"); 
1008      td.tx(" > "); 
1009    } 
1010    td.img(getImgPath("icon_q_item.png"), "icon"); 
1011    td.tx(" Item "); 
1012    td.b().tx(qi.primitiveValue("linkId")); 
1013    String type = qi.primitiveValue("type");
1014
1015    // general information 
1016    defn(tbl, context.formatPhrase(RenderingContext.QUEST_ID), qi.primitiveValue("linkId")); 
1017    defn(tbl, context.formatPhrase(RenderingContext.QUEST_PREFIX), qi.primitiveValue("prefix")); 
1018    defn(tbl, context.formatPhrase(RenderingContext.QUEST_TEXT), qi.primitiveValue("text")); 
1019    defn(tbl, context.formatPhrase(RenderingContext.GENERAL_TYPE), type); 
1020    defn(tbl, context.formatPhrase(RenderingContext.GENERAL_REQUIRED), qi.primitiveValue("required")); 
1021    defn(tbl, context.formatPhrase(RenderingContext.QUEST_REP), qi.primitiveValue("repeats")); 
1022    defn(tbl, context.formatPhrase(RenderingContext.QUEST_READ_ONLY), qi.primitiveValue("readOnly")); 
1023    if ("true".equals(qi.extensionString("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-isSubject"))) { 
1024      defn(tbl, context.formatPhrase(RenderingContext.GENERAL_SUBJ), "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-isSubject", "This element changes who the subject of the question is", null); 
1025    } 
1026
1027    // content control 
1028    defn(tbl, context.formatPhrase(RenderingContext.QUEST_MAX_LENGTH), qi.primitiveValue("maxLength")); 
1029    if (qi.has("answerValueSet")) { 
1030      defn(tbl, context.formatPhrase(RenderingContext.GENERAL_VALUESET), qi.primitiveValue("definition"), context.getWorker().findTxResource(ValueSet.class,  qi.primitiveValue("answerValueSet"), q.getResourceNative())); 
1031    } 
1032    if (qi.has("answerOption")) { 
1033      XhtmlNode tr = tbl.tr(); 
1034      tr.td().tx(context.formatPhrase(RenderingContext.QUEST_ALLOWED)); 
1035      XhtmlNode ul = tr.td().ul(); 
1036      for (ResourceWrapper ans : qi.children("answerOption")) { 
1037        XhtmlNode li = ul.li(); 
1038        renderDataType(status, li, ans.child("value")); 
1039        if ("true".equals(ans.primitiveValue("initialSelected"))) { 
1040          li.tx(" "+(context.formatPhrase(RenderingContext.QUEST_INITIALLY))); 
1041        } 
1042      }       
1043    } 
1044    if (qi.has("initial")) { 
1045      XhtmlNode tr = tbl.tr(); 
1046      tr.td().tx(Utilities.pluralize((context.formatPhrase(RenderingContext.QUEST_INITIAL_ANSWER)), qi.children("initial").size())); 
1047      if (qi.children("initial").size() == 1) { 
1048        renderDataType(status, tr.td(), qi.firstChild("initial").child("value")); 
1049      } else { 
1050        XhtmlNode ul = tr.td().ul(); 
1051        for (ResourceWrapper ans : qi.children("initial")) { 
1052          XhtmlNode li = ul.li(); 
1053          renderDataType(status, li, ans.child("value")); 
1054        } 
1055      }       
1056    } 
1057
1058    // appearance  
1059    if (qi.hasExtension(ToolingExtensions.EXT_Q_DISPLAY_CAT)) { 
1060      XhtmlNode tr = tbl.tr(); 
1061      tr.td().ah(ToolingExtensions.EXT_Q_DISPLAY_CAT).tx("Display Category"); 
1062      renderDataType(status, tr.td(), qi.extension(ToolingExtensions.EXT_Q_DISPLAY_CAT).child("value")); 
1063    } 
1064    if ("true".equals(qi.extensionString(ToolingExtensions.EXT_Q_HIDDEN))) { 
1065      defn(tbl, context.formatPhrase(RenderingContext.QUEST_HIDDEN_ITEM), ToolingExtensions.EXT_Q_DISPLAY_CAT, "This item is a hidden question", null); 
1066    } 
1067    if ("true".equals(qi.extensionString(ToolingExtensions.EXT_Q_OTP_DISP))) { 
1068      defn(tbl, context.formatPhrase(RenderingContext.QUEST_HIDDEN_ITEM), ToolingExtensions.EXT_Q_OTP_DISP, "This item is optional to display", null); 
1069    } 
1070
1071    // formal definitions 
1072    if (qi.has("definition")) { 
1073      genDefinitionLink(defn(tbl, context.formatPhrase(RenderingContext.GENERAL_DEFINITION)), qi, q); 
1074    } 
1075
1076    if (qi.has("code")) { 
1077      XhtmlNode tr = tbl.tr(); 
1078      tr.td().tx(Utilities.pluralize(context.formatPhrase(RenderingContext.GENERAL_CODE), qi.children("code").size())); 
1079      XhtmlNode ul = tr.td().ul(); 
1080      for (ResourceWrapper c : qi.children("code")) { 
1081        renderCodingWithDetails(status, ul.li(), c); 
1082      } 
1083    } 
1084    if (qi.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-observationLinkPeriod")) { 
1085      XhtmlNode tr = tbl.tr(); 
1086      StructureDefinition sd = context.getContext().fetchResource(StructureDefinition.class, ToolingExtensions.EXT_O_LINK_PERIOD); 
1087      if (sd != null && sd.hasWebPath()) { 
1088        tr.td().ah(sd.getWebPath()).tx(context.formatPhrase(RenderingContext.QUEST_OBSERVATION)); 
1089      } else { 
1090        tr.td().ah("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-observationLinkPeriod").tx(context.formatPhrase(RenderingContext.QUEST_OBSERVATION)); 
1091      } 
1092      renderDataType(status, tr.td(), qi.extension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-Questionnaire-observationLinkPeriod").child("value")); 
1093    } 
1094
1095    // dynamic management 
1096    if (qi.has("enableWhen")) { 
1097      XhtmlNode tr = tbl.tr(); 
1098      tr.td().tx(context.formatPhrase(RenderingContext.QUEST_EN)); 
1099      td = tr.td(); 
1100      if (qi.children("enableWhen").size() == 1) { 
1101        renderEnableWhen(td, qi.children("enableWhen").get(0)); 
1102      } else { 
1103        if (qi.has("enableBehavior")) { 
1104          td.tx(qi.primitiveValue("enableBehavior")+" "+(context.formatPhrase(RenderingContext.QUEST_TRUE))); 
1105        } else { 
1106          td.tx(context.formatPhrase(RenderingContext.QUEST_ARE_TRUE)); 
1107        } 
1108        XhtmlNode ul = td.ul(); 
1109        for (ResourceWrapper ew : qi.children("enableWhen")) { 
1110          renderEnableWhen(ul.li(), ew); 
1111        } 
1112      }       
1113    } 
1114
1115
1116    // other stuff 
1117
1118
1119
1120    List<ResourceWrapper> curr = new ArrayList<>(); 
1121    curr.addAll(parents); 
1122    curr.add(qi); 
1123    for (ResourceWrapper qic : qi.children("item")) { 
1124      renderDefinition(status, tbl, q, qic, curr); 
1125    }  
1126  } 
1127
1128  private void defn(XhtmlNode tbl, String name, String url, Resource res) throws UnsupportedEncodingException, IOException { 
1129    if (res != null && res.hasWebPath()) { 
1130      defn(tbl, context.formatPhrase(RenderingContext.GENERAL_DEFINITION), RendererFactory.factory(res, context.forContained()).buildSummary(wrap(res)), res.getWebPath()); 
1131    } else if (Utilities.isAbsoluteUrlLinkable(url)) { 
1132      defn(tbl, context.formatPhrase(RenderingContext.GENERAL_DEFINITION), url, url); 
1133    } { 
1134      defn(tbl, context.formatPhrase(RenderingContext.GENERAL_DEFINITION), url); 
1135    } 
1136
1137  } 
1138
1139  private void renderEnableWhen(XhtmlNode x, ResourceWrapper ew) { 
1140    x.ah(context.prefixLocalHref("#item."+ew.primitiveValue("question"))).tx(ew.primitiveValue("question")); 
1141    x.tx(" "); 
1142    x.tx(ew.primitiveValue("operator")); 
1143    x.tx(" "); 
1144    x.tx(displayDataType(ew.child("Answer"))); 
1145  } 
1146
1147  private XhtmlNode defn(XhtmlNode tbl, String name) { 
1148    XhtmlNode tr = tbl.tr(); 
1149    tr.td().tx(name); 
1150    return tr.td(); 
1151  } 
1152
1153  private void defn(XhtmlNode tbl, String name, int value) { 
1154    if (value > 0) { 
1155      XhtmlNode tr = tbl.tr(); 
1156      tr.td().tx(name); 
1157      tr.td().tx(value); 
1158    }     
1159  } 
1160
1161
1162  private void defn(XhtmlNode tbl, String name, boolean value) { 
1163    XhtmlNode tr = tbl.tr(); 
1164    tr.td().tx(name); 
1165    tr.td().tx(Boolean.toString(value)); 
1166  } 
1167
1168  private void defn(XhtmlNode tbl, String name, String value) { 
1169    if (!Utilities.noString(value)) { 
1170      XhtmlNode tr = tbl.tr(); 
1171      tr.td().tx(name); 
1172      tr.td().tx(value); 
1173    }     
1174  } 
1175
1176  private void defn(XhtmlNode tbl, String name, String value, String url) { 
1177    if (!Utilities.noString(value)) { 
1178      XhtmlNode tr = tbl.tr(); 
1179      tr.td().tx(name); 
1180      tr.td().ah(context.prefixLocalHref(url)).tx(value); 
1181    }     
1182  } 
1183
1184  private void defn(XhtmlNode tbl, String name, String nurl, String value, String url) { 
1185    if (!Utilities.noString(value)) { 
1186      XhtmlNode tr = tbl.tr(); 
1187      tr.td().ah(context.prefixLocalHref(nurl)).tx(name); 
1188      if (url != null) { 
1189        tr.td().ah(context.prefixLocalHref(url)).tx(value); 
1190      } else { 
1191        tr.td().tx(value); 
1192      } 
1193    }     
1194  } 
1195
1196  private void defn(XhtmlNode tbl, String name, boolean value, boolean ifFalse) { 
1197    if (ifFalse || value) { 
1198      XhtmlNode tr = tbl.tr(); 
1199      tr.td().tx(name); 
1200      tr.td().tx(Boolean.toString(value)); 
1201    }     
1202  } 
1203
1204}