001package org.hl7.fhir.r5.renderers;
002
003import java.io.IOException;
004import java.util.ArrayList;
005import java.util.Collections;
006import java.util.List;
007import java.util.Map;
008
009import org.hl7.fhir.exceptions.DefinitionException;
010import org.hl7.fhir.exceptions.FHIRFormatError;
011import org.hl7.fhir.r5.model.CodeSystem;
012import org.hl7.fhir.r5.model.CodeSystem.CodeSystemContentMode;
013import org.hl7.fhir.r5.model.CodeSystem.CodeSystemFilterComponent;
014import org.hl7.fhir.r5.model.CodeSystem.ConceptDefinitionComponent;
015import org.hl7.fhir.r5.model.CodeSystem.ConceptDefinitionDesignationComponent;
016import org.hl7.fhir.r5.model.CodeSystem.ConceptPropertyComponent;
017import org.hl7.fhir.r5.model.CodeSystem.PropertyComponent;
018import org.hl7.fhir.r5.model.Coding;
019import org.hl7.fhir.r5.model.DomainResource;
020import org.hl7.fhir.r5.model.Enumeration;
021import org.hl7.fhir.r5.model.Extension;
022import org.hl7.fhir.r5.model.Resource;
023import org.hl7.fhir.r5.renderers.utils.RenderingContext;
024import org.hl7.fhir.r5.renderers.utils.Resolver.ResourceContext;
025import org.hl7.fhir.r5.terminologies.CodeSystemUtilities;
026import org.hl7.fhir.r5.terminologies.CodeSystemUtilities.CodeSystemNavigator;
027import org.hl7.fhir.r5.utils.ToolingExtensions;
028import org.hl7.fhir.utilities.Utilities;
029import org.hl7.fhir.utilities.xhtml.XhtmlNode;
030
031public class CodeSystemRenderer extends TerminologyRenderer {
032
033  public CodeSystemRenderer(RenderingContext context) {
034    super(context);
035  }
036
037  public CodeSystemRenderer(RenderingContext context, ResourceContext rcontext) {
038    super(context, rcontext);
039  }
040  
041
042  public boolean render(XhtmlNode x, Resource dr) throws FHIRFormatError, DefinitionException, IOException {
043    return render(x, (CodeSystem) dr);
044  }
045  
046  public boolean render(XhtmlNode x, CodeSystem cs) throws FHIRFormatError, DefinitionException, IOException {
047    boolean hasExtensions = false;
048
049    if (context.isHeader()) {
050      XhtmlNode h = x.h2();
051      h.addText(cs.hasTitle() ? cs.getTitle() : cs.getName());
052      addMarkdown(x, cs.getDescription());
053      if (cs.hasCopyright())
054        generateCopyright(x, cs );
055    }
056
057    generateProperties(x, cs);
058    generateFilters(x, cs);
059    List<UsedConceptMap> maps = new ArrayList<UsedConceptMap>();
060    hasExtensions = generateCodeSystemContent(x, cs, hasExtensions, maps);
061
062    return hasExtensions;
063  }
064
065  public void describe(XhtmlNode x, CodeSystem cs) {
066    x.tx(display(cs));
067  }
068
069  public String display(CodeSystem cs) {
070    return cs.present();
071  }
072  
073  private void generateFilters(XhtmlNode x, CodeSystem cs) {
074    if (cs.hasFilter()) {
075      x.para().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "Filters", getContext().getLang()));
076      XhtmlNode tbl = x.table("grid");
077      XhtmlNode tr = tbl.tr();
078      tr.td().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "Code", getContext().getLang()));
079      tr.td().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "Description", getContext().getLang()));
080      tr.td().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "operator", getContext().getLang()));
081      tr.td().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "Value", getContext().getLang()));
082      for (CodeSystemFilterComponent f : cs.getFilter()) {
083        tr = tbl.tr();
084        tr.td().tx(f.getCode());
085        tr.td().tx(f.getDescription());
086        XhtmlNode td = tr.td();
087        for (Enumeration<org.hl7.fhir.r5.model.Enumerations.FilterOperator> t : f.getOperator())
088          td.tx(t.asStringValue()+" ");
089        tr.td().tx(f.getValue());
090      }
091    }
092  }
093
094  private void generateProperties(XhtmlNode x, CodeSystem cs) {
095    if (cs.hasProperty()) {
096      boolean hasRendered = false;
097      boolean hasURI = false;
098      for (PropertyComponent p : cs.getProperty()) {
099        hasRendered = hasRendered || !p.getCode().equals(ToolingExtensions.getPresentation(p, p.getCodeElement()));
100        hasURI = hasURI || p.hasUri();
101      }
102      
103      x.para().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "Properties", getContext().getLang()));
104      XhtmlNode tbl = x.table("grid");
105      XhtmlNode tr = tbl.tr();
106      if (hasRendered) {
107        tr.td().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "Name", getContext().getLang()));        
108      }
109      tr.td().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "Code", getContext().getLang()));
110      if (hasURI) {
111        tr.td().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "URL", getContext().getLang()));
112      }
113      tr.td().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "Type", getContext().getLang()));
114      tr.td().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "Description", getContext().getLang()));
115      for (PropertyComponent p : cs.getProperty()) {
116        tr = tbl.tr();
117        if (hasRendered) {
118          tr.td().tx(ToolingExtensions.getPresentation(p, p.getCodeElement()));          
119        }
120        tr.td().tx(p.getCode());
121        if (hasURI) {
122          tr.td().tx(p.getUri());
123        }
124        tr.td().tx(p.hasType() ? p.getType().toCode() : "");
125        tr.td().tx(p.getDescription());
126      }
127    }
128  }
129
130  private boolean generateCodeSystemContent(XhtmlNode x, CodeSystem cs, boolean hasExtensions, List<UsedConceptMap> maps) throws FHIRFormatError, DefinitionException, IOException {
131    XhtmlNode p = x.para();
132    if (cs.getContent() == CodeSystemContentMode.COMPLETE)
133      p.tx(getContext().getWorker().translator().translateAndFormat("xhtml-gen-cs", getContext().getLang(), "This code system %s defines the following codes", cs.getUrl())+":");
134    else if (cs.getContent() == CodeSystemContentMode.EXAMPLE)
135      p.tx(getContext().getWorker().translator().translateAndFormat("xhtml-gen-cs", getContext().getLang(), "This code system %s defines some example codes", cs.getUrl())+":");
136    else if (cs.getContent() == CodeSystemContentMode.FRAGMENT )
137      p.tx(getContext().getWorker().translator().translateAndFormat("xhtml-gen-cs", getContext().getLang(), "This code system %s defines many codes, of which the following are a subset", cs.getUrl())+":");
138    else if (cs.getContent() == CodeSystemContentMode.NOTPRESENT ) {
139      p.tx(getContext().getWorker().translator().translateAndFormat("xhtml-gen-cs", getContext().getLang(), "This code system %s defines many codes, but they are not represented here", cs.getUrl()));
140      return false;
141    }
142    XhtmlNode t = x.table( "codes");
143    boolean definitions = false;
144    boolean commentS = false;
145    boolean deprecated = false;
146    boolean display = false;
147    boolean hierarchy = false;
148    boolean version = false;
149    boolean ignoreStatus = false;
150    boolean isSupplement = cs.getContent() == CodeSystemContentMode.SUPPLEMENT;
151    List<PropertyComponent> properties = new ArrayList<>();
152    for (PropertyComponent cp : cs.getProperty()) {
153      if (showPropertyInTable(cp)) {
154        boolean exists = false;
155        for (ConceptDefinitionComponent c : cs.getConcept()) {
156          exists = exists || conceptsHaveProperty(c, cp);
157        }
158        if (exists) {
159          properties.add(cp);
160          if ("status".equals(cp.getCode())) {
161            ignoreStatus = true;
162          }
163        }
164      }
165    }
166    for (ConceptDefinitionComponent c : cs.getConcept()) {
167      commentS = commentS || conceptsHaveComments(c);
168      deprecated = deprecated || conceptsHaveDeprecated(cs, c, ignoreStatus);
169      display = display || conceptsHaveDisplay(c);
170      version = version || conceptsHaveVersion(c);
171      hierarchy = hierarchy || c.hasConcept();
172      definitions = definitions || conceptsHaveDefinition(c);
173    }
174    CodeSystemNavigator csNav = new CodeSystemNavigator(cs);
175    hierarchy = hierarchy || csNav.isRestructure();
176    
177    List<String> langs = new ArrayList<>();
178    addMapHeaders(addTableHeaderRowStandard(t, hierarchy, display, definitions, commentS, version, deprecated, properties, null, null, false), maps);
179    for (ConceptDefinitionComponent c : csNav.getConcepts(null)) {
180      hasExtensions = addDefineRowToTable(t, c, 0, hierarchy, display, definitions, commentS, version, deprecated, maps, cs.getUrl(), cs, properties, csNav, langs, isSupplement) || hasExtensions;
181    }
182    if (langs.size() > 0) {
183      Collections.sort(langs);
184      x.para().b().tx("Additional Language Displays");
185      t = x.table( "codes");
186      XhtmlNode tr = t.tr();
187      tr.td().b().tx("Code");
188      for (String lang : langs)
189        tr.td().b().addText(describeLang(lang));
190      for (ConceptDefinitionComponent c : cs.getConcept()) {
191        addLanguageRow(c, t, langs);
192      }
193    }
194    return hasExtensions;
195  }
196
197  private boolean conceptsHaveDefinition(ConceptDefinitionComponent c) {
198    if (c.hasDefinition()) {
199      return true;
200    }
201    for (ConceptDefinitionDesignationComponent cd : c.getDesignation()) { 
202      if (cd.getUse().is("http://terminology.hl7.org/CodeSystem/designation-usage", "definition") && cd.hasLanguage() && !c.getDefinition().equalsIgnoreCase(cd.getValue())) {
203        return true;
204      }
205    }
206    for (ConceptDefinitionComponent g : c.getConcept()) {
207      if (conceptsHaveDefinition(g)) {
208        return true;
209      }
210    }
211    return false;
212  }
213
214  private boolean conceptsHaveProperty(ConceptDefinitionComponent c, PropertyComponent cp) {
215    if (CodeSystemUtilities.hasProperty(c, cp.getCode()))
216      return true;
217    for (ConceptDefinitionComponent g : c.getConcept())
218      if (conceptsHaveProperty(g,  cp))
219        return true;
220    return false;
221
222  }
223
224  private boolean showPropertyInTable(PropertyComponent cp) {
225    if (cp.hasCode()) {
226      if (cp.hasExtension(ToolingExtensions.EXT_RENDERED_VALUE)) {
227        return true;
228      }
229      if (cp.getCodeElement().hasExtension(ToolingExtensions.EXT_RENDERED_VALUE)) {
230        return true;
231      }
232      String uri = cp.getUri();
233      if (Utilities.noString(uri)){
234        return true; // do we always want to render properties in this case? Not sure...
235      }
236      String code = null;
237      if (uri.contains("#")) {
238        code = uri.substring(uri.indexOf("#")+1);
239        uri = uri.substring(0, uri.indexOf("#"));
240      }
241      if (Utilities.existsInList(uri, "http://hl7.org/fhir/concept-properties") || context.getCodeSystemPropList().contains(uri)) {
242        return true;
243      };
244      CodeSystem cs = getContext().getWorker().fetchCodeSystem(uri);
245      if (cs == null) {
246        return false;
247      }
248      return code == null ? false : CodeSystemUtilities.hasCode(cs, code);
249    }
250    return false;
251  }
252
253
254  private int countConcepts(List<ConceptDefinitionComponent> list) {
255    int count = list.size();
256    for (ConceptDefinitionComponent c : list)
257      if (c.hasConcept())
258        count = count + countConcepts(c.getConcept());
259    return count;
260  }
261  
262  private boolean conceptsHaveComments(ConceptDefinitionComponent c) {
263    if (ToolingExtensions.hasCSComment(c))
264      return true;
265    for (ConceptDefinitionComponent g : c.getConcept())
266      if (conceptsHaveComments(g))
267        return true;
268    return false;
269  }
270
271  private boolean conceptsHaveDisplay(ConceptDefinitionComponent c) {
272    if (c.hasDisplay())
273      return true;
274    for (ConceptDefinitionComponent g : c.getConcept())
275      if (conceptsHaveDisplay(g))
276        return true;
277    return false;
278  }
279
280  private boolean conceptsHaveVersion(ConceptDefinitionComponent c) {
281    if (c.hasUserData("cs.version.notes"))
282      return true;
283    for (ConceptDefinitionComponent g : c.getConcept())
284      if (conceptsHaveVersion(g))
285        return true;
286    return false;
287  }
288
289  private boolean conceptsHaveDeprecated(CodeSystem cs, ConceptDefinitionComponent c, boolean ignoreStatus) {
290    if (CodeSystemUtilities.isDeprecated(cs, c, ignoreStatus))
291      return true;
292    for (ConceptDefinitionComponent g : c.getConcept())
293      if (conceptsHaveDeprecated(cs, g, ignoreStatus))
294        return true;
295    return false;
296  }
297
298
299
300  private boolean addDefineRowToTable(XhtmlNode t, ConceptDefinitionComponent c, int level, boolean hasHierarchy, boolean hasDisplay, boolean hasDefinitions, boolean comment, boolean version, boolean deprecated, List<UsedConceptMap> maps, String system, CodeSystem cs, List<PropertyComponent> properties, CodeSystemNavigator csNav, List<String> langs, boolean isSupplement) throws FHIRFormatError, DefinitionException, IOException {
301    boolean hasExtensions = false;
302    XhtmlNode tr = t.tr();
303    XhtmlNode td = tr.td();
304    if (hasHierarchy) {
305      td.addText(Integer.toString(level+1));
306      td = tr.td();
307      String s = Utilities.padLeft("", '\u00A0', level*2);
308      td.addText(s);
309    }
310    String link = isSupplement ? getLinkForCode(cs.getSupplements(), null, c.getCode()) : null;
311    if (link != null) {
312      td.ah(link).attribute("style", "white-space:nowrap").addText(c.getCode());
313    } else {
314      td.attribute("style", "white-space:nowrap").addText(c.getCode());
315    }      
316    XhtmlNode a;
317    if (c.hasCodeElement()) {
318      td.an(cs.getId()+"-" + Utilities.nmtokenize(c.getCode()));
319    }
320
321    for (ConceptDefinitionDesignationComponent cd : c.getDesignation()) {
322      if (cd.hasLanguage() && !langs.contains(cd.getLanguage()) && (!cs.hasLanguage() || !cs.getLanguage().equals(cd.getLanguage()))) {
323        langs.add(cd.getLanguage());
324      }
325        
326    }
327
328    if (hasDisplay) {
329      td = tr.td();
330      renderDisplayName(c, cs, td);
331    } 
332    if (hasDefinitions) {
333      td = tr.td();
334      if (c != null && 
335          c.hasDefinitionElement()) {
336        if (getContext().getLang() == null) {
337          if (hasMarkdownInDefinitions(cs))
338            addMarkdown(td, c.getDefinition());
339          else
340            td.addText(c.getDefinition());
341        } else if (getContext().getLang().equals("*")) {
342          boolean sl = false;
343          for (ConceptDefinitionDesignationComponent cd : c.getDesignation()) 
344            if (cd.getUse().is("http://terminology.hl7.org/CodeSystem/designation-usage", "definition") && cd.hasLanguage() && !c.getDefinition().equalsIgnoreCase(cd.getValue())) 
345              sl = true;
346          td.addText((sl ? cs.getLanguage("en")+": " : "")+c.getDefinition());
347          for (ConceptDefinitionDesignationComponent cd : c.getDesignation()) {
348            if (cd.getUse().is("http://terminology.hl7.org/CodeSystem/designation-usage", "definition") && cd.hasLanguage() && !c.getDefinition().equalsIgnoreCase(cd.getValue())) {
349              td.br();
350              td.addText(cd.getLanguage()+": "+cd.getValue());
351            }
352          }
353        } else if (getContext().getLang().equals(cs.getLanguage()) || (getContext().getLang().equals("en") && !cs.hasLanguage())) {
354          td.addText(c.getDefinition());
355        } else {
356          for (ConceptDefinitionDesignationComponent cd : c.getDesignation()) {
357            if (cd.getUse().is("http://terminology.hl7.org/CodeSystem/designation-usage", "definition") && cd.hasLanguage() && cd.getLanguage().equals(getContext().getLang())) {
358              td.addText(cd.getValue());
359            }
360          }
361        }
362      }
363    }
364    if (deprecated) {
365      td = tr.td();
366      Boolean b = CodeSystemUtilities.isDeprecated(cs, c, false);
367      if (b !=  null && b) {
368        smartAddText(td, getContext().getWorker().translator().translate("xhtml-gen-cs", "Deprecated", getContext().getLang()));
369        hasExtensions = true;
370        if (ToolingExtensions.hasExtension(c, ToolingExtensions.EXT_REPLACED_BY)) {
371          Coding cc = (Coding) ToolingExtensions.getExtension(c, ToolingExtensions.EXT_REPLACED_BY).getValue();
372          td.tx(" (replaced by ");
373          String url = getCodingReference(cc, system);
374          if (url != null) {
375            td.ah(url).addText(cc.getCode());
376            td.tx(": "+cc.getDisplay()+")");
377          } else
378            td.addText(cc.getCode()+" '"+cc.getDisplay()+"' in "+cc.getSystem()+")");
379        }
380      }
381    }
382    if (comment) {
383      td = tr.td();
384      Extension ext = c.getExtensionByUrl(ToolingExtensions.EXT_CS_COMMENT);
385      if (ext != null) {
386        hasExtensions = true;
387        String bc = ext.hasValue() ? ext.getValue().primitiveValue() : null;
388        Map<String, String> translations = ToolingExtensions.getLanguageTranslations(ext.getValue());
389
390        if (getContext().getLang() == null) {
391          if (bc != null)
392            td.addText(bc);
393        } else if (getContext().getLang().equals("*")) {
394          boolean sl = false;
395          for (String l : translations.keySet()) 
396            if (bc == null || !bc.equalsIgnoreCase(translations.get(l))) 
397              sl = true;
398          if (bc != null) {
399            td.addText((sl ? cs.getLanguage("en")+": " : "")+bc);
400          }
401          for (String l : translations.keySet()) {
402            if (bc == null || !bc.equalsIgnoreCase(translations.get(l))) {
403              if (!td.getChildNodes().isEmpty()) 
404                td.br();
405              td.addText(l+": "+translations.get(l));
406            }
407          }
408        } else if (getContext().getLang().equals(cs.getLanguage()) || (getContext().getLang().equals("en") && !cs.hasLanguage())) {
409          if (bc != null)
410            td.addText(bc);
411        } else {
412          if (bc != null)
413            translations.put(cs.getLanguage("en"), bc);
414          for (String l : translations.keySet()) { 
415            if (l.equals(getContext().getLang())) {
416              td.addText(translations.get(l));
417            }
418          }
419        }
420      }      
421    }
422    if (version) {
423      td = tr.td();
424      if (c.hasUserData("cs.version.notes"))
425        td.addText(c.getUserString("cs.version.notes"));
426    }
427    if (properties != null) {
428      for (PropertyComponent pc : properties) {
429        td = tr.td();
430        boolean first = true;
431        List<ConceptPropertyComponent> pcvl = CodeSystemUtilities.getPropertyValues(c, pc.getCode());
432        for (ConceptPropertyComponent pcv : pcvl) {
433          if (pcv.hasValue()) {
434            if (first) first = false; else td.addText(", ");
435            if (pcv.hasValueCoding()) { 
436              td.addText(pcv.getValueCoding().getCode());
437            } else if (pcv.hasValueStringType() && Utilities.isAbsoluteUrlLinkable(pcv.getValue().primitiveValue())) {
438              td.ah(pcv.getValue().primitiveValue()).tx(pcv.getValue().primitiveValue());
439            } else {
440              td.addText(pcv.getValue().primitiveValue());
441            }
442          }
443        }
444      }
445    }
446    
447    for (UsedConceptMap m : maps) {
448      td = tr.td();
449      List<TargetElementComponentWrapper> mappings = findMappingsForCode(c.getCode(), m.getMap());
450      boolean first = true;
451      for (TargetElementComponentWrapper mapping : mappings) {
452        if (!first)
453            td.br();
454        first = false;
455        XhtmlNode span = td.span(null, mapping.comp.hasRelationship() ?  mapping.comp.getRelationship().toCode() : "");
456        span.addText(getCharForRelationship(mapping.comp));
457        a = td.ah(getContext().getSpecificationLink()+m.getLink()+"#"+makeAnchor(mapping.group.getTarget(), mapping.comp.getCode()));
458        a.addText(mapping.comp.getCode());
459        if (!Utilities.noString(mapping.comp.getComment()))
460          td.i().tx("("+mapping.comp.getComment()+")");
461      }
462    }
463    List<ConceptDefinitionComponent> ocl = csNav.getOtherChildren(c);
464    for (ConceptDefinitionComponent cc : csNav.getConcepts(c)) {
465      hasExtensions = addDefineRowToTable(t, cc, level+1, hasHierarchy, hasDisplay, hasDefinitions, comment, version, deprecated, maps, system, cs, properties, csNav, langs, isSupplement) || hasExtensions;
466    }
467    for (ConceptDefinitionComponent cc : ocl) {
468      tr = t.tr();
469      td = tr.td();
470      td.addText(Integer.toString(level+2));
471      td = tr.td();
472      String s = Utilities.padLeft("", '\u00A0', (level+1)*2);
473      td.addText(s);
474      td.attribute("style", "white-space:nowrap");
475      a = td.ah("#"+cs.getId()+"-" + Utilities.nmtokenize(cc.getCode()));
476      a.addText(cc.getCode());
477      if (hasDisplay) {
478        td = tr.td();
479        renderDisplayName(cc, cs, td);
480      }
481      int w = 1 + (deprecated ? 1 : 0) + (comment ? 1 : 0) + (version ? 1 : 0) + maps.size();
482      if (properties != null) {
483        w = w + properties.size();
484      }
485      td = tr.td().colspan(Integer.toString(w));
486    }
487    return hasExtensions;
488  }
489
490  private boolean hasMarkdownInDefinitions(CodeSystem cs) {
491    return ToolingExtensions.readBoolExtension(cs, "http://hl7.org/fhir/StructureDefinition/codesystem-use-markdown");
492  }
493
494
495  public void renderDisplayName(ConceptDefinitionComponent c, CodeSystem cs, XhtmlNode td) {
496    if (c.hasDisplayElement()) {
497      if (getContext().getLang() == null) {
498        td.addText(c.getDisplay());
499      } else if (getContext().getLang().equals("*")) {
500        boolean sl = false;
501        for (ConceptDefinitionDesignationComponent cd : c.getDesignation()) 
502          if (cd.getUse().is("http://terminology.hl7.org/CodeSystem/designation-usage", "display") && cd.hasLanguage() && !c.getDisplay().equalsIgnoreCase(cd.getValue())) 
503            sl = true;
504        td.addText((sl ? cs.getLanguage("en")+": " : "")+c.getDisplay());
505        for (ConceptDefinitionDesignationComponent cd : c.getDesignation()) {
506          if (cd.getUse().is("http://terminology.hl7.org/CodeSystem/designation-usage", "display") && cd.hasLanguage() && !c.getDisplay().equalsIgnoreCase(cd.getValue())) {
507            td.br();
508            td.addText(cd.getLanguage()+": "+cd.getValue());
509          }
510        }
511     } else if (getContext().getLang().equals(cs.getLanguage()) || (getContext().getLang().equals("en") && !cs.hasLanguage())) {
512       td.addText(c.getDisplay());
513     } else {
514       for (ConceptDefinitionDesignationComponent cd : c.getDesignation()) {
515         if (cd.getUse().is("http://terminology.hl7.org/CodeSystem/designation-usage", "display") && cd.hasLanguage() && cd.getLanguage().equals(getContext().getLang())) {
516           td.addText(cd.getValue());
517         }
518       }
519     }
520    }
521  }
522
523  private String getCodingReference(Coding cc, String system) {
524    if (cc.getSystem().equals(system))
525      return "#"+cc.getCode();
526    if (cc.getSystem().equals("http://snomed.info/sct"))
527      return "http://snomed.info/sct/"+cc.getCode();
528    if (cc.getSystem().equals("http://loinc.org"))
529      return "http://s.details.loinc.org/LOINC/"+cc.getCode()+".html";
530    return null;
531  }
532
533
534  private void addLanguageRow(ConceptDefinitionComponent c, XhtmlNode t, List<String> langs) {
535    XhtmlNode tr = t.tr();
536    tr.td().addText(c.getCode());
537    for (String lang : langs) {
538      ConceptDefinitionDesignationComponent d = null;
539      for (ConceptDefinitionDesignationComponent designation : c.getDesignation()) {
540        if (designation.hasLanguage()) {
541          if (lang.equals(designation.getLanguage()))
542            d = designation;
543        }
544      }
545      tr.td().addText(d == null ? "" : d.getValue());
546    }
547  }
548 
549}