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