package edu.mit.mitmobile2.dining; import java.util.Calendar; import java.util.GregorianCalendar; import java.util.HashMap; import java.util.List; import edu.mit.mitmobile2.dining.DiningModel.DailyMeals; import edu.mit.mitmobile2.dining.DiningModel.HouseDiningHall; import edu.mit.mitmobile2.dining.DiningModel.Meal; public class DiningMealIterator { List<HouseDiningHall> mHalls; public class MealOrEmptyDay { Calendar mDay; HashMap<String, Meal> mMeals = new HashMap<String, Meal>(); public MealOrEmptyDay(Calendar day) { mDay = day; } public boolean isEmpty() { return (mMeals.size() == 0); } public List<HouseDiningHall> getHalls() { return mHalls; } public Calendar getDay() { return mDay; } public Calendar getDay(HouseDiningHall house) { if (mMeals.containsKey(house.getID())) { return mMeals.get(house.getID()).mStart; } else { return mDay; } } public Meal getMeal(String hallID) { return mMeals.get(hallID); } private Meal getAnyMeal() { if (!mMeals.isEmpty()) { return mMeals.entrySet().iterator().next().getValue(); } return null; } public String getCapitalizedMealName() { Meal meal = getAnyMeal(); if (meal != null) { return meal.getCapitalizedName(); } throw new RuntimeException("No meals to be named"); } public String getDayMessage() { if (mHalls.size() == 1) { DailyMeals meals = mHalls.get(0).getSchedule().getDailyMeals(mDay); if (meals != null && meals.getMessage() != null) { return meals.getMessage(); } } // since we can't find or decide which message to use, use a default if (isEmpty()) { return "No Information Available"; } else { return null; } } } private MealPointer mCurrentMealPointer; private boolean mScheduleUnavailable; private static class MealPointer { private Calendar mDay; private String mMealName; public MealPointer(Calendar day, String mealName) { mDay = day; mMealName = mealName; } } public DiningMealIterator(Calendar day, List<HouseDiningHall> halls) { mHalls = halls; String mealName = DailyMeals.getFirstMealName(); String lastTodayMealName = null; while (mealName != null) { for (HouseDiningHall hall : mHalls) { DailyMeals dailyMeals = hall.getSchedule().getDailyMeals(day); if (dailyMeals != null) { Meal meal = dailyMeals.getMeal(mealName); if (meal != null) { lastTodayMealName = mealName; if (meal.isUpcoming(day) || meal.isInProgress(day)) { // found a meal which is not completed // start here mCurrentMealPointer = new MealPointer(day, mealName); return; } } } } mealName = DailyMeals.getNextMealName(mealName); } mCurrentMealPointer = new MealPointer(day, lastTodayMealName); mScheduleUnavailable = isAfterAllSchedules(day) || isBeforeAllSchedules(day); } private MealOrEmptyDay getMealOrEmptyDay(Calendar day, String mealName) { MealOrEmptyDay mealOrEmptyDay = new MealOrEmptyDay(day); for (HouseDiningHall hall : mHalls) { DailyMeals dailyMeals = hall.getSchedule().getDailyMeals(day); if (dailyMeals != null) { Meal meal = dailyMeals.getMeal(mealName); if (meal != null) { mealOrEmptyDay.mMeals.put(hall.getID(), meal); } } } return mealOrEmptyDay; } public void moveToPrevious() { mCurrentMealPointer = getPointerToPreviousMeal(mCurrentMealPointer); } public void moveToNext() { mCurrentMealPointer = getPointerToNextMeal(mCurrentMealPointer); } public MealOrEmptyDay getCurrent() { return getMealOrEmptyDay(mCurrentMealPointer.mDay, mCurrentMealPointer.mMealName); } public boolean hasNext() { return !mScheduleUnavailable && (getPointerToNextMeal(mCurrentMealPointer) != null); } public MealOrEmptyDay getNext() { MealPointer mealPointer = getPointerToNextMeal(mCurrentMealPointer); return getMealOrEmptyDay(mealPointer.mDay, mealPointer.mMealName); } public boolean hasPrevious() { return !mScheduleUnavailable && (getPointerToPreviousMeal(mCurrentMealPointer) != null); } public MealOrEmptyDay getPrevious() { MealPointer mealPointer = getPointerToPreviousMeal(mCurrentMealPointer); return getMealOrEmptyDay(mealPointer.mDay, mealPointer.mMealName); } private MealPointer getPointerToNextMeal(MealPointer mealPointer) { String nextMealName = DailyMeals.getNextMealName(mealPointer.mMealName); MealPointer nextMealPointer = getNextForDay(mealPointer.mDay, nextMealName); if (nextMealPointer.mMealName != null) { // another meal found today return nextMealPointer; } // no more meals for current day, check next day Calendar nextDay = new GregorianCalendar(); nextDay.setTime(mealPointer.mDay.getTime()); nextDay.add(Calendar.DATE, 1); if (isAfterAllSchedules(nextDay)) { return null; } return getNextForDay(nextDay, DailyMeals.getFirstMealName()); } private MealPointer getNextForDay(Calendar day, String mealName) { while(mealName != null) { MealOrEmptyDay mealOrEmptyDay = getMealOrEmptyDay(day, mealName); if (!mealOrEmptyDay.isEmpty()) { return new MealPointer(day, mealName); } mealName = DailyMeals.getNextMealName(mealName); } return new MealPointer(day, null); } private boolean isAfterAllSchedules(Calendar day) { for (HouseDiningHall hall : mHalls) { if (!hall.getSchedule().isAfterAllDays(day)) { return false; } } return true; } private MealPointer getPointerToPreviousMeal(MealPointer mealPointer) { String previousMealName = DailyMeals.getPreviousMealName(mealPointer.mMealName); MealPointer previousMealPointer = getPreviousForDay(mealPointer.mDay, previousMealName); if (previousMealPointer.mMealName != null) { // another meal found today return previousMealPointer; } // no more meals for current day, check next day Calendar previousDay = new GregorianCalendar(); previousDay.setTime(mealPointer.mDay.getTime()); previousDay.add(Calendar.DATE, -1); if (isBeforeAllSchedules(previousDay)) { return null; } return getPreviousForDay(previousDay, DailyMeals.getLastMealName()); } private MealPointer getPreviousForDay(Calendar day, String mealName) { while(mealName != null) { MealOrEmptyDay mealOrEmptyDay = getMealOrEmptyDay(day, mealName); if (!mealOrEmptyDay.isEmpty()) { return new MealPointer(day, mealName); } mealName = DailyMeals.getPreviousMealName(mealName); } return new MealPointer(day, null); } private boolean isBeforeAllSchedules(Calendar day) { for (HouseDiningHall hall : mHalls) { if (!hall.getSchedule().isBeforeAllDays(day)) { return false; } } return true; } }