001package org.hl7.fhir.r5.renderers;
002
003import java.io.IOException;
004import java.io.UnsupportedEncodingException;
005
006import org.apache.poi.hssf.record.chart.DatRecord;
007import org.hl7.fhir.exceptions.DefinitionException;
008import org.hl7.fhir.exceptions.FHIRFormatError;
009import org.hl7.fhir.r5.model.DateTimeType;
010import org.hl7.fhir.r5.model.DateType;
011import org.hl7.fhir.r5.model.DomainResource;
012import org.hl7.fhir.r5.model.HumanName;
013import org.hl7.fhir.r5.model.HumanName.NameUse;
014import org.hl7.fhir.r5.model.Identifier;
015import org.hl7.fhir.r5.model.Identifier.IdentifierUse;
016import org.hl7.fhir.r5.model.Patient;
017import org.hl7.fhir.r5.model.Resource;
018import org.hl7.fhir.r5.renderers.utils.RenderingContext;
019import org.hl7.fhir.r5.renderers.utils.BaseWrappers.BaseWrapper;
020import org.hl7.fhir.r5.renderers.utils.BaseWrappers.PropertyWrapper;
021import org.hl7.fhir.r5.renderers.utils.BaseWrappers.ResourceWrapper;
022import org.hl7.fhir.utilities.xhtml.XhtmlNode;
023
024public class PatientRenderer extends ResourceRenderer {
025
026  public PatientRenderer(RenderingContext context) {
027    super(context);
028  }
029
030  public boolean render(XhtmlNode x, Resource dr) throws UnsupportedEncodingException, IOException {
031    describe(x, dr);
032    return false;
033  }
034
035  // name gender DoB (MRN)
036  public String display(Resource dr) {
037    Patient pat = (Patient) dr;
038    Identifier id = null;
039    for (Identifier t : pat.getIdentifier()) {
040      id = chooseId(id, t);
041    }
042    HumanName n = null;
043    for (HumanName t : pat.getName()) {
044      n = chooseName(n, t);
045    }
046    return display(n, pat.hasGender() ? pat.getGender().getDisplay() : null, pat.getBirthDateElement(), id);
047  }
048
049  private Identifier chooseId(Identifier oldId, Identifier newId) {
050    if (oldId == null) {
051      return newId;
052    }
053    if (newId == null) {
054      return oldId;
055    }
056    return isPreferred(newId.getUse(), oldId.getUse()) ? newId : oldId;
057  }
058
059  private boolean isPreferred(IdentifierUse newUse, IdentifierUse oldUse) {
060    if (newUse == null && oldUse == null || newUse == oldUse) {
061      return false;
062    }
063    if (newUse == null) {
064      return true;
065    }
066    switch (newUse) {
067    case NULL: return !existsInList(oldUse, IdentifierUse.OFFICIAL, IdentifierUse.USUAL);
068    case OFFICIAL: return !existsInList(oldUse, IdentifierUse.USUAL);
069    case OLD: return !existsInList(oldUse, IdentifierUse.OFFICIAL, IdentifierUse.SECONDARY, IdentifierUse.USUAL);
070    case SECONDARY: return !existsInList(oldUse, IdentifierUse.OFFICIAL, IdentifierUse.USUAL);
071    case TEMP: return !existsInList(oldUse, IdentifierUse.OFFICIAL, IdentifierUse.SECONDARY, IdentifierUse.USUAL);
072    case USUAL: return true;
073    default: return false;
074    }
075  }
076
077  private boolean existsInList(IdentifierUse oldUse, IdentifierUse... values) {
078    for (IdentifierUse value : values) {
079      if (value == oldUse) {
080        return true;
081      }
082    }
083    return false;
084  }
085
086  private HumanName chooseName(HumanName oldName, HumanName newName) {
087    if (oldName == null) {
088      return newName;
089    }
090    if (newName == null) {
091      return oldName;
092    }
093    return isPreferred(newName.getUse(), oldName.getUse()) ? newName : oldName;
094  }
095
096
097  private boolean isPreferred(NameUse newUse, NameUse oldUse) {
098    if (newUse == null && oldUse == null || newUse == oldUse) {
099      return false;
100    }
101    if (newUse == null) {
102      return true;
103    }
104    switch (oldUse) {
105      case ANONYMOUS: return existsInList(newUse, NameUse.OFFICIAL, NameUse.USUAL);
106      case MAIDEN: return existsInList(newUse, NameUse.OFFICIAL, NameUse.USUAL);
107      case NICKNAME: return existsInList(newUse, NameUse.OFFICIAL, NameUse.USUAL);
108      case NULL: return existsInList(newUse, NameUse.OFFICIAL, NameUse.USUAL);
109      case OFFICIAL: return existsInList(newUse, NameUse.USUAL);
110      case OLD: return existsInList(newUse, NameUse.OFFICIAL, NameUse.USUAL);
111      case TEMP: return existsInList(newUse, NameUse.OFFICIAL, NameUse.USUAL);
112      case USUAL: return false; 
113    }
114    return false;
115  }
116
117  private boolean existsInList(NameUse oldUse, NameUse... values) {
118    for (NameUse value : values) {
119      if (value == oldUse) {
120        return true;
121      }
122    }
123    return false;
124  }
125
126  @Override
127  public String display(ResourceWrapper pat) throws UnsupportedEncodingException, IOException {
128    Identifier id = null;
129    PropertyWrapper pw = getProperty(pat, "identifier");
130    for (BaseWrapper t : pw.getValues()) {
131      id = chooseId(id, (Identifier) t.getBase());
132    }
133    pw = getProperty(pat, "name");
134    HumanName n = null;
135    for (BaseWrapper t : pw.getValues()) {
136      n = chooseName(n, (HumanName) t);
137    }
138    String gender = null;
139    pw = getProperty(pat, "gender");
140    if (valued(pw)) {
141      pw.value().getBase().primitiveValue();
142    }
143    DateType dt = null; 
144    pw = getProperty(pat, "birthDate");
145    if (valued(pw)) {
146      dt = (DateType) pw.value().getBase();
147    }
148    return display(n, gender, dt, id);  
149  }
150
151  public void describe(XhtmlNode x, ResourceWrapper pat) throws UnsupportedEncodingException, IOException {
152    Identifier id = null;
153    PropertyWrapper pw = getProperty(pat, "identifier");
154    for (BaseWrapper t : pw.getValues()) {
155      id = chooseId(id, (Identifier) t.getBase());
156    }
157    pw = getProperty(pat, "name");
158    HumanName n = null;
159    for (BaseWrapper t : pw.getValues()) {
160      n = chooseName(n, (HumanName) t.getBase());
161    }
162    String gender = null;
163    pw = getProperty(pat, "gender");
164    if (valued(pw)) {
165      pw.value().getBase().primitiveValue();
166    }
167    DateType dt = null; 
168    pw = getProperty(pat, "birthDate");
169    if (valued(pw)) {
170      dt = (DateType) pw.value().getBase();
171    }
172    describe(x, n, gender, dt, id);
173  }
174
175
176  private String display(HumanName name, String gender, DateType dob, Identifier id) {
177    StringBuilder b = new StringBuilder();
178    b.append(display(name));
179    b.append(" ");
180    if (dob == null) {
181      b.append("(no stated gender)");
182    } else {
183      b.append(gender);
184    }
185    b.append(" ");
186    if (dob == null) {
187      b.append("DoB Unknown");
188    } else {
189      b.append(display(dob));      
190    }
191    if (id != null) {
192      b.append(" ( ");      
193      b.append(display(id));
194      b.append(")");      
195    }
196    return b.toString();
197  }
198  
199  public void describe(XhtmlNode x, HumanName name, String gender, DateType dob, Identifier id) throws UnsupportedEncodingException, IOException {
200    if (name == null) {
201      x.b().tx("Anonymous Patient"); // todo: is this appropriate?  
202    } else {
203      render(x.b(), name);
204    }
205    x.tx(" ");
206    if (gender == null) {
207      x.tx("(no stated gender)");
208    } else {
209      x.tx(gender);
210    }
211    x.tx(" ");
212    if (dob == null) {
213      x.tx("DoB Unknown");
214    } else {
215      render(x, dob);
216    }
217    if (id != null) {
218      x.tx(" ( ");      
219      render(x, id);
220      x.tx(")");      
221    }
222  }
223
224  @Override
225  public boolean render(XhtmlNode x, ResourceWrapper r) throws FHIRFormatError, DefinitionException, IOException {
226    describe(x.para(), r);
227    return false;
228  }
229}