001package org.hl7.fhir.r5.renderers;
002
003import java.io.IOException;
004import java.io.UnsupportedEncodingException;
005import java.util.List;
006
007import org.hl7.fhir.r5.model.Base;
008import org.hl7.fhir.r5.model.DataType;
009import org.hl7.fhir.r5.model.Expression;
010import org.hl7.fhir.r5.model.QuestionnaireResponse;
011import org.hl7.fhir.r5.model.QuestionnaireResponse.QuestionnaireResponseItemAnswerComponent;
012import org.hl7.fhir.r5.model.QuestionnaireResponse.QuestionnaireResponseItemComponent;
013import org.hl7.fhir.r5.model.Resource;
014import org.hl7.fhir.r5.model.StructureDefinition;
015import org.hl7.fhir.r5.renderers.utils.BaseWrappers.BaseWrapper;
016import org.hl7.fhir.r5.renderers.utils.BaseWrappers.ResourceWrapper;
017import org.hl7.fhir.r5.renderers.utils.RenderingContext;
018import org.hl7.fhir.r5.renderers.utils.RenderingContext.KnownLinkType;
019import org.hl7.fhir.utilities.Utilities;
020import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator;
021import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.Cell;
022import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.Piece;
023import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.Row;
024import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.TableModel;
025import org.hl7.fhir.utilities.xhtml.NodeType;
026import org.hl7.fhir.utilities.xhtml.XhtmlNode;
027
028public class QuestionnaireResponseRenderer extends ResourceRenderer {
029
030  public QuestionnaireResponseRenderer(RenderingContext context) {
031    super(context);
032  }
033  
034  public boolean render(XhtmlNode x, Resource q) throws UnsupportedEncodingException, IOException {
035    return render(x, (QuestionnaireResponse) q);
036  }
037  
038  public boolean render(XhtmlNode x, QuestionnaireResponse q) throws UnsupportedEncodingException, IOException {
039    switch (context.getQuestionnaireMode()) {
040    case FORM:  return renderForm(x, q);
041    case LINKS: return renderLinks(x, q);
042//    case LOGIC: return renderLogic(x, q);
043//    case DEFNS: return renderDefns(x, q);
044    case TREE:  return renderTree(x, q);
045    default:
046      throw new Error("Unknown QuestionnaireResponse Renderer Mode");
047    }
048  }
049  
050  public boolean render(XhtmlNode x, ResourceWrapper qr) throws UnsupportedEncodingException, IOException {
051    switch (context.getQuestionnaireMode()) {
052    case FORM:  return renderTree(x, qr);
053    case LINKS: return renderLinks(x, qr);
054//    case LOGIC: return renderLogic(x, q);
055//    case DEFNS: return renderDefns(x, q);
056    case TREE:  return renderTree(x, qr);
057    default:
058      throw new Error("Unknown QuestionnaireResponse Renderer Mode");
059    }
060  }
061  
062  public boolean renderTree(XhtmlNode x, ResourceWrapper qr) throws UnsupportedEncodingException, IOException {
063    HierarchicalTableGenerator gen = new HierarchicalTableGenerator(context.getDestDir(), context.isInlineGraphics(), true);
064    TableModel model = gen.new TableModel("qtree="+qr.getId(), false);    
065    model.setAlternating(true);
066    model.setDocoImg(context.getLink(KnownLinkType.SPEC) +"help16.png");
067    model.setDocoRef(context.getLink(KnownLinkType.SPEC)+"formats.html#table");
068    model.getTitles().add(gen.new Title(null, model.getDocoRef(), translate("sd.head", "LinkId"), translate("sd.hint", "The linkId for the item"), null, 0));
069    model.getTitles().add(gen.new Title(null, model.getDocoRef(), translate("sd.head", "Text"), translate("sd.hint", "Text for the item"), null, 0));
070    model.getTitles().add(gen.new Title(null, model.getDocoRef(), translate("sd.head", "Definition"), translate("sd.hint", "Minimum and Maximum # of times the the itemcan appear in the instance"), null, 0));
071    model.getTitles().add(gen.new Title(null, model.getDocoRef(), translate("sd.head", "Answer"), translate("sd.hint", "The type of the item"), null, 0));
072
073    boolean hasExt = false;
074    // first we add a root for the questionaire itself
075    Row row = addTreeRoot(gen, model.getRows(), qr);
076    List<BaseWrapper> items = qr.children("item");
077    for (BaseWrapper i : items) {
078      hasExt = renderTreeItem(gen, row.getSubRows(), qr, i) || hasExt;
079    }
080    XhtmlNode xn = gen.generate(model, context.getLocalPrefix(), 1, null);
081    x.getChildNodes().add(xn);
082    return hasExt;
083  }
084
085  public boolean renderTree(XhtmlNode x, QuestionnaireResponse q) throws UnsupportedEncodingException, IOException {
086    HierarchicalTableGenerator gen = new HierarchicalTableGenerator(context.getDestDir(), context.isInlineGraphics(), true);
087    TableModel model = gen.new TableModel("qtree="+q.getId(), true);    
088    model.setAlternating(true);
089    model.setDocoImg(context.getLink(KnownLinkType.SPEC) +"help16.png");
090    model.setDocoRef(context.getLink(KnownLinkType.SPEC)+"formats.html#table");
091    model.getTitles().add(gen.new Title(null, model.getDocoRef(), translate("sd.head", "LinkId"), translate("sd.hint", "The linkId for the item"), null, 0));
092    model.getTitles().add(gen.new Title(null, model.getDocoRef(), translate("sd.head", "Text"), translate("sd.hint", "Text for the item"), null, 0));
093    model.getTitles().add(gen.new Title(null, model.getDocoRef(), translate("sd.head", "Definition"), translate("sd.hint", "Minimum and Maximum # of times the the itemcan appear in the instance"), null, 0));
094    model.getTitles().add(gen.new Title(null, model.getDocoRef(), translate("sd.head", "Answer"), translate("sd.hint", "The type of the item"), null, 0));
095
096    boolean hasExt = false;
097    // first we add a root for the questionaire itself
098    Row row = addTreeRoot(gen, model.getRows(), q);
099    for (QuestionnaireResponseItemComponent i : q.getItem()) {
100      hasExt = renderTreeItem(gen, row.getSubRows(), q, i) || hasExt;
101    }
102    XhtmlNode xn = gen.generate(model, context.getLocalPrefix(), 1, null);
103    x.getChildNodes().add(xn);
104    return hasExt;
105  }
106
107
108
109  private Row addTreeRoot(HierarchicalTableGenerator gen, List<Row> rows, QuestionnaireResponse q) throws IOException {
110    Row r = gen.new Row();
111    rows.add(r);
112
113    r.setIcon("icon_q_root.gif", "QuestionnaireResponseRoot");
114    r.getCells().add(gen.new Cell(null, null, q.getId(), null, null));
115    r.getCells().add(gen.new Cell(null, null, "", null, null));
116    r.getCells().add(gen.new Cell(null, null, "QuestionnaireResponse", null, null));
117    r.getCells().add(gen.new Cell(null, null, "", null, null));
118    return r;    
119  }
120
121  private Row addTreeRoot(HierarchicalTableGenerator gen, List<Row> rows, ResourceWrapper q) throws IOException {
122    Row r = gen.new Row();
123    rows.add(r);
124
125    r.setIcon("icon_q_root.gif", "QuestionnaireResponseRoot");
126    r.getCells().add(gen.new Cell(null, null, q.getId(), null, null));
127    r.getCells().add(gen.new Cell(null, null, "", null, null));
128    r.getCells().add(gen.new Cell(null, null, "QuestionnaireResponse", null, null));
129    r.getCells().add(gen.new Cell(null, null, "", null, null));
130    return r;    
131  }
132
133
134
135  private boolean renderTreeItem(HierarchicalTableGenerator gen, List<Row> rows, ResourceWrapper q, BaseWrapper i) throws IOException {
136    Row r = gen.new Row();
137    rows.add(r);
138    boolean hasExt = false;
139
140    List<BaseWrapper> items = i.children("item");
141    List<BaseWrapper> answers = i.children("answer");
142    boolean hasItem = items != null && !items.isEmpty();
143    if (answers != null) {
144      for (BaseWrapper a : answers) {
145        hasItem = a.has("item");
146      }
147    }
148    if (hasItem) {
149      r.setIcon("icon-q-group.png", "Group");
150    } else {
151      r.setIcon("icon-q-string.png", "Item");
152    }
153    String linkId = i.has("linkId") ? i.get("linkId").primitiveValue() : "??";
154    String text = i.has("text") ? i.get("text").primitiveValue() : "";
155    r.getCells().add(gen.new Cell(null, context.getDefinitionsTarget() == null ? "" : context.getDefinitionsTarget()+"#item."+linkId, linkId, null, null));
156    r.getCells().add(gen.new Cell(null, null, text, null, null));
157    r.getCells().add(gen.new Cell(null, null, null, null, null));
158    if (answers == null ||  answers.size() == 0) {
159      r.getCells().add(gen.new Cell(null, null, null, null, null));
160      if (items != null) {
161        for (BaseWrapper si : items) {
162          renderTreeItem(gen, r.getSubRows(), q, si);
163        }
164      }
165    } else if (answers.size() == 1) {
166      BaseWrapper ans = answers.get(0);
167      renderAnswer(gen, q, r, ans);
168    } else {
169      r.getCells().add(gen.new Cell(null, null, null, null, null));          
170      for (BaseWrapper ans : answers) {
171        Row ar = gen.new Row();
172        ar.setIcon("icon-q-string.png", "Item");
173        ar.getSubRows().add(ar);
174        ar.getCells().add(gen.new Cell(null, null, null, null, null));
175        ar.getCells().add(gen.new Cell(null, null, text, null, null));
176        ar.getCells().add(gen.new Cell(null, null, null, null, null));
177        renderAnswer(gen, q, ar, ans);
178      }
179    }
180
181    return hasExt;    
182  }
183
184  public void renderAnswer(HierarchicalTableGenerator gen, ResourceWrapper q, Row r, BaseWrapper ans) throws UnsupportedEncodingException, IOException {
185    List<BaseWrapper> items;
186    Base b = ans.get("value[x]");
187    if (b == null) {
188      r.getCells().add(gen.new Cell(null, null, "null!", null, null));
189    } else if (b.isPrimitive()) {
190      r.getCells().add(gen.new Cell(null, null, b.primitiveValue(), null, null));
191    } else {
192      XhtmlNode x = new XhtmlNode(NodeType.Element, "span");
193      Cell cell = gen.new Cell(null, null, null, null, null);
194      Piece p = gen.new Piece("span");
195      p.getChildren().add(x);
196      cell.addPiece(p);
197      render(x, (DataType) b);
198      r.getCells().add(cell);
199    }
200    items = ans.children("item");
201    for (BaseWrapper si : items) {
202      renderTreeItem(gen, r.getSubRows(), q, si);
203    }
204  }
205  
206  private boolean renderTreeItem(HierarchicalTableGenerator gen, List<Row> rows, QuestionnaireResponse q, QuestionnaireResponseItemComponent i) throws IOException {
207    Row r = gen.new Row();
208    rows.add(r);
209    boolean hasExt = false;
210
211    boolean hasItem = i.hasItem();
212    for (QuestionnaireResponseItemAnswerComponent a : i.getAnswer()) {
213      hasItem = a.hasItem();
214    }
215    if (hasItem) {
216      r.setIcon("icon-q-group.png", "Group");
217    } else {
218      r.setIcon("icon-q-string.png", "Item");
219    }
220    r.getCells().add(gen.new Cell(null, context.getDefinitionsTarget() == null ? "" : context.getDefinitionsTarget()+"#item."+i.getLinkId(), i.getLinkId(), null, null));
221    r.getCells().add(gen.new Cell(null, null, i.getText(), null, null));
222    r.getCells().add(gen.new Cell(null, null, null, null, null));
223    r.getCells().add(gen.new Cell(null, null, null, null, null));
224
225    return hasExt;    
226  }
227
228  public void genDefinitionLink(HierarchicalTableGenerator gen, QuestionnaireResponseItemComponent i, Cell defn, Resource src) {
229    // can we resolve the definition? 
230    String path = null;
231    String d = i.getDefinition();
232    if (d.contains("#")) {
233      path = d.substring(d.indexOf("#")+1);
234      d = d.substring(0, d.indexOf("#"));
235    }
236    StructureDefinition sd = context.getWorker().fetchResource(StructureDefinition.class, d, src);
237    if (sd != null) {
238      String url = sd.getUserString("path");
239      if (url != null) {
240        defn.getPieces().add(gen.new Piece(url+"#"+path, path, null));          
241      } else {
242        defn.getPieces().add(gen.new Piece(null, i.getDefinition(), null));
243      }
244    } else {
245      defn.getPieces().add(gen.new Piece(null, i.getDefinition(), null));
246    }
247  }
248
249  public void genDefinitionLink(XhtmlNode x, QuestionnaireResponseItemComponent i, Resource src) {
250    // can we resolve the definition? 
251    String path = null;
252    String d = i.getDefinition();
253    if (d.contains("#")) {
254      path = d.substring(d.indexOf("#")+1);
255      d = d.substring(0, d.indexOf("#"));
256    }
257    StructureDefinition sd = context.getWorker().fetchResource(StructureDefinition.class, d, src);
258    if (sd != null) {
259      String url = sd.getUserString("path");
260      if (url != null) {
261        x.ah(url+"#"+path).tx(path);          
262      } else {
263        x.tx(i.getDefinition());
264      }
265    } else {
266      x.tx(i.getDefinition());
267    }
268  }
269
270  private void addExpression(Piece p, Expression exp, String label, String url) {
271    XhtmlNode x = new XhtmlNode(NodeType.Element, "li").style("font-size: 11px");
272    p.addHtml(x);
273    x.ah(url).tx(label);
274    x.tx(": ");
275    x.code(exp.getExpression());
276  }
277
278  public boolean renderForm(XhtmlNode x, QuestionnaireResponse q) throws UnsupportedEncodingException, IOException {
279    boolean hasExt = false;
280//    XhtmlNode d = x.div();
281//    boolean hasPrefix = false;
282//    for (QuestionnaireItemComponent c : q.getItem()) {
283//      hasPrefix = hasPrefix || doesItemHavePrefix(c);
284//    }
285//    int i = 1;
286//    for (QuestionnaireItemComponent c : q.getItem()) {
287//      hasExt = renderFormItem(d, q, c, hasPrefix ? null : Integer.toString(i), 0) || hasExt;
288//      i++;
289//    }
290//    return hasExt; 
291//  }
292//
293//  private boolean doesItemHavePrefix(QuestionnaireItemComponent i) {
294//    if (i.hasPrefix()) {
295//      return true;
296//    }
297//    for (QuestionnaireItemComponent c : i.getItem()) {
298//      if (doesItemHavePrefix(c)) {
299//        return true;
300//      }
301//    }
302    return false;
303  }
304
305  public boolean renderForm(XhtmlNode x, ResourceWrapper q) throws UnsupportedEncodingException, IOException {
306    boolean hasExt = false;
307    XhtmlNode d = x.div();
308    d.tx("todo");
309//    boolean hasPrefix = false;
310//    for (QuestionnaireItemComponent c : q.getItem()) {
311//      hasPrefix = hasPrefix || doesItemHavePrefix(c);
312//    }
313//    int i = 1;
314//    for (QuestionnaireItemComponent c : q.getItem()) {
315//      hasExt = renderFormItem(d, q, c, hasPrefix ? null : Integer.toString(i), 0) || hasExt;
316//      i++;
317//    }
318//    return hasExt; 
319//  }
320//
321//  private boolean doesItemHavePrefix(QuestionnaireItemComponent i) {
322//    if (i.hasPrefix()) {
323//      return true;
324//    }
325//    for (QuestionnaireItemComponent c : i.getItem()) {
326//      if (doesItemHavePrefix(c)) {
327//        return true;
328//      }
329//    }
330    return hasExt;
331  }
332
333//  private boolean renderFormItem(XhtmlNode x, QuestionnaireResponse q, QuestionnaireItemComponent i, String pfx, int indent) throws IOException {
334//    boolean hasExt = false;
335//    XhtmlNode d = x.div().style("width: "+Integer.toString(900-indent*10)+"px; border-top: 1px #eeeeee solid");
336//    if (indent > 0) {
337//      d.style("margin-left: "+Integer.toString(10*indent)+"px");
338//    }
339//    XhtmlNode display = d.div().style("display: inline-block; width: "+Integer.toString(500-indent*10)+"px");
340//    XhtmlNode details = d.div().style("border: 1px #ccccff solid; padding: 2px; display: inline-block; background-color: #fefce7; width: 380px");
341//    XhtmlNode p = display.para();
342//    if (i.getType() == QuestionnaireItemType.GROUP) {
343//      p = p.b();
344//    }
345//    if (i.hasPrefix()) {
346//      p.tx(i.getPrefix());
347//      p.tx(": ");
348//    }
349//    p.span(null, "linkId: "+i.getLinkId()).tx(i.getText());
350//    if (i.getRequired()) {
351//      p.span("color: red", "Mandatory").tx("*");
352//    }
353//
354//    XhtmlNode input = null;
355//    switch (i.getType()) {
356//    case STRING:
357//      p.tx(" ");
358//      input = p.input(i.getLinkId(), "text", i.getType().getDisplay(), 60);
359//      break;
360//    case ATTACHMENT:
361//      break;
362//    case BOOLEAN:
363//      p.tx(" ");
364//      input = p.input(i.getLinkId(), "checkbox", i.getType().getDisplay(), 1);
365//      break;
366//    case CHOICE:
367//      input = p.select(i.getLinkId());
368//      listOptions(q, i, input);
369//      break;
370//    case DATE:
371//      p.tx(" ");
372//      input = p.input(i.getLinkId(), "date", i.getType().getDisplay(), 10);
373//      break;
374//    case DATETIME:
375//      p.tx(" ");
376//      input = p.input(i.getLinkId(), "datetime-local", i.getType().getDisplay(), 25);
377//      break;
378//    case DECIMAL:
379//      p.tx(" ");
380//      input = p.input(i.getLinkId(), "number", i.getType().getDisplay(), 15);
381//      break;
382//    case DISPLAY:
383//      break;
384//    case GROUP:
385//      
386//      break;
387//    case INTEGER:
388//      p.tx(" ");
389//      input = p.input(i.getLinkId(), "number", i.getType().getDisplay(), 10);
390//      break;
391//    case OPENCHOICE:
392//      break;
393//    case QUANTITY:
394//      p.tx(" ");
395//      input = p.input(i.getLinkId(), "number", "value", 15);
396//      p.tx(" ");
397//      input = p.input(i.getLinkId(), "unit", "unit", 10);
398//      break;
399//    case QUESTION:
400//      break;
401//    case REFERENCE:
402//      break;
403//    case TEXT:
404//      break;
405//    case TIME:
406//      break;
407//    case URL:
408//      break;
409//    default:
410//      break;
411//    }
412//    if (input != null) {
413//      if (i.getReadOnly()) {
414//        input.attribute("readonly", "1");
415//        input.style("background-color: #eeeeee");
416//      }
417//    }
418//    
419////  if (i.hasExtension(" http://hl7.org/fhir/StructureDefinition/QuestionnaireResponse-choiceOrientation")) {
420////  String code = ToolingExtensions.readStringExtension(i,  "http://hl7.org/fhir/StructureDefinition/QuestionnaireResponse-choiceOrientation");
421////  flags.addPiece(gen.new Piece("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-observationLinkPeriod", null, "Orientation: "+code).addHtml(new XhtmlNode(NodeType.Element, "img").attribute("alt", "icon").attribute("src", Utilities.path(context.getLocalPrefix(), "icon-qi-"+code+".png"))));
422////}
423//
424//    
425//    XhtmlNode ul = details.ul();
426//    boolean hasFlag = false; 
427//    XhtmlNode flags = item(ul, "Flags");
428//    item(ul, "linkId", i.getLinkId());
429//    
430//    if (ToolingExtensions.readBoolExtension(i, "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-isSubject")) {
431//      hasFlag = true;
432//      flags.ah(getSDCLink("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-isSubject", "Can change the subject of the QuestionnaireResponse").img(Utilities.path(context.getLocalPrefix(), "icon-qi-subject.png"));
433//    }
434//    if (ToolingExtensions.readBoolExtension(i, "http://hl7.org/fhir/StructureDefinition/QuestionnaireResponse-hidden")) {
435//      hasFlag = true;
436//      flags.ah(Utilities.pathURL(context.getLink(KnownLinkType.SPEC), "extension-QuestionnaireResponse-hidden.html"), "Is a hidden item").img(Utilities.path(context.getLocalPrefix(), "icon-qi-hidden.png"));
437//      d.style("background-color: #eeeeee");
438//    }
439//    if (ToolingExtensions.readBoolExtension(i, "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-optionalDisplay")) {
440//      hasFlag = true;
441//      flags.ah(getSDCLink("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-optionalDisplay", "Is optional to display").img(Utilities.path(context.getLocalPrefix(), "icon-qi-optional.png"));
442//    }
443//    if (i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-observationLinkPeriod")) {
444//      hasFlag = true;
445//      flags.ah(getSDCLink("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-observationLinkPeriod", "Is linked to an observation").img(Utilities.path(context.getLocalPrefix(), "icon-qi-observation.png"));
446//    }
447//    if (i.hasExtension(" http://hl7.org/fhir/StructureDefinition/QuestionnaireResponse-displayCategory")) {
448//      CodeableConcept cc = i.getExtensionByUrl("http://hl7.org/fhir/StructureDefinition/QuestionnaireResponse-displayCategory").getValueCodeableConcept();
449//      String code = cc.getCode("http://hl7.org/fhir/QuestionnaireResponse-display-category");
450//      hasFlag = true;
451//      flags.ah(getSDCLink("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-displayCategory", "Category: "+code).img(Utilities.path(context.getLocalPrefix(), "icon-qi-"+code+".png"));
452//    }
453//
454//    if (i.hasMaxLength()) {
455//      item(ul, "Max Length", Integer.toString(i.getMaxLength()));
456//    }
457//    if (i.hasDefinition()) {
458//      genDefinitionLink(item(ul, "Definition"), i);      
459//    }
460//    if (i.hasEnableWhen()) {
461//      item(ul, "Enable When", "todo");
462//    }
463//    if (i.hasAnswerValueSet()) {
464//      XhtmlNode ans = item(ul, "Answers");
465//      if (i.getAnswerValueSet().startsWith("#")) {
466//        ValueSet vs = (ValueSet) q.getContained(i.getAnswerValueSet().substring(1));
467//        if (vs == null) {
468//          ans.tx(i.getAnswerValueSet());                    
469//        } else {
470//          ans.ah(vs.getUserString("path")).tx(vs.present());                              
471//        }
472//      } else {
473//        ValueSet vs = context.getWorker().fetchResource(ValueSet.class, i.getAnswerValueSet());
474//        if (vs == null  || !vs.hasUserData("path")) {
475//          ans.tx(i.getAnswerValueSet());                    
476//        } else {
477//          ans.ah(vs.getUserString("path")).tx(vs.present());                              
478//        }             
479//      }
480//    }
481//    if (i.hasAnswerOption()) {
482//      item(ul, "Answers", Integer.toString(i.getAnswerOption().size())+" "+Utilities.pluralize("option", i.getAnswerOption().size()), context.getDefinitionsTarget()+"#item."+i.getLinkId());
483//    }
484//    if (i.hasInitial()) {
485//      XhtmlNode vi = item(ul, "Initial Values");
486//      boolean first = true;
487//      for (QuestionnaireItemInitialComponent v : i.getInitial()) {
488//        if (first) first = false; else vi.tx(", ");
489//        if (v.getValue().isPrimitive()) {
490//          vi.tx(v.getValue().primitiveValue());
491//        } else {
492//          vi.tx("{todo}");          
493//        }
494//      }
495//    }
496//    if (!hasFlag) {
497//      ul.remove(flags);
498//    }
499////    if (i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-enableWhenExpression") || i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-itemContext") || i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-calculatedExpression") || i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-contextExpression") || i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-candidateExpression") || i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-initialExpression")) {
500////      if (!defn.getPieces().isEmpty()) defn.addPiece(gen.new Piece("br"));
501////      defn.getPieces().add(gen.new Piece(null, "Expressions: ", null));
502////      Piece p = gen.new Piece("ul");
503////      defn.getPieces().add(p);
504////      for (Extension e : i.getExtensionsByUrl("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-initialExpression")) {
505////        addExpression(p, e.getValueExpression(), "Initial Value", "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-initialExpression");
506////      }
507////      for (Extension e : i.getExtensionsByUrl("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-contextExpression")) {
508////        addExpression(p, e.getValueExpression(), "Context", "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-contextExpression");
509////      }
510////      for (Extension e : i.getExtensionsByUrl("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-itemContext")) {
511////        addExpression(p, e.getValueExpression(), "Item Context", "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-itemContext");
512////      }
513////      for (Extension e : i.getExtensionsByUrl("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-enableWhenExpression")) {
514////        addExpression(p, e.getValueExpression(), "Enable When", "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-enableWhenExpression");
515////      }
516////      for (Extension e : i.getExtensionsByUrl("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-calculatedExpression")) {
517////        addExpression(p, e.getValueExpression(), "Calculated Value", "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-calculatedExpression");
518////      }
519////      for (Extension e : i.getExtensionsByUrl("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-candidateExpression")) {
520////        addExpression(p, e.getValueExpression(), "Candidates", "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-candidateExpression");
521////      } 
522////    }
523////
524//
525//    int t = 1;
526//    for (QuestionnaireItemComponent c : i.getItem()) {
527//      hasExt = renderFormItem(x, q, c, pfx == null ? null : pfx+"."+Integer.toString(t), indent+1) || hasExt;
528//      t++;
529//    }
530//    return hasExt; 
531//  }
532//
533//  private void item(XhtmlNode ul, String name, String value, String valueLink) {
534//    if (!Utilities.noString(value)) {
535//      ul.li().style("font-size: 10px").ah(valueLink).tx(name+": "+value);
536//    }
537//  }
538//
539//  private void item(XhtmlNode ul, String name, String value) {
540//    if (!Utilities.noString(value)) {
541//      ul.li().style("font-size: 10px").tx(name+": "+value);
542//    }
543//  }
544//  private XhtmlNode item(XhtmlNode ul, String name) {
545//    XhtmlNode li = ul.li();
546//    li.style("font-size: 10px").tx(name+": ");
547//    return li;
548//  }
549//
550//
551//  private void listOptions(QuestionnaireResponse q, QuestionnaireItemComponent i, XhtmlNode select) {
552//    if (i.hasAnswerValueSet()) {
553//      ValueSet vs = null;
554//      if (i.getAnswerValueSet().startsWith("#")) {
555//        vs = (ValueSet) q.getContained(i.getAnswerValueSet().substring(1)).copy();
556//        if (vs != null && !vs.hasUrl()) {
557//          vs.setUrl("urn:uuid:"+UUID.randomUUID().toString().toLowerCase());
558//        }
559//      } else {
560//        vs = context.getContext().fetchResource(ValueSet.class, i.getAnswerValueSet());
561//      }
562//      if (vs != null) {
563//        ValueSetExpansionOutcome exp = context.getContext().expandVS(vs, true, false);
564//        if (exp.getValueset() != null) {
565//          for (ValueSetExpansionContainsComponent cc : exp.getValueset().getExpansion().getContains()) {
566//            select.option(cc.getCode(), cc.hasDisplay() ? cc.getDisplay() : cc.getCode(), false);    
567//          }
568//          return;
569//        }
570//      }
571//    } else if (i.hasAnswerOption()) {
572//      
573//    } 
574//    select.option("a", "??", false);    
575//  }
576//
577//  public String display(Resource dr) throws UnsupportedEncodingException, IOException {
578//    return display((QuestionnaireResponse) dr);
579//  }
580//
581//  public String display(QuestionnaireResponse q) throws UnsupportedEncodingException, IOException {
582//    return "QuestionnaireResponse "+q.present();
583//  }
584// 
585  private boolean renderLinks(XhtmlNode x, QuestionnaireResponse q) {
586    x.para().tx("Try this QuestionnaireResponse out:");
587    XhtmlNode ul = x.ul();
588    ul.li().ah("http://todo.nlm.gov/path?mode=ig&src="+Utilities.pathURL(context.getLink(KnownLinkType.SELF), "package.tgz")+"&q="+q.getId()+".json").tx("NLM Forms Library");
589    return false;
590  }
591
592  private boolean renderLinks(XhtmlNode x, ResourceWrapper q) {
593    x.para().tx("Try this QuestionnaireResponse out:");
594    XhtmlNode ul = x.ul();
595    ul.li().ah("http://todo.nlm.gov/path?mode=ig&src="+Utilities.pathURL(context.getLink(KnownLinkType.SELF), "package.tgz")+"&q="+q.getId()+".json").tx("NLM Forms Library");
596    return false;
597  }
598
599//  private boolean renderDefns(XhtmlNode x, QuestionnaireResponse q) throws IOException {
600//    XhtmlNode tbl = x.table("dict");
601//    boolean ext = false;
602//    ext = renderRootDefinition(tbl, q, new ArrayList<>()) || ext;
603//    for (QuestionnaireItemComponent qi : q.getItem()) {
604//      ext = renderDefinition(tbl, q, qi, new ArrayList<>()) || ext;
605//    }
606//    return ext;
607//  }
608//
609//  private boolean renderRootDefinition(XhtmlNode tbl, QuestionnaireResponse q, List<QuestionnaireItemComponent> parents) throws IOException {
610//    boolean ext = false;
611//    XhtmlNode td = tbl.tr().td("structure").colspan("2").span(null, null).attribute("class", "self-link-parent");
612//    td.an(q.getId());
613//    td.img(Utilities.path(context.getLocalPrefix(), "icon_q_root.gif"));
614//    td.tx(" QuestionnaireResponse ");
615//    td.b().tx(q.getId());
616//    
617//    // general information
618//    defn(tbl, "URL", q.getUrl());
619//    defn(tbl, "Version", q.getVersion());
620//    defn(tbl, "Name", q.getName());
621//    defn(tbl, "Title", q.getTitle());
622//    if (q.hasDerivedFrom()) {
623//      td = defn(tbl, "Derived From");
624//      boolean first = true;
625//      for (CanonicalType c : q.getDerivedFrom()) {
626//        if (first) first = false; else td.tx(", ");
627//        td.tx(c.asStringValue()); // todo: make these a reference
628//      }
629//    }
630//    defn(tbl, "Status", q.getStatus().getDisplay());
631//    defn(tbl, "Experimental", q.getExperimental());
632//    defn(tbl, "Publication Date", q.getDateElement().primitiveValue());
633//    defn(tbl, "Approval Date", q.getApprovalDateElement().primitiveValue());
634//    defn(tbl, "Last Review Date", q.getLastReviewDateElement().primitiveValue());
635//    if (q.hasEffectivePeriod()) {
636//      renderPeriod(defn(tbl, "Effective Period"), q.getEffectivePeriod());
637//    }
638//    
639//    if (q.hasSubjectType()) {
640//      td = defn(tbl, "Subject Type");
641//      boolean first = true;
642//      for (CodeType c : q.getSubjectType()) {
643//        if (first) first = false; else td.tx(", ");
644//        td.tx(c.asStringValue());
645//      }
646//    }
647//    defn(tbl, "Description", q.getDescription());
648//    defn(tbl, "Purpose", q.getPurpose());
649//    defn(tbl, "Copyright", q.getCopyright());
650//    if (q.hasCode()) {
651//      td = defn(tbl, Utilities.pluralize("Code", q.getCode().size()));
652//      boolean first = true;
653//      for (Coding c : q.getCode()) {
654//        if (first) first = false; else td.tx(", ");
655//        renderCodingWithDetails(td,  c);
656//      }
657//    }
658//    return false;
659//  }
660  
661//  private boolean renderDefinition(XhtmlNode tbl, QuestionnaireResponse q, QuestionnaireItemComponent qi, List<QuestionnaireItemComponent> parents) throws IOException {
662//    boolean ext = false;
663//    XhtmlNode td = tbl.tr().td("structure").colspan("2").span(null, null).attribute("class", "self-link-parent");
664//    td.an("item."+qi.getLinkId());
665//    for (QuestionnaireItemComponent p : parents) {
666//      td.ah("#item."+p.getLinkId()).img(Utilities.path(context.getLocalPrefix(), "icon_q_item.png"));
667//      td.tx(" > ");
668//    }
669//    td.img(Utilities.path(context.getLocalPrefix(), "icon_q_item.png"));
670//    td.tx(" Item ");
671//    td.b().tx(qi.getLinkId());
672//    
673//    // general information
674//    defn(tbl, "Link Id", qi.getLinkId());
675//    defn(tbl, "Prefix", qi.getPrefix());
676//    defn(tbl, "Text", qi.getText());
677//    defn(tbl, "Type", qi.getType().getDisplay());
678//    defn(tbl, "Required", qi.getRequired(), true);
679//    defn(tbl, "Repeats", qi.getRepeats(), true);
680//    defn(tbl, "Read Only", qi.getReadOnly(), false);
681//    if (ToolingExtensions.readBoolExtension(qi, "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-isSubject")) {
682//      defn(tbl, "Subject", "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-isSubject", "This element changes who the subject of the question is", null);
683//    }
684//    
685//    // content control
686//    defn(tbl, "Max Length", qi.getMaxLength());
687//    if (qi.hasAnswerValueSet()) {
688//      defn(tbl, "Value Set", qi.getDefinition(), context.getWorker().fetchResource(ValueSet.class,  qi.getAnswerValueSet()));
689//    }
690//    if (qi.hasAnswerOption()) {
691//      XhtmlNode tr = tbl.tr();
692//      tr.td().tx("Allowed Answers");
693//      XhtmlNode ul = tr.td().ul();
694//      for (QuestionnaireItemAnswerOptionComponent ans : qi.getAnswerOption()) {
695//        XhtmlNode li = ul.li();
696//        render(li, ans.getValue());
697//        if (ans.getInitialSelected()) {
698//          li.tx(" (initially selected)");
699//        }
700//      }      
701//    }
702//    if (qi.hasInitial()) {
703//      XhtmlNode tr = tbl.tr();
704//      tr.td().tx(Utilities.pluralize("Initial Answer", qi.getInitial().size()));
705//      if (qi.getInitial().size() == 1) {
706//        render(tr.td(), qi.getInitialFirstRep().getValue());
707//      } else {
708//        XhtmlNode ul = tr.td().ul();
709//        for (QuestionnaireItemInitialComponent ans : qi.getInitial()) {
710//          XhtmlNode li = ul.li();
711//          render(li, ans.getValue());
712//        }
713//      }      
714//    }
715//
716//    // appearance 
717//    if (qi.hasExtension(" http://hl7.org/fhir/StructureDefinition/QuestionnaireResponse-displayCategory")) {
718//      XhtmlNode tr = tbl.tr();
719//      tr.td().ah("http://hl7.org/fhir/StructureDefinition/QuestionnaireResponse-displayCategory").tx("Display Category");
720//      render(tr.td(), qi.getExtensionByUrl("http://hl7.org/fhir/StructureDefinition/QuestionnaireResponse-displayCategory").getValue());
721//    }
722//    if (ToolingExtensions.readBoolExtension(qi, "http://hl7.org/fhir/StructureDefinition/QuestionnaireResponse-hidden")) {
723//      defn(tbl, "Hidden Item", "http://hl7.org/fhir/StructureDefinition/QuestionnaireResponse-displayCategory", "This item is a hidden question", null);
724//    }
725//    if (ToolingExtensions.readBoolExtension(qi, "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-optionalDisplay")) {
726//      defn(tbl, "Hidden Item", "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-optionalDisplay", "This item is optional to display", null);
727//    }
728//    
729//    // formal definitions
730//    if (qi.hasDefinition()) {
731//      genDefinitionLink(defn(tbl, "Definition"), qi);
732//    }
733//      
734//    if (qi.hasCode()) {
735//      XhtmlNode tr = tbl.tr();
736//      tr.td().tx(Utilities.pluralize("Code", qi.getCode().size()));
737//      XhtmlNode ul = tr.td().ul();
738//      for (Coding c : qi.getCode()) {
739//        renderCodingWithDetails(ul.li(), c);
740//      }
741//    }
742//    if (qi.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-observationLinkPeriod")) {
743//      XhtmlNode tr = tbl.tr();
744//      tr.td().ah(getSDCLink("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-observationLinkPeriod").tx("Observation Link Period");
745//      render(tr.td(), qi.getExtensionByUrl("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-observationLinkPeriod").getValue());
746//    }
747//    
748//    // dynamic management
749//    if (qi.hasEnableWhen()) {
750//      XhtmlNode tr = tbl.tr();
751//      tr.td().tx("Enable When");
752//      td = tr.td();
753//      if (qi.getEnableWhen().size() == 1) {
754//        renderEnableWhen(td, qi.getEnableWhen().get(0));
755//      } else {
756//        td.tx(qi.getEnableBehavior().getDisplay()+" are true:");
757//        XhtmlNode ul = td.ul();
758//        for (QuestionnaireItemEnableWhenComponent ew : qi.getEnableWhen()) {
759//          renderEnableWhen(ul.li(), ew);
760//        }
761//      }      
762//    }
763//    
764//    
765//    // other stuff
766//    
767//
768//    
769//    List<QuestionnaireItemComponent> curr = new ArrayList<>();
770//    curr.addAll(parents);
771//    curr.add(qi);
772//    for (QuestionnaireItemComponent qic : qi.getItem()) {
773//      ext = renderDefinition(tbl, q, qic, curr) || ext;
774//    }
775//    return ext;
776//  }
777//
778//  private void defn(XhtmlNode tbl, String name, String url, Resource res) throws UnsupportedEncodingException, IOException {
779//    if (res != null && res.hasUserData("path")) {
780//      defn(tbl, "Definition", RendererFactory.factory(res, context).display(res), res.getUserString("path"));
781//    } else if (Utilities.isAbsoluteUrl(url)) {
782//      defn(tbl, "Definition", url, url);
783//    } {
784//      defn(tbl, "Definition", url);
785//    }
786// 
787//  }
788//
789//  private void renderEnableWhen(XhtmlNode x, QuestionnaireItemEnableWhenComponent ew) {
790//    x.ah("#item."+ew.getQuestion()).tx(ew.getQuestion());
791//    x.tx(" ");
792//    x.tx(ew.getOperator().toCode());
793//    x.tx(" ");
794//    x.tx(display(ew.getAnswer()));
795//  }
796//
797//  private XhtmlNode defn(XhtmlNode tbl, String name) {
798//    XhtmlNode tr = tbl.tr();
799//    tr.td().tx(name);
800//    return tr.td();
801//  }
802//  
803//  private void defn(XhtmlNode tbl, String name, int value) {
804//    if (value > 0) {
805//      XhtmlNode tr = tbl.tr();
806//      tr.td().tx(name);
807//      tr.td().tx(value);
808//    }    
809//  }
810// 
811//  
812//  private void defn(XhtmlNode tbl, String name, boolean value) {
813//    XhtmlNode tr = tbl.tr();
814//    tr.td().tx(name);
815//    tr.td().tx(Boolean.toString(value));
816//  }
817// 
818//  private void defn(XhtmlNode tbl, String name, String value) {
819//    if (!Utilities.noString(value)) {
820//      XhtmlNode tr = tbl.tr();
821//      tr.td().tx(name);
822//      tr.td().tx(value);
823//    }    
824//  }
825//  
826//  private void defn(XhtmlNode tbl, String name, String value, String url) {
827//    if (!Utilities.noString(value)) {
828//      XhtmlNode tr = tbl.tr();
829//      tr.td().tx(name);
830//      tr.td().ah(url).tx(value);
831//    }    
832//  }
833//
834//  private void defn(XhtmlNode tbl, String name, String nurl, String value, String url) {
835//    if (!Utilities.noString(value)) {
836//      XhtmlNode tr = tbl.tr();
837//      tr.td().ah(nurl).tx(name);
838//      if (url != null) {
839//        tr.td().ah(url).tx(value);
840//      } else {
841//        tr.td().tx(value);
842//      }
843//    }    
844//  }
845//
846//  private void defn(XhtmlNode tbl, String name, boolean value, boolean ifFalse) {
847//    if (ifFalse || value) {
848//      XhtmlNode tr = tbl.tr();
849//      tr.td().tx(name);
850//      tr.td().tx(Boolean.toString(value));
851//    }    
852//  }
853
854
855  @Override
856  public String display(Resource r) throws UnsupportedEncodingException, IOException {
857    return "todo";
858  }
859
860  @Override
861  public String display(ResourceWrapper r) throws UnsupportedEncodingException, IOException {
862    return "Not done yet";
863  }
864
865}