Skip to content
Snippets Groups Projects
ViewDiagnosisStatisticsAction.java 10.8 KiB
Newer Older
  • Learn to ignore specific revisions
  • HMoss's avatar
    HMoss committed
    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 {
    	/** 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;
    	}
    	
    	/**
    	 * 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.");
    
    HMoss's avatar
    HMoss committed
    		}
    		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 curDateStr 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 curDateStr, String zip) throws ParseException, DBException {
    		new SimpleDateFormat("MM/dd/yyyy").parse("01/04/1998");
    		Date curDate = new SimpleDateFormat("MM/dd/yyyy").parse(curDateStr);
    		
    		Calendar cal = Calendar.getInstance();
    		cal.setTime(curDate);
    		
    		int weekOfYr = cal.get(Calendar.WEEK_OF_YEAR);
    		double threshold = calcThreshold(weekOfYr);
    		double thresholdL = calcThreshold(weekOfYr-1);
    		double thresholdN = calcThreshold(weekOfYr+1); 
    		
    		DiagnosisStatisticsBean dbNow = diagnosesDAO.getCountForWeekOf(ICD_INFLUENZA, zip, cal.getTime());
    		cal.add(Calendar.HOUR, -12*7);
    		DiagnosisStatisticsBean dbLast = diagnosesDAO.getCountForWeekOf(ICD_INFLUENZA, zip, cal.getTime());
    		cal.add(Calendar.HOUR, 2*12*7);
    		DiagnosisStatisticsBean dbNext =  diagnosesDAO.getCountForWeekOf(ICD_INFLUENZA, zip, cal.getTime());
    		
    		double weekNow = (double) dbNow.getRegionStats();
    		double weekL = (double) dbLast.getRegionStats();
    		double weekN = (double) dbNext.getRegionStats();
    		
    		return weekNow > threshold && (weekL > thresholdL || weekN > thresholdN);
    		
    	}
    	
    	/**
    	 * 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);
    
    HMoss's avatar
    HMoss committed
    	
    	/**
    
    	 * Determines whether a Malaria epidemic is happening for two consecutive weeks
         * prior to the current date.
    
    HMoss's avatar
    HMoss committed
    	 * 
    	 * @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);
            
    
    HMoss's avatar
    HMoss committed
    		Calendar cal = Calendar.getInstance();
    
            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();
            
    
    HMoss's avatar
    HMoss committed
    		cal.add(Calendar.HOUR, -7*24);
    
    		DiagnosisStatisticsBean prev2 = diagnosesDAO.getCountForWeekBefore(ICD_MALARIA, zip, cal.getTime());
    		long weekTotalL2 = prev2.getRegionStats();
    
    HMoss's avatar
    HMoss committed
    		
    		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));
            
    
    HMoss's avatar
    HMoss committed
    		while( cal.getTime().before(wkDate) && cal.get(Calendar.YEAR) != wkDateCal.get(Calendar.YEAR)) {
    
    			historyWkL1.add( diagnosesDAO.getCountForWeekBefore(ICD_MALARIA, zip, cal.getTime()) );
    
    HMoss's avatar
    HMoss committed
    			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);
    
    HMoss's avatar
    HMoss committed
    		}
    		
    
            long totalHistL1 = 0;
            long totalHistL2 = 0;
            long countHistL1 = historyWkL1.size();
            long countHistL2 = historyWkL1.size();
            for (DiagnosisStatisticsBean d : historyWkL1) {
                totalHistL1 += d.getRegionStats();
    
    HMoss's avatar
    HMoss committed
    		}
    
    		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;
            boolean epidemicL2 = (weekTotalL2*100.0) / threshold > avgL2 || countHistL2 == 0;
            return epidemicL1 && epidemicL2;
    
    HMoss's avatar
    HMoss committed
    	}
    }