Downloads Documentation Community Contribute Demo






Show Sidebar
Login | Register

Changeset 3854

Show
Ignore:
Timestamp:
04/07/08 18:37:31 (9 months ago)
Author:
bmckown
Message:

Clinical Summary Module: Quick-hack to add CD4 count reminders on summary sheets. Also included a few previous AMPATH specific modifications.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • openmrs-modules/clinicalsummary/.classpath

    r2639 r3854  
    44        <classpathentry kind="src" path="web/src"/> 
    55        <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> 
    6         <classpathentry kind="lib" path="lib-common/openmrs-api-1.1.10.2290.jar" sourcepath="/openmrs-alpha"/> 
     6        <classpathentry kind="lib" path="lib-common/openmrs-api-1.1.10.2290.jar" /> 
    77        <classpathentry kind="lib" path="lib-common/web-openmrs-api-1.0.52.1465.jar"/> 
    88        <classpathentry kind="lib" path="lib-common/commons-logging-1.0.4.jar"/> 
    99        <classpathentry kind="lib" path="lib-common/servlet-api.jar"/> 
    10         <classpathentry kind="lib" path="lib-common/spring-2.0.jar" sourcepath="C:/Documents and Settings/bmckown/Desktop/doc/spring-framework-2.0.6/spring-framework-2.0.6"/> 
     10        <classpathentry kind="lib" path="lib-common/spring-2.0.jar" /> 
    1111        <classpathentry kind="lib" path="lib-common/hibernate3.jar"/> 
    1212        <classpathentry kind="lib" path="lib-common/velocity-1.4.jar"/> 
  • openmrs-modules/clinicalsummary/src/org/openmrs/module/clinicalsummary/AMPATHClinicalSummaryPrintingLogic.java

    r1833 r3854  
    1111import org.openmrs.Encounter; 
    1212import org.openmrs.Form; 
     13import org.openmrs.Location; 
    1314import org.openmrs.Obs; 
    1415import org.openmrs.api.context.Context; 
     
    3334                String formName = form.getName(); 
    3435                 
    35                 return printableFormNames.contains(formName); 
     36        // Handle only encounters from MTRH Module 2 
     37                Location location = e.getLocation(); 
     38                Integer locationId = location.getLocationId(); 
     39                 
     40                return (printableFormNames.contains(formName) && locationId == 13); 
    3641        } 
    3742 
  • openmrs-modules/clinicalsummary/src/org/openmrs/module/clinicalsummary/SummaryExportFunctions.java

    r2330 r3854  
    11package org.openmrs.module.clinicalsummary; 
    22 
     3import java.text.DateFormat; 
     4import java.text.SimpleDateFormat; 
    35import java.util.Calendar; 
    46import java.util.Collection; 
     
    1113import java.util.List; 
    1214import java.util.Map; 
     15import java.util.Set; 
    1316import java.util.Vector; 
    1417 
     
    1821import org.openmrs.Encounter; 
    1922import org.openmrs.EncounterType; 
     23import org.openmrs.Obs; 
    2024import org.openmrs.api.ConceptService; 
    2125import org.openmrs.api.context.Context; 
     
    2327 
    2428public class SummaryExportFunctions extends DataExportFunctions { 
    25          
    26         public final Log log = LogFactory.getLog(this.getClass()); 
    27          
    28         protected Map<Integer, List<List<Object>>> patientIdObsValueMapLeft = null; 
    29         protected Map<Integer, List<List<Object>>> patientIdObsValueMapRight = null; 
    30          
    31         public SummaryExportFunctions() { 
    32                 super(); 
    33                  
    34                 this.validEncounterTypes.add(new EncounterType(1)); 
    35                 this.validEncounterTypes.add(new EncounterType(2)); 
    36                 this.validEncounterTypes.add(new EncounterType(3)); 
    37                 this.validEncounterTypes.add(new EncounterType(4)); 
    38                 this.validEncounterTypes.add(new EncounterType(14)); 
    39                 this.validEncounterTypes.add(new EncounterType(15)); 
    40         } 
    41  
    42         /** 
    43          * Returns a list of obs rows 
    44          *  
    45          * [{concept value}, {attr 1}, {attr 2}, etc] 
    46          *  
    47          * @param conceptNameLeft 
    48          * @param conceptNameRight 
    49          * @param attrObj 
    50          * @return 
    51          * @throws Exception 
    52          */ 
    53         @SuppressWarnings("unchecked") 
    54         public List<List<Object>> getIntersectedObs(String conceptNameLeft, String conceptNameRight, Object attrListObj) throws Exception { 
    55                  
    56                 List<String> attrs = (List<String>)attrListObj; 
    57                  
    58                 Concept conceptLeft = getConcept(conceptNameLeft); 
    59                 Concept conceptRight = getConcept(conceptNameRight); 
    60                  
    61                 if (patientIdObsValueMapLeft == null) { 
    62                         patientIdObsValueMapLeft = patientSetService.getObservationsValues(getPatientSet(), conceptLeft, attrs); 
    63                         patientIdObsValueMapRight = patientSetService.getObservationsValues(getPatientSet(), conceptRight, attrs); 
    64                 } 
    65                  
    66                 List<List<Object>> answersLeft = patientIdObsValueMapLeft.get(getPatientId()); 
    67                 List<List<Object>> answersRight = patientIdObsValueMapRight.get(getPatientId()); 
    68                  
    69                 if (answersLeft == null) 
    70                         answersLeft = new Vector<List<Object>>(); 
    71                  
    72                 if (answersRight == null) 
    73                         answersRight = new Vector<List<Object>>(); 
    74                  
    75                 Map<Object, List<Object>> answerHash = new Hashtable<Object, List<Object>>(); 
    76                  
    77                 // Create hash with an entry for the most recent of each left-sided observation 
    78                 for (int i = answersLeft.size()-1; i>=0; i--) { 
    79                         List<Object> leftRow = answersLeft.get(i); 
    80                         Object answer = leftRow.get(0); 
    81                         if (answer != null) 
    82                                 if (!answerHash.containsKey(answer)) 
    83                                         answerHash.put(answer, leftRow); 
    84                 } 
    85                  
    86                 // Remove any observations from the hash where there is a later entry in the right-side 
    87                 // list of observations 
    88                 for (int i = answersRight.size()-1; i>=0; i--) { 
    89                         List<Object> rightRow = answersRight.get(i); 
    90                         Date rightDate = (Date)rightRow.get(1); 
    91                         Object answer = rightRow.get(0); 
    92                         if (answer != null) 
    93                                 if (answerHash.containsKey(answer)) { 
    94                                         List<Object> leftRow = answerHash.get(answer); 
    95                                         Date leftDate = (Date)leftRow.get(1); 
    96                                         if (leftDate.before(rightDate)) 
    97                                                 answerHash.remove(answer); 
    98                                 } 
    99                 } 
    100                  
    101                 // answersLeft and answersRight are always sorted from [most recent] -> [oldest] 
    102                 // if we loop over answersRight from the top down, and inner loop over answersLeft top down,  
    103                 // we can compare/remove obs from left 
    104                 /* 
    105                 for (List<Object> row : answersRight) { 
    106                         Object rightValue = row.get(0); 
    107                         Date rightDate = (Date)row.get(1); 
    108                         int x = 0; 
    109                         while (x < answersLeft.size()) { 
    110                                 List<Object> leftRow = answersLeft.get(x++); 
    111                                 if (rightValue.equals(leftRow.get(0))) { 
    112                                         Date leftDate = (Date) leftRow.get(1); 
    113                                         if (leftDate.before(rightDate)) 
    114                                                 answersLeft.remove(--x); 
    115                                 } 
    116                         } 
    117                 } 
    118                  
    119                 return answersLeft; 
    120                 */ 
    121                  
    122                 List<List<Object>> sortedAnswers = new Vector<List<Object>>(); 
    123                 if (answerHash.size() > 0) 
    124                         for (List<Object> value : answerHash.values()) 
    125                                 sortedAnswers.add(value); 
    126                 Collections.sort(sortedAnswers, new DateComparator()); 
    127                  
    128                 return sortedAnswers; 
    129         } 
    130          
    131         /** 
    132          * Returns a list of [number, (years|months|days)] 
    133          *  
    134          * @param d 
    135          * @return 
    136          */ 
    137         public List<Object> getAge(Date birthdate) { 
    138                 List<Object> returnList = new Vector<Object>(); 
    139  
    140                 if (birthdate != null) { 
    141                         Calendar today = Calendar.getInstance(); 
    142                          
    143                         Calendar bday = new GregorianCalendar(); 
    144                         bday.setTime(birthdate); 
    145                          
    146                         int years = today.get(Calendar.YEAR) - bday.get(Calendar.YEAR); 
    147                          
    148                         //tricky bit: 
    149                         // set birthday calendar to this year 
    150                         // if the current date is less that the new 'birthday', subtract a year 
    151                         bday.set(Calendar.YEAR, today.get(Calendar.YEAR)); 
    152                         if (today.before(bday)) { 
    153                                         years = years -1; 
    154                         } 
    155                          
    156                         if (years > 1) { 
    157                                 returnList.add(years); 
    158                                 returnList.add("years"); 
    159                                 return returnList; 
    160                         } 
    161                         else { 
    162                                 // calculate months 
    163                                 int months = today.get(Calendar.MONTH) - bday.get(Calendar.MONTH); 
    164                                 if (months < 0) //if this overlaps the new year 
    165                                         months = 12 + months + (years > 0 ? 12 : 0); 
    166                                  
    167                                 if (months > 1) { 
    168                                         returnList.add(months); 
    169                                         returnList.add("months"); 
    170                                         return returnList; 
    171                                 } 
    172                                  
    173                                 //calculate weeks 
    174                                 int days = today.get(Calendar.DAY_OF_YEAR) - bday.get(Calendar.DAY_OF_YEAR); 
    175                                 if (days < 0) // if this overlaps the new year 
    176                                         days = 365 - bday.get(Calendar.DAY_OF_YEAR) + today.get(Calendar.DAY_OF_YEAR); 
    177                                  
    178                                 if (days > 7) { 
    179                                         returnList.add((int)days / 7); 
    180                                         returnList.add("weeks"); 
    181                                         return returnList; 
    182                                 } 
    183                                 else { 
    184                                         returnList.add(days); 
    185                                         returnList.add("days"); 
    186                                         return returnList; 
    187                                 } 
    188                                  
    189                         } 
    190                 } 
    191                          
    192                 returnList.add(""); 
    193                 returnList.add(""); 
    194                 return returnList; 
    195         } 
    196          
    197         /** 
    198          * Finds all <code>conceptNames</code>s within the last <code>withinNumberOfMonths</code> months 
    199          *  
    200          * @param conceptName 
    201          * @param withinNumberOfMonths 
    202          * @return 
    203          * @throws Exception 
    204          */ 
    205         public List<Object> getObsTimeframe(String conceptName, Integer withinNumberOfMonths) throws Exception { 
    206                 Concept c = getConcept(conceptName); 
    207                 List<String> arr = new Vector<String>(); 
    208                  
    209                 arr.add("obsDatetime"); 
    210                 List<List<Object>> rows = getLastNObsWithValues(-1, c, arr); 
    211                  
    212                 Calendar cutoffDate = Calendar.getInstance(); 
    213                 cutoffDate.add(Calendar.MONTH, -1 * withinNumberOfMonths); 
    214                  
    215                 List<Object> obsValues = new Vector<Object>(); 
    216                  
    217                 Calendar currentDate = Calendar.getInstance(); 
    218                  
    219                 for (List<Object> vals : rows) { 
    220                         currentDate.setTime((Date)vals.get(1)); 
    221                         if (cutoffDate.compareTo(currentDate) < 0) { 
    222                                 obsValues.add(vals.get(0)); 
    223                         } 
    224                 } 
    225                  
    226                 return obsValues; 
    227         } 
    228          
    229         /** 
    230          * Returns a patient property as a list 
    231          * @param className 
    232          * @param property  
    233          * @return list of values for given property 
    234          */ 
    235         @SuppressWarnings("unchecked") 
    236         public Object[] getPatientAttrAsList(String className, String property) { 
    237                 return (Object[]) super.getPatientAttr(className, property, true); 
    238         } 
    239          
    240          
    241         protected List<EncounterType> validEncounterTypes = new Vector<EncounterType>(); //set in constructor 
    242         protected Map<Integer, Encounter> patientIdLastValidEncounter = null; 
    243         protected Map<Integer, Object /*Date*/> patientIdLastValidEncounterDatetime = null; 
    244         //protected Map<Integer, Map<Integer, List<List<Object>>>> conceptMap = null; 
    245         protected Map<Integer, Map<Integer, List<Object>>> conceptMap = null; 
    246          
    247         protected Map<Integer, Concept> cachedConcepts = null; 
    248          
    249         /** 
    250          *  
    251          * @return List of [medication, date] objects 
    252          */ 
    253         public List<List<Object>> getAmpathActiveMedications() { 
    254                  
    255                 ClinicalSummaryService css = (ClinicalSummaryService)Context.getService(ClinicalSummaryService.class); 
    256                  
    257                 // set up all of the obs and encounter maps 
    258                 if (conceptMap == null) { 
    259                         //conceptMap = new HashMap<Integer, Map<Integer, List<List<Object>>>>(); 
    260                         conceptMap = new HashMap<Integer, Map<Integer, List<Object>>>(); 
    261                          
    262                         List<String> attrs = new Vector<String>(); 
    263                         attrs.add("obsDatetime"); 
    264                          
    265                         patientIdLastValidEncounter = patientSetService.getEncountersByType(getPatientSet(), validEncounterTypes); 
    266                         patientIdLastValidEncounterDatetime = patientSetService.getEncounterAttrsByType(getPatientSet(), validEncounterTypes, "encounterDatetime"); 
    267                         Collection<Encounter> encounters = patientIdLastValidEncounter.values(); 
    268                          
    269                         Integer[] questionConceptIds = { 
    270                                                  966, 1088, 1107, 1109, 1111, 1112,  
    271                                                 1193, 1250, 1255, 1261, 1263, 1264,   
    272                                                 1265, 1268, 1270, 1277, 1278}; 
    273                          
    274                         ConceptService cs = Context.getConceptService(); 
    275                         for (Integer conceptId : questionConceptIds) { 
    276                                 conceptMap.put(conceptId, css.getObservationsForEncounters(encounters, cs.getConcept(conceptId))); 
    277                         } 
    278                          
    279                          
    280                         Integer[] cachedConceptIds = { 
    281                                          656, 747}; 
    282                          
    283                         cachedConcepts = new HashMap<Integer, Concept>(); 
    284                         for (Integer conceptId : cachedConceptIds) { 
    285                                 cachedConcepts.put(conceptId, cs.getConcept(conceptId)); 
    286                         } 
    287                          
    288                 } 
    289                  
    290                 List<Object> meds = new Vector<Object>(); 
    291                  
    292                 Integer pId = getPatientId(); 
    293  
    294                 Concept CHANGE_REGIMEN = new Concept(1259); 
    295                 Concept CONTINUE_REGIMEN = new Concept(1257); 
    296                 Concept STOP_ALL = new Concept(1260); 
    297                 Concept START_DRUGS = new Concept(1256); 
    298                 Concept DOSING_CHANGE = new Concept(981); 
    299                  
    300                  
    301                 addAll(meds, conceptMap.get(1193).get(pId)); //CURRENT MEDICATIONS 
    302                 addAll(meds, conceptMap.get(1112).get(pId)); //PATIENT REPORTED CURRENT CRYPTOCOCCUS TREATMENT 
    303                 addAll(meds, conceptMap.get(1109).get(pId)); //PATIENT REPORTED CURRENT PCP PROPHYLAXIS 
    304                 addAll(meds, conceptMap.get(1107).get(pId)); //PATIENT REPORTED CURRENT TUBERCULOSIS PROPHYLAXIS 
    305                 addAll(meds, conceptMap.get(1111).get(pId)); //PATIENT REPORTED CURRENT TUBERCULOSIS TREATMENT  
    306                  
    307                  
    308                 List<Object> ARVS_STARTED = conceptMap.get(1250).get(pId); 
    309                 if (ARVS_STARTED != null) 
    310                         addAll(meds, ARVS_STARTED); 
    311                 else { 
    312                         List<Object> ARV_PLAN = conceptMap.get(1255).get(pId); 
    313                         if (ARV_PLAN == null || ARV_PLAN.contains(CONTINUE_REGIMEN)) { 
    314                                 addAll(meds, conceptMap.get(966).get(pId));  //CURRENT ANTIRETROVIRAL DRUGS USED FOR TRANSMISSION PROPHYLAXIS 
    315                                 addAll(meds, conceptMap.get(1088).get(pId)); //CURRENT ANTIRETROVIRAL DRUGS USED FOR TREATMENT 
    316                         } 
    317                 } 
    318                  
    319                  
    320                 List<Object> CRYPT_TREATMENT_PLAN = conceptMap.get(1277).get(pId); 
    321                 Concept FLUCONAZOLE = cachedConcepts.get(747); 
    322                 if (CRYPT_TREATMENT_PLAN != null && CRYPT_TREATMENT_PLAN.contains(STOP_ALL)) { 
    323                         meds.remove(FLUCONAZOLE); 
    324                 } 
    325                 else if (containsAny(CRYPT_TREATMENT_PLAN, new Concept[] {START_DRUGS, CONTINUE_REGIMEN})) 
    326                         meds.add(FLUCONAZOLE); 
    327                 addAll(meds, conceptMap.get(1278).get(pId)); //CRYPTOCOCCUS TREATMENT STARTED 
    328                  
    329                  
    330                 List<Object> PCP_PRO_STARTED = conceptMap.get(1263).get(pId); 
    331                 List<Object> PCP_PRO_PLAN = conceptMap.get(1261).get(pId); 
    332                 if (PCP_PRO_STARTED != null || containsAny(PCP_PRO_PLAN, new Concept[] {START_DRUGS, CHANGE_REGIMEN, STOP_ALL, DOSING_CHANGE})) { 
    333                         meds.remove(new Concept(916)); //TRIMETHOPRIM AND SULFAMETHOXAZOLE 
    334                         meds.remove(new Concept(92));  //DAPSONE 
    335                 } 
    336                 addAll(meds, conceptMap.get(1263).get(pId)); //PCP PROPHYLAXIS STARTED 
    337                  
    338                  
    339                 List<Object> TB_PRO_PLAN = conceptMap.get(1265).get(pId); 
    340                 if (TB_PRO_PLAN != null && TB_PRO_PLAN.contains(STOP_ALL)) 
    341                         meds.remove(cachedConcepts.get(656)); //ISONIAZID  
    342                 else if (containsAny(TB_PRO_PLAN, new Concept[] {START_DRUGS, CONTINUE_REGIMEN, DOSING_CHANGE})) { 
    343                         meds.add(cachedConcepts.get(656)); //ISONIAZID 
    344                 } 
    345                 addAll(meds, conceptMap.get(1264).get(pId)); //TUBERCULOSIS PROPHYLAXIS STARTED 
    346                  
    347                  
    348                 List<Object> TB_TREATMENT_STARTED = conceptMap.get(1270).get(pId); 
    349                 List<Object> TB_TREATMENT_PLAN = conceptMap.get(1268).get(pId); 
    350                 if (TB_TREATMENT_STARTED != null ||  
    351                         containsAny(TB_TREATMENT_PLAN, new Concept[] {START_DRUGS, CHANGE_REGIMEN, STOP_ALL, DOSING_CHANGE})) { 
    352                                 meds.remove(new Concept(1108)); //ETHAMBUTOL AND ISONIZAID 
    353                                 meds.remove(new Concept(1131)); //RIFAMPICIN ISONIAZID PYRAZINAMIDE AND ETHAMBUTOL 
    354                                 meds.remove(new Concept(438));  //STREPTOMYCIN 
    355                                 meds.remove(new Concept(5829)); //PYRAZINAMIDE 
    356                                 meds.remove(new Concept(656));  //ISONIAZID  
    357                                 meds.remove(new Concept(745));  //ETHAMBUTOL  
    358                                 meds.remove(new Concept(767));  //RIFAMPICIN  
    359                                 meds.remove(new Concept(768));  //RIFAMPICIN ISONIAZID AND PYRAZINAMIDE 
    360                 } 
    361                 addAll(meds, conceptMap.get(1270).get(pId)); //TUBERCULOSIS TREATMENT STARTED 
    362                  
    363                  
    364                 // remove the possible answers we don't care about 
    365                 List<Concept> nonAnswers = new Vector<Concept>(); 
    366                 nonAnswers.add(new Concept(5622)); //OTHER NON-CODED 
    367                 nonAnswers.add(new Concept(1067)); //UNKNOWN 
    368                 nonAnswers.add(new Concept(1065)); //YES   
    369                 nonAnswers.add(new Concept(1107)); //NONE  
    370                 nonAnswers.add(new Concept(5424)); //OTHER ANTIRETROVIRAL DRUG 
    371                 nonAnswers.add(new Concept(5811)); //UNKNOWN ANTIRETROVIRAL DRUG 
    372                  
    373                 meds.removeAll(nonAnswers); 
    374                  
    375                  
    376                 //the date on all meds will currently just be the encounter datetime 
    377                 Date medStartTime = (Date)patientIdLastValidEncounterDatetime.get(pId); 
    378                  
    379                 // shrink the med list to just unique answers 
    380                 List<Object> uniqueMeds = new Vector<Object>(); 
    381                 List<List<Object>> returnMeds = new Vector<List<Object>>(); 
    382                 for (Object med : meds) { 
    383                         if (!uniqueMeds.contains(med)) { 
    384                                 uniqueMeds.add(med); 
    385                                 List<Object> medRow = new Vector<Object>(); 
    386                                 medRow.add(med); 
    387                                 medRow.add(medStartTime); 
    388                                 returnMeds.add(medRow); 
    389                         } 
    390                 } 
    391                  
    392                 return returnMeds; 
    393         } 
    394          
    395         /** 
    396          * Null <code>addAll<code> method 
    397          *  
    398          * @param currentMeds 
    399          * @param newMeds 
    400          */ 
    401         private void addAll(List<Object> currentMeds, List<Object> newMeds) { 
    402                 if (currentMeds == null || newMeds == null) 
    403                         return; 
    404                  
    405                 currentMeds.addAll(newMeds); 
    406         } 
    407  
    408         /** 
    409          * Checks list <code>actualAnswers</code> for the existence of at least one <code>possibleAnswers</code> 
    410          * @param actualAnswers 
    411          * @param possibleAnswers 
    412          * @return 
    413          */ 
    414         private Boolean containsAny(List<Object> actualAnswers, Concept[] possibleAnswers) { 
    415                  
    416                 if (actualAnswers == null || possibleAnswers == null) 
    417                         return false; 
    418                  
    419                 for (Concept possibleAnswer : possibleAnswers) { 
    420                         if (actualAnswers.contains(possibleAnswer)) 
    421                                 return true; 
    422                 } 
    423                  
    424                 return false; 
    425         } 
    426          
    427         /** 
    428          * Clean up the objects alloted 
    429          * @see org.openmrs.reporting.export.DataExportFunctions#clear() 
    430          */ 
    431         public void clear() { 
    432                 super.clear(); 
    433                  
    434                 patientIdObsValueMapLeft = null; 
    435                 patientIdObsValueMapRight = null; 
    436         } 
    437          
    438         /** 
    439          * Date Comparator for obs:date lists. 
    440          * Assumes each entry in the list will be a List<Object> with [0] = obs value and [1] = obs datetime 
    441          *  
    442          * Sorts the list from newest to oldest 
    443          */ 
    444         private class DateComparator implements Comparator<List<Object>> { 
    445                 public int compare(List<Object> a1, List<Object> a2) { 
    446                         Date d1 = (Date)a1.get(1); 
    447                         Date d2 = (Date)a2.get(1); 
    448                         int retVal = -1 * d1.compareTo(d2); 
    449                         if (retVal == 0) { 
    450                                 Concept c1 = (Concept)a1.get(0); 
    451                                 Concept c2 = (Concept)a2.get(0); 
    452                                 retVal = c1.getName().getName().compareTo(c2.getName().getName()); 
    453                         } 
    454                         return retVal; 
    455                 } 
    456         } 
     29 
     30    public final Log log = LogFactory.getLog(this.getClass()); 
     31 
     32    protected Map<Integer, List<List<Object>>> patientIdObsValueMapLeft = null; 
     33 
     34    protected Map<Integer, List<List<Object>>> patientIdObsValueMapRight = null; 
     35 
     36    public SummaryExportFunctions() { 
     37        super(); 
     38 
     39        this.validEncounterTypes.add(new EncounterType(1)); 
     40        this.validEncounterTypes.add(new EncounterType(2)); 
     41        this.validEncounterTypes.add(new EncounterType(3)); 
     42        this.validEncounterTypes.add(new EncounterType(4)); 
     43        this.validEncounterTypes.add(new EncounterType(14)); 
     44        this.validEncounterTypes.add(new EncounterType(15)); 
     45    } 
     46 
     47    /** 
     48     * Returns a list of obs rows 
     49     *  
     50     * [{concept value}, {attr 1}, {attr 2}, etc] 
     51     *  
     52     * @param conceptNameLeft 
     53     * @param conceptNameRight 
     54     * @param attrObj 
     55     * @return 
     56     * @throws Exception 
     57     */ 
     58    @SuppressWarnings("unchecked") 
     59    public List<List<Object>> getIntersectedObs(String conceptNameLeft, 
     60            String conceptNameRight, Object attrListObj) throws Exception { 
     61 
     62        List<String> attrs = (List<String>) attrListObj; 
     63 
     64        Concept conceptLeft = getConcept(conceptNameLeft); 
     65        Concept conceptRight = getConcept(conceptNameRight); 
     66 
     67        if (patientIdObsValueMapLeft == null) { 
     68            patientIdObsValueMapLeft = patientSetService.getObservationsValues( 
     69                    getPatientSet(), conceptLeft, attrs); 
     70            patientIdObsValueMapRight = patientSetService 
     71                    .getObservationsValues(getPatientSet(), conceptRight, attrs); 
     72        } 
     73 
     74        List<List<Object>> answersLeft = patientIdObsValueMapLeft 
     75                .get(getPatientId()); 
     76        List<List<Object>> answersRight = patientIdObsValueMapRight 
     77                .get(getPatientId()); 
     78 
     79        if (answersLeft == null) 
     80            answersLeft = new Vector<List<Object>>(); 
     81 
     82        if (answersRight == null) 
     83            answersRight = new Vector<List<Object>>(); 
     84 
     85        Map<Object, List<Object>> answerHash = new Hashtable<Object, List<Object>>(); 
     86 
     87        // Create hash with an entry for the most recent of each left-sided 
     88        // observation 
     89        for (int i = answersLeft.size() - 1; i >= 0; i--) { 
     90            List<Object> leftRow = answersLeft.get(i); 
     91            Object answer = leftRow.get(0); 
     92            if (answer != null) 
     93                if (!answerHash.containsKey(answer)) 
     94                    answerHash.put(answer, leftRow); 
     95        } 
     96 
     97        // Remove any observations from the hash where there is a later entry in 
     98        // the right-side 
     99        // list of observations 
     100        for (int i = answersRight.size() - 1; i >= 0; i--) { 
     101            List<Object> rightRow = answersRight.get(i); 
     102            Date rightDate = (Date) rightRow.get(1); 
     103            Object answer = rightRow.get(0); 
     104            if (answer != null) 
     105                if (answerHash.containsKey(answer)) { 
     106                    List<Object> leftRow = answerHash.get(answer); 
     107                    Date leftDate = (Date) leftRow.get(1); 
     108                    if (leftDate.before(rightDate)) 
     109                        answerHash.remove(answer); 
     110                } 
     111        } 
     112 
     113        // answersLeft and answersRight are always sorted from [most recent] -> 
     114        // [oldest] 
     115        // if we loop over answersRight from the top down, and inner loop over 
     116        // answersLeft top down, 
     117        // we can compare/remove obs from left 
     118        /* 
     119         * for (List<Object> row : answersRight) { Object rightValue = 
     120         * row.get(0); Date rightDate = (Date)row.get(1); int x = 0; while (x < 
     121         * answersLeft.size()) { List<Object> leftRow = answersLeft.get(x++); 
     122         * if (rightValue.equals(leftRow.get(0))) { Date leftDate = (Date) 
     123         * leftRow.get(1); if (leftDate.before(rightDate)) 
     124         * answersLeft.remove(--x); } } } 
     125         *  
     126         * return answersLeft; 
     127         */ 
     128 
     129        List<List<Object>> sortedAnswers = new Vector<List<Object>>(); 
     130        if (answerHash.size() > 0) 
     131            for (List<Object> value : answerHash.values()) 
     132                sortedAnswers.add(value); 
     133        Collections.sort(sortedAnswers, new DateComparator()); 
     134 
     135        return sortedAnswers; 
     136    } 
     137 
     138    /** 
     139     * Returns a list of [number, (years|months|days)] 
     140     *  
     141     * @param d 
     142     * @return 
     143     */ 
     144    public List<Object> getAge(Date birthdate) { 
     145        List<Object> returnList = new Vector<Object>(); 
     146 
     147        if (birthdate != null) { 
     148            Calendar today = Calendar.getInstance(); 
     149 
     150            Calendar bday = new GregorianCalendar(); 
     151            bday.setTime(birthdate); 
     152 
     153            int years = today.get(Calendar.YEAR) - bday.get(Calendar.YEAR); 
     154 
     155            // tricky bit: 
     156            // set birthday calendar to this year 
     157            // if the current date is less that the new 'birthday', subtract a 
     158            // year 
     159            bday.set(Calendar.YEAR, today.get(Calendar.YEAR)); 
     160            if (today.before(bday)) { 
     161                years = years - 1; 
     162            } 
     163 
     164            if (years > 1) { 
     165                returnList.add(years); 
     166                returnList.add("years"); 
     167                return returnList; 
     168            } else { 
     169                // calculate months 
     170                int months = today.get(Calendar.MONTH) 
     171                        - bday.get(Calendar.MONTH); 
     172                if (months < 0) // if this overlaps the new year 
     173                    months = 12 + months + (years > 0 ? 12 : 0); 
     174 
     175                if (months > 1) { 
     176                    returnList.add(months); 
     177                    returnList.add("months"); 
     178                    return returnList; 
     179                } 
     180 
     181                // calculate weeks 
     182                int days = today.get(Calendar.DAY_OF_YEAR) 
     183                        - bday.get(Calendar.DAY_OF_YEAR); 
     184                if (days < 0) // if this overlaps the new year 
     185                    days = 365 - bday.get(Calendar.DAY_OF_YEAR) 
     186                            + today.get(Calendar.DAY_OF_YEAR); 
     187 
     188                if (days > 7) { 
     189                    returnList.add((int) days / 7); 
     190                    returnList.add("weeks"); 
     191                    return returnList; 
     192                } else { 
     193                    returnList.add(days); 
     194                    returnList.add("days"); 
     195                    return returnList; 
     196                } 
     197 
     198            } 
     199        } 
     200 
     201        returnList.add(""); 
     202        returnList.add(""); 
     203        return returnList; 
     204    } 
     205 
     206    /** 
     207     * Finds all <code>conceptNames</code>s within the last 
     208     * <code>withinNumberOfMonths</code> months 
     209     *  
     210     * @param conceptName 
     211     * @param withinNumberOfMonths 
     212     * @return 
     213     * @throws Exception 
     214     */ 
     215    public List<Object> getObsTimeframe(String conceptName, 
     216            Integer withinNumberOfMonths) throws Exception { 
     217        Concept c = getConcept(conceptName); 
     218        List<String> arr = new Vector<String>(); 
     219 
     220        arr.add("obsDatetime"); 
     221        List<List<Object>> rows = getLastNObsWithValues(-1, c, arr); 
     222 
     223        Calendar cutoffDate = Calendar.getInstance(); 
     224        cutoffDate.add(Calendar.MONTH, -1 * withinNumberOfMonths); 
     225 
     226        List<Object> obsValues = new Vector<Object>(); 
     227 
     228        Calendar currentDate = Calendar.getInstance(); 
     229 
     230        for (List<Object> vals : rows) { 
     231            currentDate.setTime((Date) vals.get(1)); 
     232            if (cutoffDate.compareTo(currentDate) < 0) { 
     233                obsValues.add(vals.get(0)); 
     234            } 
     235        } 
     236 
     237        return obsValues; 
     238    } 
     239 
     240    /** 
     241     * Simple temporary hack method to get Clinical Summary reminder for CD4 
     242     * count. The rules are: 1. If there has never been a CD4 count for this 
     243     * patient, then remind to have one taken now. 2. If there has been more 
     244     * than one CD4 count taken, do nothing for now. This is not yet 
     245     * implemented. 3. If there has been exactly one CD4 count, and it was more 
     246     * than six months ago, remind to check CD4 count now. If it was less than 
     247     * six months ago, then remind to check CD4 count on the specified month and 
     248     * year. 4. If there have been more than one CD4 count and all CD4 counts 
     249     * occurred within the same 24-hour period, then treat it as if there were 
     250     * exactly one CD4 count. 
     251     *  
     252     * @return String reminder 
     253     * @throws Exception 
     254     */ 
     255    public String getCD4CountReminder() throws Exception { 
     256        boolean duplicateCD4Obs = false; 
     257        DateFormat dateFormat = new SimpleDateFormat("MMMMM, yyyy"); 
     258        GregorianCalendar tomorrow = new GregorianCalendar(); 
     259        tomorrow.add(Calendar.DAY_OF_MONTH, 1); 
     260        GregorianCalendar sixMosAgo = new GregorianCalendar(); 
     261        sixMosAgo.add(Calendar.MONTH, -6); 
     262        GregorianCalendar conceptDatetime = new GregorianCalendar(); 
     263        Concept cd4 = getConcept("5497"); // name='CD4, BY FACS' 
     264        Set<Obs> obs = Context.getObsService().getObservations(getPatient(), 
     265                cd4, false); 
     266        // No CD4 count. 
     267        if (obs.isEmpty()) { 
     268            return "No CD4 count has been taken.  Please check CD4 count now."; 
     269        } 
     270        // More than one CD4 count 
     271        else if (obs.size() > 1) { 
     272            GregorianCalendar firstCD4 = new GregorianCalendar(); 
     273            GregorianCalendar lastCD4 = new GregorianCalendar(); 
     274            GregorianCalendar thisCD4 = new GregorianCalendar(); 
     275            int cnt = 0; 
     276            for (Obs o : obs) { 
     277                if (++cnt == 1) { 
     278                    firstCD4.setTime(o.getObsDatetime()); 
     279                    lastCD4.setTime(o.getObsDatetime()); 
     280                } 
     281                thisCD4.setTime(o.getObsDatetime()); 
     282                firstCD4 = thisCD4.before(firstCD4) ? thisCD4 : firstCD4; 
     283                lastCD4 = thisCD4.after(lastCD4) ? thisCD4 : lastCD4; 
     284            } 
     285            if (Math 
     286                    .abs(lastCD4.getTimeInMillis() - firstCD4.getTimeInMillis()) < 86400000) { 
     287                // All CD4's have been taken within the same 24 hour time span. 
     288                // Consider them the same day. 
     289                duplicateCD4Obs = true; 
     290            } else { 
     291                return " "; 
     292            } 
     293        } 
     294        // Exactly one CD4 count 
     295        if (obs.size() == 1 || duplicateCD4Obs) { 
     296            for (Obs o : obs) { 
     297                conceptDatetime.setTime(o.getObsDatetime()); 
     298                if (conceptDatetime.before(sixMosAgo)) { 
     299                    return "CD4 count needs rechecked.  Please check CD4 count now."; 
     300                } else if (conceptDatetime.after(sixMosAgo) 
     301                        && conceptDatetime.before(tomorrow)) { 
     302                    Calendar nextCD4 = (Calendar) conceptDatetime.clone(); 
     303                    nextCD4.add(Calendar.MONTH, 6); 
     304                    return new String("Please check CD4 count in " 
     305                            + dateFormat.format(nextCD4.getTime()) + "."); 
     306                } else { 
     307                    return " "; 
     308                } 
     309            } 
     310        } 
     311        return " "; 
     312    } 
     313 
     314    /** 
     315     * Returns a patient property as a list 
     316     *  
     317     * @param className 
     318     * @param property 
     319     * @return list of values for given property 
     320     */ 
     321    @SuppressWarnings("unchecked") 
     322    public Object[] getPatientAttrAsList(String className, String property) { 
     323        return (Object[]) super.getPatientAttr(className, property, true); 
     324    } 
     325 
     326    protected List<EncounterType> validEncounterTypes = new Vector<EncounterType>(); // set 
     327 
     328    // in 
     329    // constructor 
     330 
     331    protected Map<Integer, Encounter> patientIdLastValidEncounter = null; 
     332 
     333    protected Map<Integer, Object /* Date */> patientIdLastValidEncounterDatetime = null; 
     334 
     335    // protected Map<Integer, Map<Integer, List<List<Object>>>> conceptMap = 
     336    // null; 
     337    protected Map<Integer, Map<Integer, List<Object>>> conceptMap = null; 
     338 
     339    protected Map<Integer, Concept> cachedConcepts = null; 
     340 
     341    /** 
     342     *  
     343     * @return List of [medication, date] objects 
     344     */ 
     345    public List<List<Object>> getAmpathActiveMedications() { 
     346 
     347        ClinicalSummaryService css = (ClinicalSummaryService) Context 
     348                .getService(ClinicalSummaryService.class); 
     349 
     350        // set up all of the obs and encounter maps 
     351        if (conceptMap == null) { 
     352            // conceptMap = new HashMap<Integer, Map<Integer, 
     353            // List<List<Object>>>>(); 
     354            conceptMap = new HashMap<Integer, Map<Integer, List<Object>>>(); 
     355 
     356            List<String> attrs = new Vector<String>(); 
     357&n