Newer
Older
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
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 {
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
71
72
73
/** 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;
sbobo3
committed
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
/**
* Gets the counts of local and regional diagnoses for the specified input (lower date 8 weeks prior to upper date)
*
* @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 upperDate, String icdCode, String zip) throws FormValidationException, ITrustException {
DiagnosisStatisticsBean dsBean;
try {
if (upperDate == null || icdCode == null)
return null;
Date upper = new SimpleDateFormat("MM/dd/yyyy").parse(upperDate);
//calculate lower date by finding the date that is 8 weeks prior to upperDate
Calendar cal = Calendar.getInstance();
cal.setTime(upper);
cal.add(Calendar.HOUR, -56*24);
Date lower = cal.getTime();
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 date in MM/dd/yyyy");
}
return dsBean;
}
public List<DiagnosisStatisticsBean> getDiagnosisTrends(String dateString, String icdCode, String zip) throws FormValidationException, ITrustException {
ArrayList<DiagnosisStatisticsBean> dsBean = null;
if (dateString == null || icdCode == null) {
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!");
}
if (!zip.matches("([0-9]{5})|([0-9]{5}-[0-9]{4})")) {
throw new FormValidationException("Zip Code must be 5 digits!");
}
Date next;
try {
DateFormat formatter = new SimpleDateFormat("MM/dd/yyyy");
formatter.setLenient(false);
next = formatter.parse(dateString);
} catch (ParseException e) {
throw new FormValidationException("Enter dates in MM/dd/yyyy");
}
if (next.after(new Date())) {
throw new FormValidationException("Provided date is in the future.");
}
dsBean = new ArrayList<>();
Calendar cal = Calendar.getInstance();
cal.setTime(next);
for (int i = 0; i < 8; i++) {
Date weekDate = cal.getTime();
dsBean.add(diagnosesDAO.getCountForWeekBefore(icdCode, zip, weekDate));
cal.add(Calendar.HOUR, -24*7);
}
/**
* 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) {
if (!(icdCode.equals("84.50") || icdCode.equals("487.00")) ) {
throw new FormValidationException("Invalid ICD code.");
}
} catch(NumberFormatException e) {
throw new FormValidationException("Threshold must be an integer.");
}
}
Date lower; //lower, which is parsed to startDate
try {
DateFormat formatter = new SimpleDateFormat("MM/dd/yyyy");
formatter.setLenient(false);
lower = formatter.parse(startDate);
} catch (ParseException e) {
throw new FormValidationException("Enter dates in MM/dd/yyyy");
}
if (lower.after(new Date())) {
throw new FormValidationException("Provided date is in the future.");
}
if (!zip.matches("([0-9]{5})|([0-9]{5}-[0-9]{4})")) {
throw new FormValidationException("Zip Code must be 5 digits!");
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
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 {
Date wkDate = new SimpleDateFormat("MM/dd/yyyy").parse(weekDate);
cal.setTime(wkDate);
int weekOfYr = cal.get(Calendar.WEEK_OF_YEAR);
double threshold = calcInfluenzaThreshold(weekOfYr);
DiagnosisStatisticsBean prev1 = diagnosesDAO.getCountForWeekBefore(ICD_INFLUENZA, zip, cal.getTime());
cal.add(Calendar.HOUR, -7*24);
DiagnosisStatisticsBean prev2 = diagnosesDAO.getCountForWeekBefore(ICD_INFLUENZA, zip, cal.getTime());
long weekL1 = prev1.getRegionStats();
long weekL2 = prev2.getRegionStats();
boolean epidemicL1 = weekL1 > threshold;
boolean epidemicL2 = weekL2 > threshold;
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 calcInfluenzaThreshold(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;