001package org.hl7.fhir.r4b.renderers; 002 003import java.io.IOException; 004import java.io.UnsupportedEncodingException; 005import java.util.ArrayList; 006import java.util.List; 007 008import org.hl7.fhir.exceptions.DefinitionException; 009import org.hl7.fhir.exceptions.FHIRFormatError; 010import org.hl7.fhir.r4b.context.IWorkerContext.ValidationResult; 011import org.hl7.fhir.r4b.model.Bundle.BundleEntryComponent; 012import org.hl7.fhir.r4b.model.CanonicalResource; 013import org.hl7.fhir.r4b.model.CodeSystem; 014import org.hl7.fhir.r4b.model.CodeSystem.ConceptDefinitionComponent; 015import org.hl7.fhir.r4b.model.CodeSystem.PropertyComponent; 016import org.hl7.fhir.r4b.model.ConceptMap; 017import org.hl7.fhir.r4b.model.ConceptMap.ConceptMapGroupComponent; 018import org.hl7.fhir.r4b.model.ConceptMap.SourceElementComponent; 019import org.hl7.fhir.r4b.model.ConceptMap.TargetElementComponent; 020import org.hl7.fhir.r4b.model.DomainResource; 021import org.hl7.fhir.r4b.model.Questionnaire; 022import org.hl7.fhir.r4b.model.Resource; 023import org.hl7.fhir.r4b.model.StructureDefinition; 024import org.hl7.fhir.r4b.model.ValueSet; 025import org.hl7.fhir.r4b.model.ValueSet.ConceptSetComponent; 026import org.hl7.fhir.r4b.renderers.utils.BaseWrappers.ResourceWrapper; 027import org.hl7.fhir.r4b.renderers.utils.RenderingContext; 028import org.hl7.fhir.r4b.renderers.utils.Resolver.ResourceContext; 029import org.hl7.fhir.r4b.terminologies.CodeSystemUtilities; 030import org.hl7.fhir.r4b.utils.ToolingExtensions; 031import org.hl7.fhir.utilities.Utilities; 032import org.hl7.fhir.utilities.xhtml.XhtmlNode; 033 034public abstract class TerminologyRenderer extends ResourceRenderer { 035 036 public TerminologyRenderer(RenderingContext context) { 037 super(context); 038 } 039 040 public TerminologyRenderer(RenderingContext context, ResourceContext rcontext) { 041 super(context, rcontext); 042 } 043 044 public String display(Resource r) throws UnsupportedEncodingException, IOException { 045 return ((CanonicalResource) r).present(); 046 } 047 048 public String display(ResourceWrapper r) throws UnsupportedEncodingException, IOException { 049 if (r.has("title")) { 050 return r.children("title").get(0).getBase().primitiveValue(); 051 } 052 if (r.has("name")) { 053 return r.children("name").get(0).getBase().primitiveValue(); 054 } 055 return "??"; 056 } 057 058 protected class TargetElementComponentWrapper { 059 protected ConceptMapGroupComponent group; 060 protected TargetElementComponent comp; 061 protected TargetElementComponentWrapper(ConceptMapGroupComponent group, TargetElementComponent comp) { 062 super(); 063 this.group = group; 064 this.comp = comp; 065 } 066 067 } 068 069 public class UsedConceptMap { 070 071 private ConceptMapRenderInstructions details; 072 private String link; 073 private ConceptMap map; 074 public UsedConceptMap(ConceptMapRenderInstructions details, String link, ConceptMap map) { 075 super(); 076 this.details = details; 077 this.link = link; 078 this.map = map; 079 } 080 public ConceptMapRenderInstructions getDetails() { 081 return details; 082 } 083 public ConceptMap getMap() { 084 return map; 085 } 086 public String getLink() { 087 return link; 088 } 089 } 090 091 public class ConceptMapRenderInstructions { 092 private String name; 093 private String url; 094 private boolean doDescription; 095 public ConceptMapRenderInstructions(String name, String url, boolean doDescription) { 096 super(); 097 this.name = name; 098 this.url = url; 099 this.doDescription = doDescription; 100 } 101 public String getName() { 102 return name; 103 } 104 public String getUrl() { 105 return url; 106 } 107 public boolean isDoDescription() { 108 return doDescription; 109 } 110 } 111 112 113 protected void addMapHeaders(XhtmlNode tr, List<UsedConceptMap> maps) throws FHIRFormatError, DefinitionException, IOException { 114 for (UsedConceptMap m : maps) { 115 XhtmlNode td = tr.td(); 116 XhtmlNode b = td.b(); 117 XhtmlNode a = b.ah(getContext().getSpecificationLink()+m.getLink()); 118 a.addText(m.getDetails().getName()); 119 if (m.getDetails().isDoDescription() && m.getMap().hasDescription()) 120 addMarkdown(td, m.getMap().getDescription()); 121 } 122 } 123 124 protected String getHeader() { 125 int i = 3; 126 while (i <= getContext().getHeaderLevelContext()) 127 i++; 128 if (i > 6) 129 i = 6; 130 return "h"+Integer.toString(i); 131 } 132 133 protected List<TargetElementComponentWrapper> findMappingsForCode(String code, ConceptMap map) { 134 List<TargetElementComponentWrapper> mappings = new ArrayList<TargetElementComponentWrapper>(); 135 136 for (ConceptMapGroupComponent g : map.getGroup()) { 137 for (SourceElementComponent c : g.getElement()) { 138 if (c.getCode().equals(code)) 139 for (TargetElementComponent cc : c.getTarget()) 140 mappings.add(new TargetElementComponentWrapper(g, cc)); 141 } 142 } 143 return mappings; 144 } 145 146 147 148 protected String getCharForRelationship(TargetElementComponent mapping) { 149 if (!mapping.hasEquivalence()) 150 return ""; 151 switch (mapping.getEquivalence()) { 152 case EQUIVALENT : return "~"; 153 case WIDER : return "<"; 154 case NARROWER : return ">"; 155 case DISJOINT : return "!="; 156 default: return "?"; 157 } 158 } 159 160 protected <T extends Resource> void addCsRef(ConceptSetComponent inc, XhtmlNode li, T cs) { 161 String ref = null; 162 boolean addHtml = true; 163 if (cs != null) { 164 ref = (String) cs.getUserData("external.url"); 165 if (Utilities.noString(ref)) 166 ref = (String) cs.getUserData("filename"); 167 else 168 addHtml = false; 169 if (Utilities.noString(ref)) { 170 ref = (String) cs.getUserData("path"); 171 if (ref != null) { 172 addHtml = false; 173 } 174 } 175 } 176 String spec = getSpecialReference(inc.getSystem()); 177 if (spec != null) { 178 XhtmlNode a = li.ah(spec); 179 a.code(inc.getSystem()); 180 } else if (cs != null && ref != null) { 181 if (addHtml && !ref.contains(".html")) 182 ref = ref + ".html"; 183 ref = context.fixReference(ref); 184 XhtmlNode a = li.ah(ref.replace("\\", "/")); 185 a.code(inc.getSystem()); 186 } else { 187 li.code(inc.getSystem()); 188 } 189 } 190 191 192 private String getSpecialReference(String system) { 193 if ("http://snomed.info/sct".equals(system)) 194 return "http://www.snomed.org/"; 195 if (Utilities.existsInList(system, "http://loinc.org", "http://unitsofmeasure.org", "http://www.nlm.nih.gov/research/umls/rxnorm", "http://ncimeta.nci.nih.gov", "http://fdasis.nlm.nih.gov", 196 "http://www.radlex.org", "http://www.whocc.no/atc", "http://dicom.nema.org/resources/ontology/DCM", "http://www.genenames.org", "http://www.ensembl.org", "http://www.ncbi.nlm.nih.gov/nuccore", 197 "http://www.ncbi.nlm.nih.gov/clinvar", "http://sequenceontology.org", "http://www.hgvs.org/mutnomen", "http://www.ncbi.nlm.nih.gov/projects/SNP", "http://cancer.sanger.ac.uk/cancergenome/projects/cosmic", 198 "http://www.lrg-sequence.org", "http://www.omim.org", "http://www.ncbi.nlm.nih.gov/pubmed", "http://www.pharmgkb.org", "http://clinicaltrials.gov", "http://www.ebi.ac.uk/ipd/imgt/hla/")) 199 return system; 200 201 return null; 202 } 203 204 protected XhtmlNode addTableHeaderRowStandard(XhtmlNode t, boolean hasHierarchy, boolean hasDisplay, boolean definitions, boolean comments, boolean version, boolean deprecated, List<PropertyComponent> properties, List<String> langs, boolean doLangs) { 205 XhtmlNode tr = t.tr(); 206 if (hasHierarchy) { 207 tr.td().b().tx("Lvl"); 208 } 209 tr.td().attribute("style", "white-space:nowrap").b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "Code", getContext().getLang())); 210 if (hasDisplay) { 211 tr.td().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "Display", getContext().getLang())); 212 } 213 if (definitions) { 214 tr.td().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "Definition", getContext().getLang())); 215 } 216 if (deprecated) { 217 tr.td().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "Deprecated", getContext().getLang())); 218 } 219 if (comments) { 220 tr.td().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "Comments", getContext().getLang())); 221 } 222 if (version) { 223 tr.td().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "Version", getContext().getLang())); 224 } 225 if (properties != null) { 226 for (PropertyComponent pc : properties) { 227 String display = ToolingExtensions.getPresentation(pc, pc.getCodeElement()); 228 if (display == null || display.equals(pc.getCode()) && pc.hasUri()) { 229 display = getDisplayForProperty(pc.getUri()); 230 if (display == null) { 231 display = pc.getCode(); 232 } 233 } 234 tr.td().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", display, getContext().getLang())); 235 } 236 } 237 if (doLangs) { 238 for (String lang : langs) { 239 tr.td().b().addText(describeLang(lang)); 240 } 241 } 242 return tr; 243 } 244 245 246 protected String getDisplayForProperty(String uri) { 247 if (Utilities.noString(uri)){ 248 return null; 249 } 250 String code = null; 251 if (uri.contains("#")) { 252 code = uri.substring(uri.indexOf("#")+1); 253 uri = uri.substring(0, uri.indexOf("#")); 254 } 255 CodeSystem cs = getContext().getWorker().fetchCodeSystem(uri); 256 if (cs == null) { 257 return null; 258 } 259 ConceptDefinitionComponent cc = code == null ? null : CodeSystemUtilities.getCode(cs, code); 260 return cc == null ? null : cc.getDisplay(); 261 } 262 263 264 protected void AddVsRef(String value, XhtmlNode li) { 265 Resource res = null; 266 if (rcontext != null) { 267 BundleEntryComponent be = rcontext.resolve(value); 268 if (be != null) { 269 res = be.getResource(); 270 } 271 } 272 if (res != null && !(res instanceof CanonicalResource)) { 273 li.addText(value); 274 return; 275 } 276 CanonicalResource vs = (CanonicalResource) res; 277 if (vs == null) 278 vs = getContext().getWorker().fetchResource(ValueSet.class, value); 279 if (vs == null) 280 vs = getContext().getWorker().fetchResource(StructureDefinition.class, value); 281 // if (vs == null) 282 // vs = context.getWorker().fetchResource(DataElement.class, value); 283 if (vs == null) 284 vs = getContext().getWorker().fetchResource(Questionnaire.class, value); 285 if (vs != null) { 286 String ref = (String) vs.getUserData("path"); 287 288 ref = context.fixReference(ref); 289 XhtmlNode a = li.ah(ref == null ? "?ngen-11?" : ref.replace("\\", "/")); 290 a.addText(value); 291 } else { 292 CodeSystem cs = getContext().getWorker().fetchCodeSystem(value); 293 if (cs != null) { 294 String ref = (String) cs.getUserData("path"); 295 ref = context.fixReference(ref); 296 XhtmlNode a = li.ah(ref == null ? "?ngen-12?" : ref.replace("\\", "/")); 297 a.addText(value); 298 } else if (value.equals("http://snomed.info/sct") || value.equals("http://snomed.info/id")) { 299 XhtmlNode a = li.ah(value); 300 a.tx("SNOMED-CT"); 301 } 302 else { 303 if (value.startsWith("http://hl7.org") && !Utilities.existsInList(value, "http://hl7.org/fhir/sid/icd-10-us")) 304 System.out.println("Unable to resolve value set "+value); 305 li.addText(value); 306 } 307 } 308 } 309 310 311 312 protected String getDisplayForConcept(String system, String version, String value) { 313 if (value == null || system == null) 314 return null; 315 ValidationResult cl = getContext().getWorker().validateCode(getContext().getTerminologyServiceOptions().setVersionFlexible(true), system, version, value, null); 316 return cl == null ? null : cl.getDisplay(); 317 } 318 319}