001package org.hl7.fhir.r5.renderers;
002
003import java.io.IOException;
004import java.io.UnsupportedEncodingException;
005import java.util.Collection;
006import java.util.HashMap;
007import java.util.HashSet;
008import java.util.List;
009import java.util.Map;
010import java.util.Set;
011
012import org.hl7.fhir.exceptions.DefinitionException;
013import org.hl7.fhir.exceptions.FHIRException;
014import org.hl7.fhir.exceptions.FHIRFormatError;
015import org.hl7.fhir.r5.model.CodeSystem;
016import org.hl7.fhir.r5.model.ConceptMap;
017import org.hl7.fhir.r5.model.ConceptMap.ConceptMapGroupComponent;
018import org.hl7.fhir.r5.model.ConceptMap.SourceElementComponent;
019import org.hl7.fhir.r5.model.DataType;
020import org.hl7.fhir.r5.model.Enumeration;
021import org.hl7.fhir.r5.model.Enumerations.ConceptMapRelationship;
022import org.hl7.fhir.r5.model.IdType;
023import org.hl7.fhir.r5.model.OperationDefinition;
024import org.hl7.fhir.r5.model.Resource;
025import org.hl7.fhir.r5.model.StringType;
026import org.hl7.fhir.r5.model.StructureDefinition;
027import org.hl7.fhir.r5.model.StructureMap;
028import org.hl7.fhir.r5.model.StructureMap.StructureMapGroupComponent;
029import org.hl7.fhir.r5.model.StructureMap.StructureMapGroupInputComponent;
030import org.hl7.fhir.r5.model.StructureMap.StructureMapGroupRuleComponent;
031import org.hl7.fhir.r5.model.StructureMap.StructureMapGroupRuleDependentComponent;
032import org.hl7.fhir.r5.model.StructureMap.StructureMapGroupRuleSourceComponent;
033import org.hl7.fhir.r5.model.StructureMap.StructureMapGroupRuleTargetComponent;
034import org.hl7.fhir.r5.model.StructureMap.StructureMapGroupRuleTargetParameterComponent;
035import org.hl7.fhir.r5.model.StructureMap.StructureMapStructureComponent;
036import org.hl7.fhir.r5.model.StructureMap.StructureMapTargetListMode;
037import org.hl7.fhir.r5.model.StructureMap.StructureMapTransform;
038import org.hl7.fhir.r5.model.UriType;
039import org.hl7.fhir.r5.renderers.utils.RenderingContext;
040import org.hl7.fhir.r5.renderers.utils.ResourceWrapper;
041import org.hl7.fhir.r5.utils.EOperationOutcome;
042import org.hl7.fhir.r5.utils.structuremap.StructureMapUtilities;
043import org.hl7.fhir.utilities.Utilities;
044import org.hl7.fhir.utilities.VersionUtilities;
045import org.hl7.fhir.utilities.xhtml.XhtmlNode;
046
047public class StructureMapRenderer extends TerminologyRenderer {
048
049  public StructureMapRenderer(RenderingContext context) { 
050    super(context); 
051  } 
052 
053  @Override
054  public void buildNarrative(RenderingStatus status, XhtmlNode x, ResourceWrapper r) throws FHIRFormatError, DefinitionException, IOException, FHIRException, EOperationOutcome {
055    if (r.isDirect()) {
056      renderResourceTechDetails(r, x);
057      genSummaryTable(status, x, (StructureMap) r.getBase());
058      renderMap(status, x.pre("fml"), (StructureMap) r.getBase());      
059    } else {
060      // the intention is to change this in the future
061      x.para().tx("StructureMapRenderer only renders native resources directly");
062    }
063  }
064  
065  
066  @Override
067  public String buildSummary(ResourceWrapper r) throws UnsupportedEncodingException, IOException {
068    return canonicalTitle(r);
069  }
070
071  
072  
073  private static final String COLOR_COMMENT = "green";
074  private static final String COLOR_METADATA = "#cc00cc";
075  private static final String COLOR_CONST = "blue";
076  private static final String COLOR_VARIABLE = "maroon";
077  private static final String COLOR_SYNTAX = "navy";
078  private static final boolean MULTIPLE_TARGETS_ONELINE = true;
079  private static final String COLOR_SPECIAL = "#b36b00";
080
081  public void renderMap(RenderingStatus status, XhtmlNode x, StructureMap map) {
082    
083    x.tx("\r\n");
084    if (VersionUtilities.isR5Plus(context.getContext().getVersion())) {
085      renderMetadata(x, "url", map.getUrlElement());
086      renderMetadata(x, "name", map.getNameElement());
087      renderMetadata(x, "title", map.getTitleElement());
088      renderMetadata(x, "status", map.getStatusElement());      
089      x.tx("\r\n");
090    } else {
091      x.b().tx("map");
092      x.color(COLOR_SYNTAX).tx(" \"");
093      x.tx(map.getUrl());
094      x.color(COLOR_SYNTAX).tx("\" = \"");
095      x.tx(Utilities.escapeJson(map.getName()));
096      x.color(COLOR_SYNTAX).tx("\"\r\n\r\n");
097      if (map.getDescription() != null) {
098        renderMultilineDoco(x, map.getDescription(), 0, null);
099        x.tx("\r\n");
100      }
101    }
102    renderConceptMaps(x, map);
103    renderUses(x, map);
104    renderImports(x, map);
105    for (StructureMapGroupComponent g : map.getGroup())
106      renderGroup(x, g);
107  }
108
109  private void renderMetadata(XhtmlNode x, String name, DataType value) {
110    if (!value.isEmpty()) {
111      renderMetadata(x, name, value, null);
112    }
113  }
114  
115  private void renderMetadata(XhtmlNode x, String name, DataType value, String def) {
116    String v = value.primitiveValue();
117    if (def == null || !def.equals(v)) {
118      XhtmlNode c = x.color(COLOR_METADATA);
119      c.tx("/// ");
120      c.b().tx(name);
121      c.tx(" = ");
122      if (Utilities.existsInList(v, "true", "false") || Utilities.isDecimal(v, true)) {
123        x.color(COLOR_CONST).tx(v);
124      } else {
125        x.color(COLOR_CONST).tx("'"+v+"'");
126      }
127      x.tx("\r\n");
128    }
129  }
130
131  private void renderConceptMaps(XhtmlNode x,StructureMap map) {
132    for (Resource r : map.getContained()) {
133      if (r instanceof ConceptMap) {
134        produceConceptMap(x, (ConceptMap) r);
135      }
136    }
137  }
138
139  private void produceConceptMap(XhtmlNode x,ConceptMap cm) {
140    if (cm.hasFormatCommentPre()) {
141      renderMultilineDoco(x, cm.getFormatCommentsPre(), 0, null);
142    }
143    x.b().tx("conceptmap");
144    x.color(COLOR_SYNTAX).tx(" \"");
145    x.tx(cm.getId());
146    x.color(COLOR_SYNTAX).tx("\" {\r\n");
147    Map<String, String> prefixesSrc = new HashMap<String, String>();
148    Map<String, String> prefixesTgt = new HashMap<String, String>();
149    char prefix = 's';
150    for (ConceptMapGroupComponent cg : cm.getGroup()) {
151      if (!prefixesSrc.containsKey(cg.getSource())) {
152        prefixesSrc.put(cg.getSource(), String.valueOf(prefix));
153        x.b().tx("  prefix ");
154        x.tx(""+prefix);
155        x.color(COLOR_SYNTAX).tx(" = \"");
156        CodeSystem cs = context.getContext().fetchResource(CodeSystem.class, cg.getSource());
157        if (cs != null && cs.hasWebPath()) {
158          x.ah(context.prefixLocalHref(cs.getWebPath()), cs.present()).tx(cg.getSource());
159        } else {
160          x.tx(cg.getSource());
161        }
162        x.color(COLOR_SYNTAX).tx("\"\r\n");
163        prefix++;
164      }
165      if (!prefixesTgt.containsKey(cg.getTarget())) {
166        prefixesTgt.put(cg.getTarget(), String.valueOf(prefix));
167        x.b().tx("  prefix ");
168        x.tx(""+prefix);
169        x.color(COLOR_SYNTAX).tx(" = \"");
170        CodeSystem cs = context.getContext().fetchResource(CodeSystem.class, cg.getTarget());
171        if (cs != null && cs.hasWebPath()) {
172          x.ah(context.prefixLocalHref(cs.getWebPath()), cs.present()).tx(cg.getTarget());
173        } else {
174          x.tx(""+cg.getTarget());
175        }
176        x.color(COLOR_SYNTAX).tx("\"\r\n");
177        prefix++;
178      }
179    }
180    x.tx("\r\n");
181    for (ConceptMapGroupComponent cg : cm.getGroup()) {
182      if (cg.hasUnmapped()) {
183        x.b().tx("  unmapped for ");
184        x.tx(prefixesSrc.get(cg.getSource()));
185        x.color(COLOR_SYNTAX).tx(" = ");
186        x.tx(cg.getUnmapped().getMode().toCode());
187        x.tx("\r\n");
188      }
189    }
190
191    for (ConceptMapGroupComponent cg : cm.getGroup()) {
192      if (cg.hasFormatCommentPre()) {
193        renderMultilineDoco(x, cg.getFormatCommentsPre(), 2, prefixesSrc.values());
194      }
195      for (SourceElementComponent ce : cg.getElement()) {
196        if (ce.hasFormatCommentPre()) {
197          renderMultilineDoco(x, ce.getFormatCommentsPre(), 2, prefixesSrc.values());
198        }
199
200        x.tx("  ");
201        x.tx(prefixesSrc.get(cg.getSource()));
202        x.color(COLOR_SYNTAX).tx(":");
203        if (Utilities.isToken(ce.getCode())) {
204          x.tx(ce.getCode());
205        } else {
206          x.tx("\"");
207          x.tx(ce.getCode());
208          x.tx("\"");
209        }
210        x.tx(" ");
211        x.b().tx(getChar(ce.getTargetFirstRep().getRelationship()));
212        x.tx(" ");
213        x.tx(prefixesTgt.get(cg.getTarget()));
214        x.color(COLOR_SYNTAX).tx(":");
215        if (Utilities.isToken(ce.getTargetFirstRep().getCode())) {
216          x.tx(ce.getTargetFirstRep().getCode());
217        } else {
218          x.color(COLOR_SYNTAX).tx("\"");
219          x.tx(ce.getTargetFirstRep().getCode());
220          x.color(COLOR_SYNTAX).tx("\"");
221        }
222        x.tx("\r\n");
223        if (ce.hasFormatCommentPost()) {
224          renderMultilineDoco(x, ce.getFormatCommentsPost(), 2, prefixesSrc.values());
225        }
226      }
227      if (cg.hasFormatCommentPost()) {
228        renderMultilineDoco(x, cg.getFormatCommentsPost(), 2, prefixesSrc.values());
229      }
230    }
231    if (cm.hasFormatCommentPost()) {
232      renderMultilineDoco(x, cm.getFormatCommentsPost(), 2, prefixesSrc.values());
233    }
234    x.color(COLOR_SYNTAX).tx("}\r\n\r\n");
235  }
236
237  private String getChar(ConceptMapRelationship relationship) {
238    switch (relationship) {
239      case RELATEDTO:
240        return "-";
241      case EQUIVALENT:
242        return "==";
243      case NOTRELATEDTO:
244        return "!=";
245      case SOURCEISNARROWERTHANTARGET:
246        return "<=";
247      case SOURCEISBROADERTHANTARGET:
248        return ">=";
249      default:
250        return "??";
251    }
252  }
253
254  private void renderUses(XhtmlNode x,StructureMap map) {
255    for (StructureMapStructureComponent s : map.getStructure()) {
256      x.b().tx("uses");
257      x.color(COLOR_SYNTAX).tx(" \"");
258      StructureDefinition sd = context.getContext().fetchResource(StructureDefinition.class, s.getUrl());
259      if (sd != null && sd.hasWebPath()) {
260        x.ah(context.prefixLocalHref(sd.getWebPath()), sd.present()).tx(s.getUrl());
261      } else {
262        x.tx(s.getUrl());
263      }
264      x.color(COLOR_SYNTAX).tx("\" ");
265      if (s.hasAlias()) {
266        x.b().tx("alias ");
267        x.tx(s.getAlias());
268        x.tx(" ");
269      }
270      x.b().tx("as ");
271      x.b().tx(s.getMode().toCode());
272      renderDoco(x, s.getDocumentation(), false, null);
273      x.tx("\r\n");
274    }
275    if (map.hasStructure())
276      x.tx("\r\n");
277  }
278
279  private void renderImports(XhtmlNode x,StructureMap map) {
280    for (UriType s : map.getImport()) {
281      x.b().tx("imports");
282      x.color(COLOR_SYNTAX).tx(" \"");
283      StructureMap m = context.getContext().fetchResource(StructureMap.class, s.getValue());
284      if (m != null) {
285        x.ah(context.prefixLocalHref(m.getWebPath()), m.present()).tx(s.getValue());
286      } else {
287        x.tx(s.getValue());
288      }
289      x.color(COLOR_SYNTAX).tx("\"\r\n");
290    }
291    if (map.hasImport())
292      x.tx("\r\n");
293  }
294
295  private void renderGroup(XhtmlNode x,StructureMapGroupComponent g) {
296    Collection<String> tokens = scanVariables(g, null);
297    if (g.hasFormatCommentPre()) {
298      renderMultilineDoco(x, g.getFormatCommentsPre(), 0, tokens);
299    }
300    if (g.hasDocumentation()) {
301      renderMultilineDoco(x, g.getDocumentation(), 0, tokens);
302    }
303    x.b().tx("group ");
304    x.tx(g.getName());
305    x.color(COLOR_SYNTAX).tx("(");
306    boolean first = true;
307    for (StructureMapGroupInputComponent gi : g.getInput()) {
308      if (first)
309        first = false;
310      else
311        x.tx(", ");
312      x.b().tx(gi.getMode().toCode());
313      x.tx(" ");
314      x.color(COLOR_VARIABLE).tx(gi.getName());
315      if (gi.hasType()) {
316        x.color(COLOR_SYNTAX).tx(" : ");
317        x.tx(gi.getType());
318      }
319    }
320    x.color(COLOR_SYNTAX).tx(")");
321    if (g.hasExtends()) {
322      x.b().tx(" extends ");
323      String ref = resolveRuleReference(g.getExtendsElement());
324      if (ref != null) {
325        x.ah(context.prefixLocalHref(ref)).tx(g.getExtends()); 
326      } else {
327        x.tx(g.getExtends());
328      }
329    }
330
331    if (g.hasTypeMode()) {
332      switch (g.getTypeMode()) {
333        case TYPES:
334          x.b().tx(" <<types>>");
335          break;
336        case TYPEANDTYPES:
337          x.b().tx(" <<type+>>");
338          break;
339        default: // NONE, NULL
340      }
341    }
342    x.color(COLOR_SYNTAX).tx(" {\r\n");
343    for (StructureMapGroupRuleComponent r : g.getRule()) {
344      renderRule(x, g, r, 2);
345    }
346    if (g.hasFormatCommentPost()) {
347      renderMultilineDoco(x, g.getFormatCommentsPost(), 0, scanVariables(g, null));
348    }
349    x.color(COLOR_SYNTAX).tx("}\r\n\r\n");
350  }
351
352  private String resolveRuleReference(IdType idType) {
353    return null;
354  }
355
356  private void renderRule(XhtmlNode x, StructureMapGroupComponent g, StructureMapGroupRuleComponent r, int indent) {
357    Collection<String> tokens = scanVariables(g, r);
358    if (r.hasFormatCommentPre()) {
359      renderMultilineDoco(x, r.getFormatCommentsPre(), indent, tokens);
360    }
361    for (int i = 0; i < indent; i++)
362      x.tx(" ");
363    boolean canBeAbbreviated = checkisSimple(r);
364    {
365      boolean first = true;
366      for (StructureMapGroupRuleSourceComponent rs : r.getSource()) {
367        if (first)
368          first = false;
369        else
370          x.color(COLOR_SYNTAX).tx(", ");
371        renderSource(x, rs, canBeAbbreviated);
372      }
373    }
374    if (r.getTarget().size() > 1) {
375      x.color(COLOR_SYNTAX).b().tx(" -> ");
376      boolean first = true;
377      for (StructureMapGroupRuleTargetComponent rt : r.getTarget()) {
378        if (first)
379          first = false;
380        else
381          x.color(COLOR_SYNTAX).tx(", ");
382        if (MULTIPLE_TARGETS_ONELINE)
383          x.tx(" ");
384        else {
385          x.tx("\r\n");
386          for (int i = 0; i < indent + 4; i++)
387            x.tx(" ");
388        }
389        renderTarget(x, rt, false);
390      }
391    } else if (r.hasTarget()) {
392      x.color(COLOR_SYNTAX).b().tx(" -> ");
393      renderTarget(x, r.getTarget().get(0), canBeAbbreviated);
394    }
395    if (r.hasRule()) {
396      x.b().tx(" then");
397      x.color(COLOR_SYNTAX).tx(" {\r\n");
398      for (StructureMapGroupRuleComponent ir : r.getRule()) {
399        renderRule(x, g, ir, indent + 2);
400      }
401      for (int i = 0; i < indent; i++)
402        x.tx(" ");
403      x.color(COLOR_SYNTAX).tx("}");
404    } else {
405      if (r.hasDependent() && !canBeAbbreviated) {
406        x.b().tx(" then ");
407        boolean first = true;
408        for (StructureMapGroupRuleDependentComponent rd : r.getDependent()) {
409          if (first)
410            first = false;
411          else
412            x.color(COLOR_SYNTAX).tx(", ");
413          String ref = resolveRuleReference(rd.getNameElement());
414          if (ref != null) {
415            x.ah(context.prefixLocalHref(ref)).tx(rd.getName());
416          } else {
417            x.tx(rd.getName());
418          }
419          x.color(COLOR_SYNTAX).tx("(");
420          boolean ifirst = true;
421          for (StructureMapGroupRuleTargetParameterComponent rdp : rd.getParameter()) {
422            if (ifirst)
423              ifirst = false;
424            else
425              x.color(COLOR_SYNTAX).tx(", ");
426            renderTransformParam(x, rdp);
427          }
428          x.color(COLOR_SYNTAX).tx(")");
429        }
430      }
431    }
432    if (r.hasName()) {
433      String n = ntail(r.getName());
434      if (!n.startsWith("\""))
435        n = "\"" + n + "\"";
436      if (!matchesName(n, r.getSource())) {
437        x.tx(" ");
438        x.i().tx(n);
439      }
440    }
441    x.color(COLOR_SYNTAX).tx(";");
442    if (r.hasDocumentation()) {
443      renderDoco(x, r.getDocumentation(), false, null);
444    }
445    x.tx("\r\n");
446    if (r.hasFormatCommentPost()) {
447      renderMultilineDoco(x, r.getFormatCommentsPost(), indent, tokens);
448    }
449  }
450
451  private Collection<String> scanVariables(StructureMapGroupComponent g, StructureMapGroupRuleComponent r) {
452    Set<String> res = new HashSet<>();
453    for (StructureMapGroupInputComponent input : g.getInput()) {
454      res.add(input.getName());
455    }
456    if (r != null) {
457      for (StructureMapGroupRuleSourceComponent src : r.getSource()) {
458        if (src.hasVariable()) {
459          res.add(src.getVariable());
460        }
461      }
462    }
463    return res;
464  }
465
466  private boolean matchesName(String n, List<StructureMapGroupRuleSourceComponent> source) {
467    if (source.size() != 1)
468      return false;
469    if (!source.get(0).hasElement())
470      return false;
471    String s = source.get(0).getElement();
472    if (n.equals(s) || n.equals("\"" + s + "\""))
473      return true;
474    if (source.get(0).hasType()) {
475      s = source.get(0).getElement() + Utilities.capitalize(source.get(0).getType());
476      return n.equals(s) || n.equals("\"" + s + "\"");
477    }
478    return false;
479  }
480
481  private String ntail(String name) {
482    if (name == null)
483      return null;
484    if (name.startsWith("\"")) {
485      name = name.substring(1);
486      name = name.substring(0, name.length() - 1);
487    }
488    return "\"" + (name.contains(".") ? name.substring(name.lastIndexOf(".") + 1) : name) + "\"";
489  }
490
491  private boolean checkisSimple(StructureMapGroupRuleComponent r) {
492    return
493      (r.getSource().size() == 1 && r.getSourceFirstRep().hasElement() && r.getSourceFirstRep().hasVariable()) &&
494        (r.getTarget().size() == 1 && r.getTargetFirstRep().hasVariable() && (r.getTargetFirstRep().getTransform() == null || r.getTargetFirstRep().getTransform() == StructureMapTransform.CREATE) && r.getTargetFirstRep().getParameter().size() == 0) &&
495        (r.getDependent().size() == 0 || (r.getDependent().size() == 1 && StructureMapUtilities.DEF_GROUP_NAME.equals(r.getDependentFirstRep().getName()))) && (r.getRule().size() == 0);
496  }
497  
498  private void renderSource(XhtmlNode x,StructureMapGroupRuleSourceComponent rs, boolean abbreviate) {
499    x.tx(rs.getContext());
500    if (rs.getContext().equals("@search")) {
501      x.color(COLOR_SYNTAX).tx("(");
502      x.tx(rs.getElement());
503      x.color(COLOR_SYNTAX).tx(")");
504    } else if (rs.hasElement()) {
505      x.tx(".");
506      x.tx(rs.getElement());
507    }
508    if (rs.hasType()) {
509      x.color(COLOR_SYNTAX).tx(" : ");
510      x.tx(rs.getType());
511      if (rs.hasMin()) {
512        x.tx(" ");
513        x.tx(rs.getMin());
514        x.color(COLOR_SYNTAX).tx("..");
515        x.tx(rs.getMax());
516      }
517    }
518
519    if (rs.hasListMode()) {
520      x.tx(" ");
521      x.tx(rs.getListMode().toCode());
522    }
523    if (rs.hasDefaultValue()) {
524      x.b().tx(" default ");
525      x.tx("\"" + Utilities.escapeJson(rs.getDefaultValue()) + "\"");
526    }
527    if (!abbreviate && rs.hasVariable()) {
528      x.b().tx(" as ");
529      x.color(COLOR_VARIABLE).tx(rs.getVariable());
530    }
531    if (rs.hasCondition()) {
532      x.b().tx(" where ");
533      x.tx(rs.getCondition());
534    }
535    if (rs.hasCheck()) {
536      x.b().tx(" check ");
537      x.tx(rs.getCheck());
538    }
539    if (rs.hasLogMessage()) {
540      x.b().tx(" log ");
541      x.tx(rs.getLogMessage());
542    }
543  }
544  
545  private void renderTarget(XhtmlNode x,StructureMapGroupRuleTargetComponent rt, boolean abbreviate) {
546    if (rt.hasContext()) {
547      x.tx(rt.getContext());
548      if (rt.hasElement()) {
549        x.tx(".");
550        x.tx(rt.getElement());
551      }
552    }
553    if (!abbreviate && rt.hasTransform()) {
554      if (rt.hasContext())
555        x.tx(" = ");
556      if (rt.getTransform() == StructureMapTransform.COPY && rt.getParameter().size() == 1) {
557        renderTransformParam(x, rt.getParameter().get(0));
558      } else if (rt.getTransform() == StructureMapTransform.EVALUATE && rt.getParameter().size() == 1) {
559        x.color(COLOR_SYNTAX).tx("(");
560        x.tx(((StringType) rt.getParameter().get(0).getValue()).asStringValue());
561        x.color(COLOR_SYNTAX).tx(")");
562      } else if (rt.getTransform() == StructureMapTransform.EVALUATE && rt.getParameter().size() == 2) {
563        x.tx(rt.getTransform().toCode());
564        x.color(COLOR_SYNTAX).tx("(");
565        x.tx(((IdType) rt.getParameter().get(0).getValue()).asStringValue());
566        x.color(COLOR_SYNTAX).tx(", ");
567        x.tx(((StringType) rt.getParameter().get(1).getValue()).asStringValue());
568        x.color(COLOR_SYNTAX).tx(")");
569      } else {
570        x.b().tx(rt.getTransform().toCode());
571        x.color(COLOR_SYNTAX).tx("(");
572        boolean first = true;
573        for (StructureMapGroupRuleTargetParameterComponent rtp : rt.getParameter()) {
574          if (first)
575            first = false;
576          else
577            x.color(COLOR_SYNTAX).tx(", ");
578          renderTransformParam(x, rtp);
579        }
580        x.color(COLOR_SYNTAX).tx(")");
581      }
582    }
583    if (!abbreviate && rt.hasVariable()) {
584      x.b().tx(" as ");
585      x.color(COLOR_VARIABLE).tx(rt.getVariable());
586    }
587    for (Enumeration<StructureMapTargetListMode> lm : rt.getListMode()) {
588      x.tx(" ");
589      x.b().tx(lm.getValue().toCode());
590      if (lm.getValue() == StructureMapTargetListMode.SHARE) {
591        x.tx(" ");
592        x.b().tx(rt.getListRuleId());
593      }
594    }
595  }
596
597
598  private void renderTransformParam(XhtmlNode x,StructureMapGroupRuleTargetParameterComponent rtp) {
599    try {
600      if (rtp.hasValueBooleanType())
601        x.color(COLOR_CONST).tx(rtp.getValueBooleanType().asStringValue());
602      else if (rtp.hasValueDecimalType())
603        x.color(COLOR_CONST).tx(rtp.getValueDecimalType().asStringValue());
604      else if (rtp.hasValueIdType())
605        x.color(COLOR_VARIABLE).tx(rtp.getValueIdType().asStringValue());
606      else if (rtp.hasValueIntegerType())
607        x.color(COLOR_CONST).tx(rtp.getValueIntegerType().asStringValue());
608      else
609        x.color(COLOR_CONST).tx("'" + Utilities.escapeJava(rtp.getValueStringType().asStringValue()) + "'");
610    } catch (FHIRException e) {
611      e.printStackTrace();
612      x.tx("error!");
613    }
614  }
615
616  private void renderDoco(XhtmlNode x,String doco, boolean startLine, Collection<String> tokens) {
617    if (Utilities.noString(doco))
618      return;
619    if (!startLine) {
620      x.tx(" ");
621    }
622    boolean isClause = false;
623    String t = doco.trim().replace(" ", "");
624    if (tokens != null) {
625      for (String s : tokens) {
626        if (t.startsWith(s+":") || t.startsWith(s+".") || t.startsWith(s+"->")) {
627          isClause = true;
628          break;
629        }
630      }
631    }
632    if (isClause) {
633      XhtmlNode s= x.color(COLOR_SPECIAL);
634      s.setAttribute("title", formatPhrase(RenderingContext.MAP_DEFAULT_COMMENT));
635      s.tx("// ");
636      s.tx(doco.replace("\r\n", " ").replace("\r", " ").replace("\n", " "));      
637    } else {
638      x.color(COLOR_SYNTAX).tx("// ");
639      x.color(COLOR_COMMENT).tx(doco.replace("\r\n", " ").replace("\r", " ").replace("\n", " "));
640    }
641  }
642
643  private void renderMultilineDoco(XhtmlNode x,String doco, int indent, Collection<String> tokens) {
644    if (Utilities.noString(doco))
645      return;
646    String[] lines = doco.split("\\r?\\n");
647    for (String line : lines) {
648      for (int i = 0; i < indent; i++)
649        x.tx(" ");
650      renderDoco(x, line, true, tokens);
651      x.tx("\r\n");
652    }
653  }
654
655  private void renderMultilineDoco(XhtmlNode x, List<String> doco, int indent, Collection<String> tokens) {
656    for (String line : doco) {
657      for (int i = 0; i < indent; i++)
658        x.tx(" ");
659      renderDoco(x, line, true, tokens);
660      x.tx("\r\n");
661    }
662  }
663
664
665  public void describe(XhtmlNode x, OperationDefinition opd) {
666    x.tx(display(opd));
667  }
668
669  public String display(OperationDefinition opd) {
670    return opd.present();
671  }
672
673  @Override
674  public String display(Resource r) throws UnsupportedEncodingException, IOException {
675    return ((StructureMap) r).present();
676  }
677
678}