Newer
Older
package edu.ncsu.csc.itrust.action;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import edu.ncsu.csc.itrust.beans.DiagnosisBean;
import edu.ncsu.csc.itrust.beans.DiagnosisStatisticsBean;
import edu.ncsu.csc.itrust.dao.DAOFactory;
import edu.ncsu.csc.itrust.dao.mysql.DiagnosesDAO;
import edu.ncsu.csc.itrust.dao.mysql.ICDCodesDAO;
import edu.ncsu.csc.itrust.exception.DBException;
import edu.ncsu.csc.itrust.exception.FormValidationException;
import edu.ncsu.csc.itrust.exception.ITrustException;
/**
* Used for the View Diagnosis Statistics page. Can return a list of all Diagnoses
* and get diagnosis statistics for a specified Zip code, Diagnosis code, and date range.
*/
public class ViewDiagnosisStatisticsAction {
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
/** Database access methods for ICD codes (diagnoses) */
private ICDCodesDAO icdDAO;
/** Database access methods for diagnosis information */
private DiagnosesDAO diagnosesDAO;
/** ICD Code for malaria */
private static final String ICD_MALARIA = "84.50";
/** ICD Code for Influenza */
private static final String ICD_INFLUENZA = "487.00";
/**
* Constructor for the action. Initializes DAO fields
* @param factory The session's factory for DAOs
*/
public ViewDiagnosisStatisticsAction(DAOFactory factory) {
this.icdDAO = factory.getICDCodesDAO();
this.diagnosesDAO = factory.getDiagnosesDAO();
}
/**
* Gets all the diagnosis codes in iTrust and returns them in a list of beans.
*
* @return List of DiagnosisBeans correlating to all ICDCodes
* @throws ITrustException
*/
public List<DiagnosisBean> getDiagnosisCodes() throws ITrustException {
return icdDAO.getAllICDCodes();
}
/**
* Gets the counts of local and regional diagnoses for the specified input
*
* @param lowerDate The beginning date for the time range
* @param upperDate The ending date for the time range
* @param icdCode The diagnosis code to examine
* @param zip The zip code to examine
* @return A bean containing the local and regional counts
* @throws FormValidationException
* @throws ITrustException
*/
public DiagnosisStatisticsBean getDiagnosisStatistics(String lowerDate, String upperDate, String icdCode, String zip) throws FormValidationException, ITrustException {
DiagnosisStatisticsBean dsBean;
try {
if (lowerDate == null || upperDate == null || icdCode == null)
return null;
Date lower = new SimpleDateFormat("MM/dd/yyyy").parse(lowerDate);
Date upper = new SimpleDateFormat("MM/dd/yyyy").parse(upperDate);
if (lower.after(upper))
throw new FormValidationException("Start date must be before end date!");
if (!zip.matches("([0-9]{5})|([0-9]{5}-[0-9]{4})"))
throw new FormValidationException("Zip Code must be 5 digits!");
boolean validCode = false;
for(DiagnosisBean diag : getDiagnosisCodes()) {
if (diag.getICDCode().equals(icdCode))
validCode = true;
}
if (validCode == false) {
throw new FormValidationException("ICDCode must be valid diagnosis!");
}
dsBean = diagnosesDAO.getDiagnosisCounts(icdCode, zip, lower, upper);
} catch (ParseException e) {
throw new FormValidationException("Enter dates in MM/dd/yyyy");
}
return dsBean;
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
/**
* Gets the local and regional counts for the specified week and calculates the prior average.
*
* @param startDate a date in the week to analyze
* @param icdCode the diagnosis to analyze
* @param zip the area to analyze
* @param threshold threshold
* @return statistics for the week and previous averages
* @throws FormValidationException
* @throws DBException
*/
public ArrayList<DiagnosisStatisticsBean> getEpidemicStatistics(String startDate, String icdCode, String zip, String threshold) throws FormValidationException, DBException {
if (startDate == null || icdCode == null)
return null;
if (!(icdCode.equals("84.50") || icdCode.equals("487.00")) ) {
throw new FormValidationException("Invalid ICD code.");
}
if(ICD_MALARIA.equals(icdCode)){
try{
Integer.parseInt(threshold);
}catch(NumberFormatException e){
throw new FormValidationException("Threshold must be an integer.");
}
}
Date lower; //lower, which is parsed to startDate
try {
lower = new SimpleDateFormat("MM/dd/yyyy").parse(startDate);
} catch (ParseException e) {
throw new FormValidationException("Enter dates in MM/dd/yyyy");
}
if (!zip.matches("([0-9]{5})|([0-9]{5}-[0-9]{4})"))
throw new FormValidationException("Zip Code must be 5 digits!");
DiagnosisStatisticsBean dbWeek = diagnosesDAO.getCountForWeekOf(icdCode, zip, lower);
DiagnosisStatisticsBean dbAvg = new DiagnosisStatisticsBean(zip, 0, 0, lower, lower);
Calendar cal = Calendar.getInstance();
Date start = diagnosesDAO.findEarliestIncident(icdCode); //start, which is set to earliest incident
Calendar startCal = Calendar.getInstance();
if(start != null)
startCal.setTime(start);
ArrayList<DiagnosisStatisticsBean> ret = new ArrayList<DiagnosisStatisticsBean>();
if (start == null) {
ret.add(dbWeek);
ret.add(dbAvg);
return ret;
}
cal.setTime(lower); //cal, which is set to lower
Calendar lowerCal = Calendar.getInstance();
lowerCal.setTime(lower);
int weekOfYr = cal.get(Calendar.WEEK_OF_YEAR);
cal.set(Calendar.YEAR, startCal.get(Calendar.YEAR)); //cal's year then gets set to start's year
ArrayList<DiagnosisStatisticsBean> dbList = new ArrayList<DiagnosisStatisticsBean>();
while( cal.getTime().before(lower) && cal.get(Calendar.YEAR) != lowerCal.get(Calendar.YEAR)) {
dbList.add( diagnosesDAO.getCountForWeekOf(icdCode, zip, cal.getTime()) );
cal.add(Calendar.YEAR, 1);
cal.set(Calendar.WEEK_OF_YEAR, weekOfYr);
cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
}
long avg = 0;
long avgRegion = 0;
if (dbList.size() > 0) {
for (DiagnosisStatisticsBean d : dbList) {
avg += d.getZipStats();
avgRegion += d.getRegionStats();
}
avg /= dbList.size();
avgRegion /= dbList.size();
}
dbAvg.setRegionStats(avgRegion);
dbAvg.setZipStats(avg);
ret.add(dbWeek);
ret.add(dbAvg);
return ret;
}
/**
* Determines if an Influenza Epidemic is happening
*
* @param weekDate a date in the currently evaluated week
* @param zip the zip code to analyze
* @return whether or not there is an epidemic
* @throws ParseException
* @throws DBException
*/
public boolean isFluEpidemic(String weekDate, String zip) throws ParseException, DBException {
//new SimpleDateFormat("MM/dd/yyyy").parse("01/04/1998");
Date wkDate = new SimpleDateFormat("MM/dd/yyyy").parse(weekDate);
ArrayList<DiagnosisStatisticsBean> historyWkL1 = new ArrayList<DiagnosisStatisticsBean>();
ArrayList<DiagnosisStatisticsBean> historyWkL2 = new ArrayList<DiagnosisStatisticsBean>();
cal.setTime(wkDate);
int weekOfYr = cal.get(Calendar.WEEK_OF_YEAR);
//double threshold = calcThreshold(weekOfYr);
double thresholdL1 = calcThreshold(weekOfYr-1);
double thresholdL2 = calcThreshold(weekOfYr-2);
//DiagnosisStatisticsBean current = diagnosesDAO.getCountForWeekOf(ICD_INFLUENZA, zip, cal.getTime());
//cal.add(Calendar.HOUR, -12*7);
DiagnosisStatisticsBean prev1 = diagnosesDAO.getCountForWeekBefore(ICD_INFLUENZA, zip, cal.getTime());
cal.add(Calendar.HOUR, -7*24);
DiagnosisStatisticsBean prev2 = diagnosesDAO.getCountForWeekBefore(ICD_INFLUENZA, zip, cal.getTime());
//double weekNow = (double) current.getRegionStats();
double weekL1 = (double) prev1.getRegionStats();
double weekL2 = (double) prev2.getRegionStats();
boolean epidemicL1 = weekL1 > thresholdL1;
boolean epidemicL2 = weekL2 > thresholdL2;
return epidemicL1 && epidemicL2;
}
/**
* Calculates the threshold of an influenza epidemic
*
* @param weekNumber the week of the year
* @return the epidemic threshold for flu cases
*/
private double calcThreshold(double weekNumber) {
return 5.34 + 0.271 * weekNumber + 3.45 * Math.sin(2 * Math.PI * weekNumber / 52.0) + 8.41 * Math.cos(2 * Math.PI * weekNumber / 52.0);
}
/**
* Determines whether a Malaria epidemic is happening for two consecutive weeks
* prior to the current date.
*
* @param weekDate a date in the currently evaluated week
* @param zip the zip code to analyze
* @param thresholdStr the threshold for an epidemic
* @return whether or not there is an epidemic
* @throws DBException
* @throws ParseException
*/
public boolean isMalariaEpidemic(String weekDate, String zip, String thresholdStr) throws DBException, ParseException {
Date wkDate = new SimpleDateFormat("MM/dd/yyyy").parse(weekDate);
ArrayList<DiagnosisStatisticsBean> historyWkL1 = new ArrayList<DiagnosisStatisticsBean>();
ArrayList<DiagnosisStatisticsBean> historyWkL2 = new ArrayList<DiagnosisStatisticsBean>();
double threshold = Double.parseDouble(thresholdStr);
cal.setTime(wkDate);
DiagnosisStatisticsBean current = diagnosesDAO.getCountForWeekOf(ICD_MALARIA, zip, cal.getTime());
DiagnosisStatisticsBean prev1 = diagnosesDAO.getCountForWeekBefore(ICD_MALARIA, zip, cal.getTime());
long weekTotalL1 = prev1.getRegionStats();
cal.add(Calendar.HOUR, -7*24);
DiagnosisStatisticsBean prev2 = diagnosesDAO.getCountForWeekBefore(ICD_MALARIA, zip, cal.getTime());
long weekTotalL2 = prev2.getRegionStats();
cal.setTime(wkDate);
//Find earliest Malaria Case. Set calendar's year to that year
Date startData = diagnosesDAO.findEarliestIncident(ICD_MALARIA);
if (startData == null) {
if (current.getRegionStats() > 0) {
return true;
}
return false;
}
Calendar startDateCal = Calendar.getInstance();
startDateCal.setTime(startData);
Calendar wkDateCal = Calendar.getInstance();
wkDateCal.setTime(wkDate);
cal.set(Calendar.YEAR, startDateCal.get(Calendar.YEAR));
while( cal.getTime().before(wkDate) && cal.get(Calendar.YEAR) != wkDateCal.get(Calendar.YEAR)) {
historyWkL1.add( diagnosesDAO.getCountForWeekBefore(ICD_MALARIA, zip, cal.getTime()) );
cal.add(Calendar.HOUR, -7*24);
historyWkL2.add( diagnosesDAO.getCountForWeekBefore(ICD_MALARIA, zip, cal.getTime()) );
cal.add(Calendar.HOUR, 7*24);
cal.add(Calendar.YEAR, 1);
long totalHistL1 = 0;
long totalHistL2 = 0;
long countHistL1 = historyWkL1.size();
long countHistL2 = historyWkL1.size();
for (DiagnosisStatisticsBean d : historyWkL1) {
totalHistL1 += d.getRegionStats();
}
for (DiagnosisStatisticsBean d : historyWkL2) {
totalHistL2 += d.getRegionStats();
}
double avgL1 = ((double)totalHistL1) / ((double)countHistL1);
double avgL2 = ((double)totalHistL2) / ((double)countHistL2);
boolean epidemicL1 = (weekTotalL1*100.0) / threshold > avgL1 || (countHistL1 == 0 && weekTotalL1 != 0);
boolean epidemicL2 = (weekTotalL2*100.0) / threshold > avgL2 || (countHistL2 == 0 && weekTotalL2 != 0);
return epidemicL1 && epidemicL2;