package org.frasermccrossan.ltc; import java.util.Calendar; import java.util.regex.Matcher; import java.util.regex.Pattern; import android.content.Context; import android.content.res.Resources; import android.text.format.DateFormat; public class Prediction implements Comparable<Prediction> { static final Pattern DESTINATION_PATTERN = Pattern.compile("(?i) *to +((\\d+[a-z]?) +)?(.*)"); static final int OVER_12_HOURS = 12*60+5; static final int VERY_FAR_AWAY = 999999999; // something guaranteed to sort after everything LTCRoute route; String rawCrossingTime; String destination; String routeNumber; String errorMessage; Boolean seriousError; // just different visual effects when displayed String crossInMinutes; String crossAt; HourMinute hourMin; public int timeDifference; Boolean isQuerying = false; Boolean isFirst = false; Prediction(LTCRoute r, String crossTime, String dest, Calendar reference) { route = r; routeNumber = route.getRouteNumber(); rawCrossingTime = crossTime; destination = dest; errorMessage = null; seriousError = false; Matcher destMatcher = DESTINATION_PATTERN.matcher(destination); if (destMatcher.find()) { // a heuristic to convert "2 TO 2A Bla bla Street" into "2A Bla Bla Street" destination = destMatcher.group(3); if (destMatcher.group(2) != null) { routeNumber = destMatcher.group(2); } } hourMin = new HourMinute(reference, crossTime); timeDifference = hourMin.timeDiff(reference); } Prediction(LTCRoute r, String err, Boolean serious) { route = r; routeNumber = route.getRouteNumber(); rawCrossingTime = destination = null; errorMessage = err; seriousError = serious; timeDifference = VERY_FAR_AWAY; } Prediction(Context c, LTCRoute r, int errRes, Boolean serious) { route = r; routeNumber = route.getRouteNumber(); rawCrossingTime = destination = null; Resources resources = c.getResources(); errorMessage = resources.getString(errRes); seriousError = serious; timeDifference = VERY_FAR_AWAY; } Boolean isValid() { return errorMessage == null; } Boolean blankDestination() { return destination != null && destination.equals(""); } Boolean isSerious() { return seriousError; } Boolean isOnRoute(LTCRoute otherRoute) { return otherRoute.number.equals(route.number) && otherRoute.directionName.equals(route.directionName); } String routeNumber() { return routeNumber; } int routeDirectionImgRes() { return route.getDirectionDrawableRes(); } String routeLongName() { return route.name; } String destination() { if (errorMessage == null) { return destination; } else { return errorMessage; } } String crossAt() { if (isQuerying) { return ""; } else { return crossAt; } } String crossInMinutes() { if (isQuerying) { return ""; } else { return crossInMinutes; } } // update the text time representations at the given time-stamp void updateFields(Context context, Calendar time) { if (isValid()) { if (timeDifference >= 0 && timeDifference < HourMinute.DAY_MINUTES - 60) { Calendar absTime = (Calendar)time.clone(); absTime.add(Calendar.MINUTE, timeDifference); java.text.DateFormat absFormatter = DateFormat.getTimeFormat(context); absFormatter.setCalendar(absTime); crossInMinutes = minutesAsText(context, timeDifference); crossAt = absFormatter.format(absTime.getTime()); } else { crossInMinutes = crossAt = ""; } } else { crossInMinutes = crossAt = ""; } } String minutesAsText(Context c, long minutes) { if (minutes < 0) { return "?"; } if (minutes < 60) { return String.format("%d min", minutes); } if (minutes > OVER_12_HOURS) { return "----"; } else { return String.format("%dh%dm", minutes / 60, minutes % 60); } } void setQuerying() { isQuerying = true; } Boolean isQuerying() { return isQuerying; } @Override public int compareTo(Prediction other) { int timeDiff = timeDifference - other.timeDifference; if (timeDiff != 0) { return timeDiff; } return route.number.compareTo(other.route.number); } }