import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; import java.util.Calendar; /** * @author Isaac Bond */ public class WeatherBackend implements IWeatherBackend { private RedBlackTree<IForecast> tree; private char tempUnit = 'f'; private char speedUnit = 'i'; public WeatherBackend() { tree = new RedBlackTree<IForecast>(); } @Override public String getClosestDate(){ for (IForecast forecast : tree){ return forecast.getDate(); } return null; } @Override public void addForecast(IForecast forecast) { tree.insert(forecast); } @Override @SuppressWarnings("deprecation") public String getDateString(Date date){ String[] months = new String[]{"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"}; String dateString = ""+ months[date.getMonth()-1]+" "+date.getDay()+ ", "+date.getYear(); return dateString; } @Override public List<IForecast> getDay(String date) throws NoSuchElementException { // create return value List<IForecast> retval = new ArrayList<IForecast>(); // iterate through tree to find forecasts with this date for (IForecast forecast : tree) { if (forecast.getDate().equals(date)) // add to return list if this forecast happens on the date we're looking for retval.add(forecast); } if (retval.size() == 0) // throw exception if no forecasts were found with this date throw new NoSuchElementException(); return retval; } @Override public IForecast getAverage(List<IForecast> day) { double totalTemp = 0; double totalHigh = 0; double totalLow = 0; int totalHumid = 0; double totalWind = 0; ArrayList<String> windDirections = new ArrayList<String>(); ArrayList<String> conditions = new ArrayList<String>(); for (IForecast forecast : day) { totalHigh += forecast.getMaxTemp('k'); totalLow += forecast.getMinTemp('k'); totalTemp += forecast.getAverageTemp('k'); totalHumid += forecast.getHumidityPercentage(); totalWind += forecast.getWindSpeed('m'); windDirections.add(forecast.getWindDirection()); conditions.add(forecast.getDescription()); } int n = day.size(); double avgHigh = totalHigh / n; double avgLow = totalLow / n; double avgTemp = totalTemp / n; int avgHumid = totalHumid / n; double avgWind = totalWind / Double.valueOf(n); String windDirection = getMode(windDirections); String condition = getMode(conditions); String[] directions = new String[] {"N", "NE", "E", "SE", "S", "SW", "W", "NW"}; int[] degrees = new int[] {0, 45, 90, 135, 180, 225, 270, 315}; int windDirectionDeg = 0; for (int i=0; i<directions.length; i++) { if (directions[i] == windDirection) { windDirectionDeg = degrees[i]; } } return new Forecast(day.get(0).getTimeCode(), avgTemp, avgLow, avgHigh, condition, avgHumid, avgWind, windDirectionDeg); } // Taken from : https://stackoverflow.com/questions/716496/get-mode-value-in-java public static String getMode(ArrayList<String> values) { HashMap<String ,Integer> freqs = new HashMap<String,Integer>(); for (String val : values) { Integer freq = freqs.get(val); freqs.put(val, (freq == null ? 1 : freq+1)); } String mode = null; int maxFreq = 0; for (Map.Entry<String,Integer> entry : freqs.entrySet()) { int freq = entry.getValue(); if (freq > maxFreq) { maxFreq = freq; mode = entry.getKey(); } } return mode; } @Override public List<IForecast> getAverageWeek() { List<IForecast> retval = new ArrayList<IForecast>(); String[] months = new String[] {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"}; Calendar calendar = Calendar.getInstance(); int currDay = calendar.get(Calendar.DAY_OF_MONTH); String currMonth = months[calendar.get(Calendar.MONTH)]; int currYear = calendar.get(Calendar.YEAR); String currDate = currMonth + " " + currDay + ", " + currYear; ArrayList<String> daysToSkip = new ArrayList<String>(); for (IForecast forecast : tree) { // if we already found this date and averaged it out, skip it if (daysToSkip.contains(forecast.getDate())) continue; // if date of forecast is greater than current date and less than one week away, average and add to list if (forecast.compareTo(getDay(currDate).get(0)) < 168 && forecast.compareTo(getDay(currDate).get(0)) > 0) { retval.add(getAverage(getDay(forecast.getDate()))); daysToSkip.add(forecast.getDate()); } } return retval; } @Override public IForecast getHottestDay(List<IForecast> week) { IForecast hottestDay = null; for (int i=0; i<week.size(); i++) { if (hottestDay == null) hottestDay = week.get(i); else if (week.get(i).getAverageTemp(tempUnit) > hottestDay.getAverageTemp(tempUnit)) hottestDay = week.get(i); } return hottestDay; } /** * Gets current scale setting * @return 'f' if scale is currently fahrenheit and 'c' if scale is currently celsius */ @Override public char getTempUnit(){ return tempUnit; } @Override public char getSpeedUnit() { return speedUnit; } /** * Sets temperature unit * @param unit unit to be switched to */ @Override public void setTempUnit(char unit) { tempUnit = unit; } /** * Sets speed unit * @param unit unit to be switched to */ @Override public void setSpeedUnit(char unit) { speedUnit = unit; } }