
001package org.hl7.fhir.r5.renderers; 002 003import java.io.File; 004import java.io.IOException; 005import java.io.UnsupportedEncodingException; 006import java.util.ArrayList; 007import java.util.HashMap; 008import java.util.List; 009import java.util.Map; 010import java.util.UUID; 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.Address; 016import org.hl7.fhir.r5.model.Attachment; 017import org.hl7.fhir.r5.model.CodeableConcept; 018import org.hl7.fhir.r5.model.ContactPoint; 019import org.hl7.fhir.r5.model.DataType; 020import org.hl7.fhir.r5.model.DateType; 021import org.hl7.fhir.r5.model.Extension; 022import org.hl7.fhir.r5.model.HumanName; 023import org.hl7.fhir.r5.model.HumanName.NameUse; 024import org.hl7.fhir.r5.model.Identifier; 025import org.hl7.fhir.r5.model.Identifier.IdentifierUse; 026import org.hl7.fhir.r5.model.Patient; 027import org.hl7.fhir.r5.model.Period; 028import org.hl7.fhir.r5.model.Reference; 029import org.hl7.fhir.r5.model.Resource; 030import org.hl7.fhir.r5.model.StructureDefinition; 031import org.hl7.fhir.r5.renderers.utils.BaseWrappers.BaseWrapper; 032import org.hl7.fhir.r5.renderers.utils.BaseWrappers.PropertyWrapper; 033import org.hl7.fhir.r5.renderers.utils.BaseWrappers.ResourceWrapper; 034import org.hl7.fhir.r5.renderers.utils.RenderingContext; 035import org.hl7.fhir.utilities.TextFile; 036import org.hl7.fhir.utilities.Utilities; 037import org.hl7.fhir.utilities.xhtml.XhtmlNode; 038 039public class PatientRenderer extends ResourceRenderer { 040 041 public class NamedReferance { 042 043 private String name; 044 private Reference reference; 045 private BaseWrapper wrapper; 046 047 public NamedReferance(String name, Reference ref, BaseWrapper refw) { 048 this.name = name; 049 this.reference = ref; 050 this.wrapper = refw; 051 } 052 053 public String getName() { 054 return name; 055 } 056 057 public Reference getReference() { 058 return reference; 059 } 060 061 public BaseWrapper getWrapper() { 062 return wrapper; 063 } 064 065 } 066 067 private static final int MAX_IMAGE_LENGTH = 2*1024*1024; 068 069 public PatientRenderer(RenderingContext context) { 070 super(context); 071 } 072 073 public boolean render(XhtmlNode x, Resource dr) throws UnsupportedEncodingException, IOException { 074 describe(x, dr); 075 return false; 076 } 077 078 // name gender DoB (MRN) 079 public String display(Resource dr) { 080 Patient pat = (Patient) dr; 081 Identifier id = null; 082 for (Identifier t : pat.getIdentifier()) { 083 id = chooseId(id, t); 084 } 085 HumanName n = null; 086 for (HumanName t : pat.getName()) { 087 n = chooseName(n, t); 088 } 089 return display(n, pat.hasGender() ? pat.getGender().getDisplay() : null, pat.getBirthDateElement(), id); 090 } 091 092 private Identifier chooseId(Identifier oldId, Identifier newId) { 093 if (oldId == null) { 094 return newId; 095 } 096 if (newId == null) { 097 return oldId; 098 } 099 return isPreferred(newId.getUse(), oldId.getUse()) ? newId : oldId; 100 } 101 102 private boolean isPreferred(IdentifierUse newUse, IdentifierUse oldUse) { 103 if (newUse == null && oldUse == null || newUse == oldUse) { 104 return false; 105 } 106 if (newUse == null) { 107 return true; 108 } 109 switch (newUse) { 110 case NULL: return !existsInList(oldUse, IdentifierUse.OFFICIAL, IdentifierUse.USUAL); 111 case OFFICIAL: return !existsInList(oldUse, IdentifierUse.USUAL); 112 case OLD: return !existsInList(oldUse, IdentifierUse.OFFICIAL, IdentifierUse.SECONDARY, IdentifierUse.USUAL); 113 case SECONDARY: return !existsInList(oldUse, IdentifierUse.OFFICIAL, IdentifierUse.USUAL); 114 case TEMP: return !existsInList(oldUse, IdentifierUse.OFFICIAL, IdentifierUse.SECONDARY, IdentifierUse.USUAL); 115 case USUAL: return true; 116 default: return false; 117 } 118 } 119 120 private boolean existsInList(IdentifierUse oldUse, IdentifierUse... values) { 121 for (IdentifierUse value : values) { 122 if (value == oldUse) { 123 return true; 124 } 125 } 126 return false; 127 } 128 129 private HumanName chooseName(HumanName oldName, HumanName newName) { 130 if (oldName == null) { 131 return newName; 132 } 133 if (newName == null) { 134 return oldName; 135 } 136 return isPreferred(newName.getUse(), oldName.getUse()) ? newName : oldName; 137 } 138 139 140 private boolean isPreferred(NameUse newUse, NameUse oldUse) { 141 if (newUse == null && oldUse == null || newUse == oldUse) { 142 return false; 143 } 144 if (newUse == null) { 145 return true; 146 } 147 if (oldUse == null) { 148 return existsInList(newUse, NameUse.OFFICIAL, NameUse.USUAL); 149 } 150 switch (oldUse) { 151 case ANONYMOUS: return existsInList(newUse, NameUse.OFFICIAL, NameUse.USUAL); 152 case MAIDEN: return existsInList(newUse, NameUse.OFFICIAL, NameUse.USUAL); 153 case NICKNAME: return existsInList(newUse, NameUse.OFFICIAL, NameUse.USUAL); 154 case NULL: return existsInList(newUse, NameUse.OFFICIAL, NameUse.USUAL); 155 case OFFICIAL: return existsInList(newUse, NameUse.USUAL); 156 case OLD: return existsInList(newUse, NameUse.OFFICIAL, NameUse.USUAL); 157 case TEMP: return existsInList(newUse, NameUse.OFFICIAL, NameUse.USUAL); 158 case USUAL: return false; 159 } 160 return false; 161 } 162 163 private boolean existsInList(NameUse oldUse, NameUse... values) { 164 for (NameUse value : values) { 165 if (value == oldUse) { 166 return true; 167 } 168 } 169 return false; 170 } 171 172 @Override 173 public String display(ResourceWrapper pat) throws UnsupportedEncodingException, IOException { 174 Identifier id = null; 175 PropertyWrapper pw = getProperty(pat, "identifier"); 176 for (BaseWrapper t : pw.getValues()) { 177 id = chooseId(id, (Identifier) t.getBase()); 178 } 179 pw = getProperty(pat, "name"); 180 HumanName n = null; 181 for (BaseWrapper t : pw.getValues()) { 182 n = chooseName(n, (HumanName) t); 183 } 184 String gender = null; 185 pw = getProperty(pat, "gender"); 186 if (valued(pw)) { 187 pw.value().getBase().primitiveValue(); 188 } 189 DateType dt = null; 190 pw = getProperty(pat, "birthDate"); 191 if (valued(pw)) { 192 dt = (DateType) pw.value().getBase(); 193 } 194 return display(n, gender, dt, id); 195 } 196 197 public void describe(XhtmlNode x, ResourceWrapper pat) throws UnsupportedEncodingException, IOException { 198 Identifier id = null; 199 PropertyWrapper pw = getProperty(pat, "identifier"); 200 for (BaseWrapper t : pw.getValues()) { 201 id = chooseId(id, (Identifier) t.getBase()); 202 } 203 pw = getProperty(pat, "name"); 204 HumanName n = null; 205 for (BaseWrapper t : pw.getValues()) { 206 n = chooseName(n, (HumanName) t.getBase()); 207 } 208 String gender = null; 209 pw = getProperty(pat, "gender"); 210 if (valued(pw)) { 211 gender = pw.value().getBase().primitiveValue(); 212 } 213 DateType dt = null; 214 pw = getProperty(pat, "birthDate"); 215 if (valued(pw)) { 216 dt = (DateType) pw.value().getBase(); 217 } 218 describe(x, n, gender, dt, id); 219 } 220 221 222 private String display(HumanName name, String gender, DateType dob, Identifier id) { 223 StringBuilder b = new StringBuilder(); 224 b.append(display(name)); 225 b.append(" "); 226 if (dob == null) { 227 b.append("(no stated gender)"); 228 } else { 229 b.append(gender); 230 } 231 b.append(", "); 232 if (dob == null) { 233 b.append("DoB Unknown"); 234 } else { 235 b.append("DoB: "+display(dob)); 236 } 237 if (id != null) { 238 b.append(" ( "); 239 b.append(display(id)); 240 b.append(")"); 241 } 242 return b.toString(); 243 } 244 245 public void describe(XhtmlNode x, HumanName name, String gender, DateType dob, Identifier id) throws UnsupportedEncodingException, IOException { 246 if (name == null) { 247 x.b().tx("Anonymous Patient"); // todo: is this appropriate? 248 } else { 249 render(x.b(), name); 250 } 251 x.tx(" "); 252 if (gender == null) { 253 x.tx("(no stated gender)"); 254 } else { 255 x.tx(gender); 256 } 257 x.tx(", "); 258 if (dob == null) { 259 x.tx("DoB Unknown"); 260 } else { 261 x.tx("DoB: "); 262 render(x, dob); 263 } 264 if (id != null) { 265 x.tx(" ( "); 266 render(x, id); 267 x.tx(")"); 268 } 269 } 270 271 @Override 272 public boolean render(XhtmlNode x, ResourceWrapper r) throws FHIRFormatError, DefinitionException, IOException { 273 // banner 274 describe(makeBanner(x.para()), r); 275 x.hr(); 276 XhtmlNode tbl; 277 if (hasRenderablePhoto(r)) { 278 tbl = x.table("none"); 279 XhtmlNode tr = tbl.tr(); 280 tbl = tr.td().table("grid"); 281 renderPhoto(tr.td(), r); 282 } else { 283 tbl = x.table("grid"); 284 } 285 286 // the table has 4 columns 287 addStatus(tbl, r); 288 addIdentifiers(tbl, r); 289 addNames(tbl, r); 290 addComms(tbl, r); 291 addLangs(tbl, r); 292 addNOKs(tbl, r); 293 addLinks(tbl, r); 294 addExtensions(tbl, r); 295 if (tbl.isEmpty()) { 296 x.remove(tbl); 297 } 298 return false; 299 } 300 301 private void addExtensions(XhtmlNode tbl, ResourceWrapper r) throws UnsupportedEncodingException, FHIRException, IOException { 302 Map<String, List<Extension>> extensions = new HashMap<>(); 303 PropertyWrapper pw = getProperty(r, "extension"); 304 for (BaseWrapper t : pw.getValues()) { 305 Extension ext = (Extension) t.getBase(); 306 if (!extensions.containsKey(ext.getUrl())) { 307 extensions.put(ext.getUrl(), new ArrayList<>()); 308 } 309 extensions.get(ext.getUrl()).add(ext); 310 } 311 for (String url : extensions.keySet()) { 312 StructureDefinition sd = context.getWorker().fetchResource(StructureDefinition.class, url); 313 if (sd != null) { 314 List<Extension> list = extensions.get(url); 315 boolean anyComplex = false; 316 for (Extension ext : list) { 317 anyComplex = anyComplex || ext.hasExtension(); 318 } 319 if (!anyComplex) { 320 XhtmlNode tr = tbl.tr(); 321 nameCell(tr, sd.getTitle()+":", sd.getDescription(), sd.getUserString("path")); 322 XhtmlNode td = tr.td(); 323 td.colspan("3"); 324 if (list.size() == 1) { 325 XhtmlNode ul = td.ul(); 326 for (Extension s : list) { 327 XhtmlNode li = ul.li(); 328 render(r, li, s.getValue()); 329 } 330 } else { 331 render(r, td, list.get(0).getValue()); 332 } 333 } else { 334 for (Extension ext : list) { 335 XhtmlNode tr = tbl.tr(); 336 nameCell(tr, sd.getTitle()+":", sd.getDescription()); 337 XhtmlNode td = tr.td(); 338 td.colspan("3"); 339 if (ext.hasExtension()) { 340 XhtmlNode ul = td.ul(); 341 for (Extension s : ext.getExtension()) { 342 XhtmlNode li = ul.li(); 343 li.tx(s.getUrl()+": "); 344 if (s.hasExtension()) { 345 boolean first = true; 346 for (Extension t : s.getExtension()) { 347 if (first) first = false; else li.tx("; "); 348 li.tx(t.getUrl()+"="); 349 render(r, li, t.getValue()); 350 } 351 } else { 352 render(r, li, s.getValue()); 353 } 354 } 355 } else { 356 render(r, td, ext.getValue()); 357 } 358 } 359 } 360 } 361 } 362 363 364 } 365 366 private void addIdentifiers(XhtmlNode tbl, ResourceWrapper r) throws FHIRFormatError, DefinitionException, IOException { 367 List<Identifier> ids = new ArrayList<>(); 368 PropertyWrapper pw = getProperty(r, "identifier"); 369 for (BaseWrapper t : pw.getValues()) { 370 ids.add((Identifier) t.getBase()); 371 } 372 Identifier id = null; 373 for (Identifier i : ids) { 374 id = chooseId(id, i); 375 } 376 if (id != null) { 377 ids.remove(id); 378 }; 379 if (ids.size() == 1) { 380 XhtmlNode tr = tbl.tr(); 381 nameCell(tr, "Other Id:", "Other Ids (see the one above)"); 382 XhtmlNode td = tr.td(); 383 td.colspan("3"); 384 render(r, td, ids.get(0)); 385 } else if (ids.size() > 1) { 386 XhtmlNode tr = tbl.tr(); 387 nameCell(tr, "Other Ids:", "Other Ids (see the one above)"); 388 XhtmlNode td = tr.td(); 389 td.colspan("3"); 390 XhtmlNode ul = td.ul(); 391 for (Identifier i : ids) { 392 render(r, ul.li(), i); 393 } 394 } 395 } 396 397 private void addLangs(XhtmlNode tbl, ResourceWrapper r) throws FHIRFormatError, DefinitionException, IOException { 398 List<CodeableConcept> langs = new ArrayList<>(); 399 PropertyWrapper pw = getProperty(r, "communication"); 400 CodeableConcept prefLang = null; 401 for (BaseWrapper t : pw.getValues()) { 402 PropertyWrapper l = getProperty(t, "language"); 403 if (l != null && l.hasValues()) { 404 CodeableConcept lang = (CodeableConcept) l.getValues().get(0).getBase(); 405 langs.add(lang); 406 l = getProperty(t, "preferred"); 407 if (l != null && l.hasValues() && "true".equals(l.getValues().get(0).getBase().primitiveValue())) { 408 prefLang = lang; 409 } 410 } 411 } 412 if (langs.size() == 1) { 413 XhtmlNode tr = tbl.tr(); 414 nameCell(tr, "Language:", "Languages spoken"); 415 XhtmlNode td = tr.td(); 416 td.colspan("3"); 417 render(r, td, langs.get(0)); 418 if (prefLang != null) { 419 td.tx(" (preferred)"); 420 } 421 } else if (langs.size() > 1) { 422 XhtmlNode tr = tbl.tr(); 423 nameCell(tr, "Languages:", "Languages spoken"); 424 XhtmlNode td = tr.td(); 425 td.colspan("3"); 426 XhtmlNode ul = td.ul(); 427 for (CodeableConcept i : langs) { 428 XhtmlNode li = ul.li(); 429 render(r, li, i); 430 if (i == prefLang) { 431 li.tx(" (preferred)"); 432 } 433 } 434 } 435 } 436 437 438 private void addLinks(XhtmlNode tbl, ResourceWrapper r) throws UnsupportedEncodingException, FHIRException, IOException { 439 List<NamedReferance> refs = new ArrayList<>(); 440 PropertyWrapper pw = getProperty(r, "generalPractitioner"); 441 if (pw != null) { 442 for (BaseWrapper t : pw.getValues()) { 443 refs.add(new NamedReferance("General Practitioner", (Reference) t.getBase(), t)); 444 } 445 } 446 pw = getProperty(r, "managingOrganization"); 447 if (pw != null) { 448 for (BaseWrapper t : pw.getValues()) { 449 refs.add(new NamedReferance("Managing Organization", (Reference) t.getBase(), t)); 450 } 451 } 452 pw = getProperty(r, "link"); 453 for (BaseWrapper t : pw.getValues()) { 454 PropertyWrapper l = getProperty(t, "other"); 455 Reference ref = null; 456 BaseWrapper refw = null; 457 for (BaseWrapper v : l.getValues()) { 458 ref = (Reference) v.getBase(); 459 refw = v; 460 } 461 String type = null; 462 l = getProperty(t, "type"); 463 for (BaseWrapper v : l.getValues()) { 464 type = v.getBase().primitiveValue(); 465 } 466 if (type != null && ref != null) { 467 refs.add(new NamedReferance(describeLinkedRecord(type), ref, refw)); 468 } 469 } 470 471 if (refs.size() > 0) { 472 XhtmlNode tr = tbl.tr(); 473 nameCell(tr, "Links:", "Patient Links"); 474 XhtmlNode td = tr.td(); 475 td.colspan("3"); 476 XhtmlNode ul = td.ul(); 477 for (NamedReferance ref : refs) { 478 XhtmlNode li = ul.li(); 479 li.tx(ref.getName()); 480 li.tx(": "); 481 renderReference(r, li, ref.getReference()); 482 } 483 } 484 } 485 486 private String describeLinkedRecord(String type) { 487 switch (type) { 488 case "replaced-by" : return "This record replaced by"; 489 case "replaces": return "This record replaces"; 490 case "refer": return "Please refer to"; 491 case "seealso": return "Also see"; 492 } 493 return "Unknown"; 494 } 495 496 private void addNOKs(XhtmlNode tbl, ResourceWrapper r) throws FHIRFormatError, DefinitionException, IOException { 497 PropertyWrapper pw = getProperty(r, "contact"); 498 for (BaseWrapper t : pw.getValues()) { 499 addNOK(tbl,r, t); 500 } 501 } 502 503 private void addNOK(XhtmlNode tbl, ResourceWrapper r, BaseWrapper bw) throws FHIRFormatError, DefinitionException, IOException { 504 List<CodeableConcept> rels = new ArrayList<>(); 505 HumanName name = null; 506 Address add = null; 507 String gender = null; 508 Period period = null; 509 Reference organization = null; 510 List<ContactPoint> tels = new ArrayList<>(); 511 512 PropertyWrapper pw = getProperty(bw, "relationship"); 513 for (BaseWrapper t : pw.getValues()) { 514 CodeableConcept v = (CodeableConcept) t.getBase(); 515 rels.add(v); 516 } 517 518 pw = getProperty(bw, "name"); 519 if (pw.hasValues()) { 520 name = (HumanName) pw.getValues().get(0).getBase(); 521 } 522 pw = getProperty(bw, "telecom"); 523 for (BaseWrapper t : pw.getValues()) { 524 ContactPoint v = (ContactPoint) t.getBase(); 525 tels.add(v); 526 } 527 528 pw = getProperty(bw, "address"); 529 if (pw.hasValues()) { 530 add = (Address) pw.getValues().get(0).getBase(); 531 } 532 533 pw = getProperty(bw, "gender"); 534 if (pw.hasValues()) { 535 gender = pw.getValues().get(0).getBase().primitiveValue(); 536 } 537 538 pw = getProperty(bw, "organization"); 539 if (pw.hasValues()) { 540 organization = (Reference) pw.getValues().get(0).getBase(); 541 } 542 543 pw = getProperty(bw, "period"); 544 if (pw.hasValues()) { 545 period = (Period) pw.getValues().get(0).getBase(); 546 } 547 548 if (rels.size() < 2 && name == null && add == null && gender == null && period == null && organization == null && tels.size() == 0) { 549 return; // nothing to render 550 } 551 XhtmlNode tr = tbl.tr(); 552 if (rels.size() == 1) { 553 nameCell(tr, (rels.get(0).getCodingFirstRep().hasDisplay() ? rels.get(0).getCodingFirstRep().getDisplay() : display(rels.get(0)))+":", "Nominated Contact: "+display(rels.get(0))); 554 } else { 555 nameCell(tr, "Contact", "Patient contact"); 556 } 557 XhtmlNode td = tr.td(); 558 td.colspan("3"); 559 XhtmlNode ul = td.ul(); 560 XhtmlNode li; 561 if (name != null) { 562 li = ul.li(); 563 render(r, li, name); 564 if (gender != null) { 565 li.tx(" ("+gender+")"); 566 } 567 } else if (gender != null) { 568 li = ul.li(); 569 li.tx("Gender: "+gender); 570 } 571 if (rels.size() > 1) { 572 li = ul.li(); 573 li.tx("Relationships: "); 574 boolean first = true; 575 for (CodeableConcept rel : rels) { 576 if (first) first = false; else li.tx(", "); 577 render(r, li, rel); 578 } 579 } 580 if (add != null) { 581 render(r, ul.li(), add); 582 } 583 for (ContactPoint cp : tels) { 584 render(r, ul.li(), cp); 585 } 586 if (organization != null) { 587 li = ul.li(); 588 li.tx("Organization: "); 589 render(r, li, organization); 590 } 591 if (period != null) { 592 li = ul.li(); 593 li.tx("Valid Period: "); 594 render(r, li, period); 595 } 596 } 597 598 private void addNames(XhtmlNode tbl, ResourceWrapper r) throws FHIRFormatError, DefinitionException, IOException { 599 List<HumanName> names = new ArrayList<>(); 600 PropertyWrapper pw = getProperty(r, "name"); 601 for (BaseWrapper t : pw.getValues()) { 602 names.add((HumanName) t.getBase()); 603 } 604 HumanName name = null; 605 for (HumanName n : names) { 606 name = chooseName(name, n); 607 } 608 if (name != null) { 609 names.remove(name); 610 }; 611 if (names.size() == 1) { 612 XhtmlNode tr = tbl.tr(); 613 nameCell(tr, "Alt. Name:", "Alternate names (see the one above)"); 614 XhtmlNode td = tr.td(); 615 td.colspan("3"); 616 render(r, td, names.get(0)); 617 } else if (names.size() > 1) { 618 XhtmlNode tr = tbl.tr(); 619 nameCell(tr, "Alt Names:", "Alternate names (see the one above)"); 620 XhtmlNode td = tr.td(); 621 td.colspan("3"); 622 XhtmlNode ul = td.ul(); 623 for (HumanName n : names) { 624 render(r, ul.li(), n); 625 } 626 } 627 } 628 629 private void addComms(XhtmlNode tbl, ResourceWrapper r) throws FHIRFormatError, DefinitionException, IOException { 630 List<ContactPoint> tels = new ArrayList<>(); 631 PropertyWrapper pw = getProperty(r, "telecom"); 632 for (BaseWrapper t : pw.getValues()) { 633 tels.add((ContactPoint) t.getBase()); 634 } 635 List<Address> adds = new ArrayList<>(); 636 pw = getProperty(r, "address"); 637 for (BaseWrapper t : pw.getValues()) { 638 adds.add((Address) t.getBase()); 639 } 640 if (tels.size() + adds.size() == 1) { 641 XhtmlNode tr = tbl.tr(); 642 nameCell(tr, "Contact Detail:", "Ways to contact the Patient"); 643 XhtmlNode td = tr.td(); 644 td.colspan("3"); 645 if (adds.isEmpty()) { 646 render(r, td, tels.get(0)); 647 } else { 648 render(r, td, adds.get(0)); 649 } 650 } else if (tels.size() + adds.size() > 1) { 651 XhtmlNode tr = tbl.tr(); 652 nameCell(tr, "Contact Details:", "Ways to contact the Patient"); 653 XhtmlNode td = tr.td(); 654 td.colspan("3"); 655 XhtmlNode ul = td.ul(); 656 for (ContactPoint n : tels) { 657 render(r, ul.li(), n); 658 } 659 for (Address n : adds) { 660 render(r, ul.li(), n); 661 } 662 } 663 } 664 665 private void addStatus(XhtmlNode tbl, ResourceWrapper r) throws FHIRFormatError, DefinitionException, UnsupportedEncodingException, FHIRException, IOException { 666 // TODO Auto-generated method stub 667 int count = 0; 668 if (r.has("active")) { 669 count++; 670 } 671 if (r.has("deceased")) { 672 count++; 673 } 674 if (r.has("maritalStatus")) { 675 count++; 676 } 677 if (r.has("multipleBirth")) { 678 count++; 679 } 680 if (count > 0) { 681 XhtmlNode tr = tbl.tr(); 682 int pos = 0; 683 if (r.has("active")) { 684 PropertyWrapper a = r.getChildByName("active"); 685 if (a.hasValues()) { 686 pos++; 687 nameCell(tr, "Active:", "Record is active"); 688 XhtmlNode td = tr.td(); 689 if (pos == count) { 690 td.colspan("3"); 691 } 692 render(r, td, (DataType) a.value().getBase()); 693 } 694 } 695 if (r.has("deceased[x]")) { 696 PropertyWrapper a = r.getChildByName("deceased[x]"); 697 if (a.hasValues()) { 698 pos++; 699 nameCell(tr, "Deceased:", "Known status of Patient"); 700 XhtmlNode td = tr.td(); 701 if (pos == count) { 702 td.colspan("3"); 703 } 704 render(r, td, (DataType) a.value().getBase()); 705 } 706 } 707 if (r.has("maritalStatus")) { 708 PropertyWrapper a = r.getChildByName("maritalStatus"); 709 if (a.hasValues()) { 710 pos++; 711 if (pos == 3) { 712 tr = tbl.tr(); 713 } 714 nameCell(tr, "Marital Status:", "Known Marital status of Patient"); 715 XhtmlNode td = tr.td(); 716 if (pos == count) { 717 td.colspan("3"); 718 } 719 render(r, td, (DataType) a.value().getBase()); 720 } 721 } 722 if (r.has("multipleBirth[x]")) { 723 PropertyWrapper a = r.getChildByName("multipleBirth[x]"); 724 if (a.hasValues()) { 725 pos++; 726 if (pos == 3) { 727 tr = tbl.tr(); 728 } 729 nameCell(tr, "Multiple Birth:", "Known multipleBirth status of Patient"); 730 XhtmlNode td = tr.td(); 731 if (pos == count) { 732 td.colspan("3"); 733 } 734 render(r, td, (DataType) a.value().getBase()); 735 } 736 } 737 } 738 } 739 740 private void nameCell(XhtmlNode tr, String text, String title) { 741 XhtmlNode td = tr.td(); 742 td.setAttribute("title", title); 743 td.tx(text); 744 td.style("background-color: #f3f5da"); 745 } 746 747 private void nameCell(XhtmlNode tr, String text, String title, String link) { 748 XhtmlNode td = tr.td(); 749 td.setAttribute("title", title); 750 if (link != null) { 751 td.ah(link).tx(text); 752 } else { 753 td.tx(text); 754 } 755 td.style("background-color: #f3f5da"); 756 } 757 758 private void renderPhoto(XhtmlNode td, ResourceWrapper r) throws UnsupportedEncodingException, FHIRException, IOException { 759 if (r.has("photo")) { 760 PropertyWrapper a = r.getChildByName("photo"); 761 for (BaseWrapper v : a.getValues()) { 762 Attachment att = (Attachment) v.getBase(); 763 if (att.getContentType().startsWith("image/") && 764 att.getData() != null && (!context.isInlineGraphics() || (att.getData().length > 0 && att.getData().length < MAX_IMAGE_LENGTH))) { 765 String ext = extensionForType(att.getContentType()); 766 if (context.isInlineGraphics() || Utilities.noString(context.getDestDir()) || ext == null) { 767 td.img("data:"+att.getContentType()+";base64,"+att.getDataElement().asStringValue(), "patient photo"); 768 } else { 769 String n = UUID.randomUUID().toString().toLowerCase()+ext; 770 TextFile.bytesToFile(att.getData(), new File(Utilities.path(context.getDestDir(), n))); 771 td.img(n, "patient photo"); 772 } 773 return; 774 } 775 } 776 } 777 return; 778 } 779 780 private String extensionForType(String contentType) { 781 if (contentType.equals("image/gif")) { 782 return ".gif"; 783 } 784 if (contentType.equals("image/png")) { 785 return ".png"; 786 } 787 if (contentType.equals("image/jpeg")) { 788 return ".jpg"; 789 } 790 return null; 791 } 792 793 private boolean hasRenderablePhoto(ResourceWrapper r) throws UnsupportedEncodingException, FHIRException, IOException { 794 if (r.has("photo")) { 795 PropertyWrapper a = r.getChildByName("photo"); 796 for (BaseWrapper v : a.getValues()) { 797 Attachment att = (Attachment) v.getBase(); 798 if (att.hasContentType() && att.getContentType().startsWith("image/") && 799 att.getData() != null && (!context.isInlineGraphics() || (att.getData().length > 0 && att.getData().length < MAX_IMAGE_LENGTH))) { 800 return true; 801 } 802 } 803 } 804 return false; 805 } 806 807 private XhtmlNode makeBanner(XhtmlNode para) { 808 para.style("border: 1px #661aff solid; background-color: #e6e6ff; padding: 10px;"); 809 return para; 810 } 811}