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