/** * */ package com.transitwidget.prefs; import java.util.ArrayList; import java.util.List; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import com.transitwidget.api.ServiceProvider; import com.transitwidget.feed.model.Agency; import com.transitwidget.feed.model.Direction; import com.transitwidget.feed.model.Route; import com.transitwidget.provider.contract.WidgetConfiguration; /** * @author james * */ public class NextBusObserverConfig { private final Context ctx; private final int widgetId; private NextBusAgencyField af = new NextBusAgencyField(); private NextBusRouteField rf = new NextBusRouteField(); private NextBusDirectionField df = new NextBusDirectionField(); private NextBusStopField sf = new NextBusStopField(); /** Seconds in the day */ private int startObserving; /** Seconds in the day */ private int stopObserving; public NextBusObserverConfig(Context ctx, int widgetId) { this.ctx = ctx; this.widgetId = widgetId; af.setNext(rf); rf.setNext(df); df.setNext(sf); // Load from database String selection = WidgetConfiguration.WIDGET_ID + " = ?"; String[] selectionArgs = { String.valueOf(widgetId) }; Cursor cursor = ctx.getContentResolver().query(WidgetConfiguration.CONTENT_URI, null, selection, selectionArgs, null); if (cursor.moveToFirst()) { String agencyTag = cursor.getString(cursor.getColumnIndex(WidgetConfiguration.AGENCY)); String routeTag = cursor.getString(cursor.getColumnIndex(WidgetConfiguration.ROUTE)); String directionTag = cursor.getString(cursor.getColumnIndex(WidgetConfiguration.DIRECTION)); String stopTag = cursor.getString(cursor.getColumnIndex(WidgetConfiguration.STOP)); setAgency(new NextBusAgency().init(ServiceProvider.getAgency(ctx, agencyTag))); setRoute(new NextBusRoute().init(ServiceProvider.getRoute(ctx, agencyTag, routeTag))); setDirection(new NextBusDirection().init(ServiceProvider.getDirection(ctx, agencyTag, directionTag))); setStop(new NextBusStop().init(ServiceProvider.getStop(ctx, agencyTag, stopTag))); setStartObserving(cursor.getInt(cursor.getColumnIndex(WidgetConfiguration.START_TIME))); setStopObserving(cursor.getInt(cursor.getColumnIndex(WidgetConfiguration.END_TIME))); } else { this.startObserving = -1; this.stopObserving = -1; } cursor.close(); if (this.startObserving == this.stopObserving && this.startObserving != -1) { this.startObserving = this.stopObserving = -1; } } public void save() { // Persist to database ContentValues values = new ContentValues(); values.put(WidgetConfiguration.WIDGET_ID, widgetId); values.put(WidgetConfiguration.AGENCY, getAgencyField().getTag()); values.put(WidgetConfiguration.ROUTE, getRouteField().getTag()); values.put(WidgetConfiguration.DIRECTION, getDirectionField().getTag()); values.put(WidgetConfiguration.STOP, getStopField().getTag()); values.put(WidgetConfiguration.START_TIME, getStartObserving()); values.put(WidgetConfiguration.END_TIME, getStopObserving()); // Check for existing preferences String selection = WidgetConfiguration.WIDGET_ID + " = ?"; String[] selectionArgs = { String.valueOf(widgetId) }; Cursor cursor = ctx.getContentResolver().query(WidgetConfiguration.CONTENT_URI, null, selection, selectionArgs, null); if (cursor.moveToFirst()) { ctx.getContentResolver().update(WidgetConfiguration.CONTENT_URI, values, selection, selectionArgs); } else { ctx.getContentResolver().insert(WidgetConfiguration.CONTENT_URI, values); } cursor.close(); } private static boolean safeEquals(Object a, Object b) { if (a == null) { return b == null; } else { return a.equals(b); } } public List<NextBusAgency> getAgencies() { return getAgencyField().loadValidValues(); } public NextBusAgency getAgency() { return getAgencyField().get(); } public void setAgency(NextBusAgency newAgency) { getAgencyField().set(newAgency); } public List<NextBusRoute> getRoutes() { return getRouteField().loadValidValues(); } public NextBusRoute getRoute() { return getRouteField().get(); } public void setRoute(NextBusRoute route) { getRouteField().set(route); } public List<NextBusDirection> getDirections() { return getDirectionField().loadValidValues(); } public NextBusDirection getDirection() { return getDirectionField().get(); } public void setDirection(NextBusDirection direction) { getDirectionField().set(direction); } public List<NextBusStop> getStops() { return getStopField().loadValidValues(); } public NextBusStop getStop() { return getStopField().get(); } public void setStop(NextBusStop stop) { getStopField().set(stop); } public int getStartObserving() { return startObserving; } public void setStartObserving(int startObserving) { this.startObserving = startObserving; } public int getStopObserving() { return stopObserving; } public void setStopObserving(int stopObserving) { this.stopObserving = stopObserving; } protected abstract class AbstractNextBusField<T extends NextBusValue> implements NextBusField<T> { protected T value = null; protected NextBusField<?> next; protected List<T> validValues = null; public void setNext(NextBusField<?> next) { this.next = next; } public boolean isSet() { return value != null; } public T get() { return value; } public String getTag() { if (value != null) { return value.getTag(); } else { return null; } } public boolean set(T value) { if (safeEquals(this.value, value)) { return false; } this.value = value; if (next != null) next.clear(); return true; } public void clear() { value = null; validValues = null; if (next != null) next.clear(); } public boolean hasValidValuesLoaded() { return validValues != null; } public final List<T> loadValidValues() { if (!hasValidValuesLoaded()) { validValues = doLoadValidValues(); } return validValues; } protected abstract List<T> doLoadValidValues(); public List<T> getValidValues() { return validValues; } public int indexOf(T value) { if (hasValidValuesLoaded()) { for (int i = 0; i < validValues.size(); i++) { if (validValues.get(i).equals(value)) return i; } } return -1; } } protected class NextBusAgencyField extends AbstractNextBusField<NextBusAgency> { @Override protected List<NextBusAgency> doLoadValidValues() { ArrayList<NextBusAgency> results = new ArrayList<NextBusAgency>(); for (Agency model : ServiceProvider.getAgencies(ctx)) { results.add(new NextBusAgency().init(model)); } return results; } } public NextBusField<NextBusAgency> getAgencyField() { return af; } protected class NextBusRouteField extends AbstractNextBusField<NextBusRoute> { @Override protected List<NextBusRoute> doLoadValidValues() { if (af.getTag() == null) return null; ArrayList<NextBusRoute> results = new ArrayList<NextBusRoute>(); for (Route model : ServiceProvider.getRoutes(ctx, af.getTag())) { results.add(new NextBusRoute().init(model)); } return results; } } public NextBusField<NextBusRoute> getRouteField() { return rf; } protected class NextBusDirectionField extends AbstractNextBusField<NextBusDirection> { @Override protected List<NextBusDirection> doLoadValidValues() { if (rf.getTag() == null) return null; ArrayList<NextBusDirection> results = new ArrayList<NextBusDirection>(); for (Direction model : ServiceProvider.getRouteConfig(ctx, af.getTag(), rf.getTag())) { results.add(new NextBusDirection().init(model)); } return results; } } public NextBusField<NextBusDirection> getDirectionField() { return df; } protected class NextBusStopField extends AbstractNextBusField<NextBusStop> { @Override protected List<NextBusStop> doLoadValidValues() { if (df.getTag() == null) return null; List<NextBusDirection> dirs = df.getValidValues(); if (dirs == null) return null; // Stops are attached to directions in the route config, not fetched // from the feed separately. Find the selected direction (this.direction // might be from prefs, and thus not have the list of stops). for (NextBusDirection d : dirs) { if (d.equals(df.get())) { return d.getStops(); } } return null; } } public NextBusField<NextBusStop> getStopField() { return sf; } }