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