/* * Southampton University Map App * Copyright (C) 2011 Christopher Baines * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package net.cbaines.suma; import java.sql.SQLException; import java.util.ArrayList; import java.util.Calendar; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import android.content.Context; import android.util.Log; import com.j256.ormlite.android.apptools.OpenHelperManager; import com.j256.ormlite.dao.Dao; import com.j256.ormlite.field.DatabaseField; import com.j256.ormlite.stmt.PreparedQuery; import com.j256.ormlite.stmt.QueryBuilder; import com.j256.ormlite.table.DatabaseTable; /** * This class represents a bus route (U1, U1N, ..). * * @author Christopher Baines * */ @DatabaseTable(tableName = "busroutes") public class BusRoute { private static final String TAG = "BusRoute"; final static String ID_FIELD_NAME = "id"; final static String CODE_FIELD_NAME = "code"; final static String LABEL_FIELD_NAME = "label"; @DatabaseField(id = true) public int id; /** * The route code (U1, U1N, ...) */ @DatabaseField public String code; @DatabaseField(canBeNull = false) String label; /** * The direction the bus is travelling if it is moving through the route and sequence is increasing. * */ @DatabaseField(canBeNull = true) String forwardDirection; /** * The direction the bus is travelling if it is moving through the route and sequence is decreasing. * */ @DatabaseField(canBeNull = true) String reverseDirection; @DatabaseField(canBeNull = false) boolean uniLink; BusRoute() { } public BusRoute(Integer id, String code, String label, String forwardDirection, String reverseDirection, boolean uniLink) { this.id = id.intValue(); this.code = code; this.label = label; this.forwardDirection = forwardDirection; this.reverseDirection = reverseDirection; this.uniLink = uniLink; } public BusRoute(Integer id, String code, String label, boolean uniLink) { this(id, code, label, null, null, uniLink); } public String toString() { return code; } /** * Untested? * * @param context * @param stop * @return */ BusStop getBusStopBefore(Context context, BusStop stop, String dir) { return moveInRoute(context, stop, dir, -1); } /** * Untested? * * @param context * @param stop * @return */ BusStop getStopAfter(Context context, BusStop stop, String dir) { return moveInRoute(context, stop, dir, 1); } /** * Return the set of bus stops that can be thought of moveAmount away from the busStop. The method returns a set as for some * movements, the destination stop is ambiguous. * * @param context * @param busStop * @param moveAmount * @return */ Set moveInRoute(final Context context, final BusStop busStop, final int moveAmount) { Set busStops = new HashSet(); if (moveAmount == 0) { busStops.add(busStop); return busStops; } DatabaseHelper helper = OpenHelperManager.getHelper(context, DatabaseHelper.class); try { Dao routeStopsDao = helper.getRouteStopsDao(); Dao busStopDao = helper.getBusStopDao(); QueryBuilder routeStopsQueryBuilder = routeStopsDao.queryBuilder(); routeStopsQueryBuilder.where().eq(RouteStop.ROUTE_ID_FIELD_NAME, this.id); PreparedQuery routeStopsPreparedQuery = routeStopsQueryBuilder.prepare(); List routeStopsFound = routeStopsDao.query(routeStopsPreparedQuery); Collections.sort(routeStopsFound); // Starting from 1, as the data does :( Set stopIndexs = new HashSet(); for (RouteStop routeStop : routeStopsFound) { if (routeStop.busStop.id.equals(busStop.id)) { stopIndexs.add(routeStop.sequence); } } for (int stopIndex : stopIndexs) { if (moveAmount > 0) { Log.v(TAG, "Moving forward " + moveAmount + " stops from " + busStop + " (" + stopIndex + "/" + routeStopsFound.size() + ")"); int stopWantedSeq = stopIndex + moveAmount; if (stopWantedSeq > routeStopsFound.size()) { Log.v(TAG, "Off the end of the route"); stopWantedSeq = ((stopWantedSeq - 1) % (routeStopsFound.size())) + 1; } Log.v(TAG, " Stop wanted " + stopWantedSeq); BusStop busStopWanted = routeStopsFound.get(stopWantedSeq - 1).busStop; busStopDao.refresh(busStopWanted); Log.v(TAG, " Moving to " + busStopWanted + " (" + stopWantedSeq + ") in route " + this); busStops.add(busStopWanted); } else { Log.v(TAG, "stopIndex " + stopIndex); int stopWanted = stopIndex + moveAmount; // This will end up as the sequence number of the wanted stop if (stopWanted < 1) { stopWanted = routeStopsFound.size() - (Math.abs(stopWanted) % routeStopsFound.size()); } Log.v(TAG, "stopWanted " + stopWanted); BusStop wantedBusStop = routeStopsFound.get(stopWanted - 1).busStop; // Need the -1 as sequence starts at 1 busStopDao.refresh(wantedBusStop); Log.v(TAG, "Moving backwards " + (-1 * moveAmount) + " stops from " + busStop + " to " + wantedBusStop + " in route " + this); busStops.add(wantedBusStop); } } return busStops; } catch (SQLException e) { e.printStackTrace(); } Log.e(TAG, "Error moving in route"); return null; } /** * Untested? * * @param context * @param busStop * @param moveAmount * @return */ BusStop moveInRoute(final Context context, final BusStop busStop, String direction, final int moveAmount) { if (moveAmount == 0) { return busStop; } DatabaseHelper helper = OpenHelperManager.getHelper(context, DatabaseHelper.class); if (forwardDirection != null) { if (direction != null) { if (direction.equals("E")) direction = "A"; // Quick hack for U1E } else { throw new NullPointerException("direction is null"); } } try { Dao routeStopsDao = helper.getRouteStopsDao(); Dao busStopDao = helper.getBusStopDao(); QueryBuilder routeStopsQueryBuilder = routeStopsDao.queryBuilder(); routeStopsQueryBuilder.where().eq(RouteStop.ROUTE_ID_FIELD_NAME, this.id); PreparedQuery routeStopsPreparedQuery = routeStopsQueryBuilder.prepare(); List routeStopsFound = routeStopsDao.query(routeStopsPreparedQuery); Collections.sort(routeStopsFound); int stopIndex = -1; for (RouteStop routeStop : routeStopsFound) { if (routeStop.busStop.id.equals(busStop.id)) { if (stopIndex == -1) { stopIndex = routeStop.sequence - 1; } else { // ARGH, weird route if (busStop.id.equals("HAA13651") && id == 327) { // U6 // by // Wessex // Lane if (direction.equals(forwardDirection)) { stopIndex = 23; } else { stopIndex = 68; } } else if (busStop.id.equals("SN120134") && id == 327) { // U6 // opposite // the // Stile if (direction.equals(forwardDirection)) { stopIndex = 30; } else { stopIndex = 59; } } else if (busStop.id.equals("SN120163") && id == 327) { // U6 // just // up // past // wessex // lane if (direction.equals(forwardDirection)) { stopIndex = 22; } else { stopIndex = 67; } } else if (busStop.id.equals("SNA19482") && id == 327) { // U6 // General // Hosp // West // Door if (moveAmount > 0) { stopIndex = 44; } else { stopIndex = 43; } } else if (busStop.id.equals("SN120134") && id == 329) { // U2 // opposite // the // Stile if (direction.equals(forwardDirection)) { stopIndex = 13; } else { stopIndex = 30; } } else if (busStop.id.equals("SN120527") && id == 329) { // U2 // Civic // Centre // Rd // os // stop // AO // Civic // Ctr E if (moveAmount > 0) { stopIndex = 0; } else { stopIndex = 42; } } else if (busStop.id.equals("SNA09298") && id == 329) { // U2 // Bassett // Green // Rd // nr // Bassett // Green // Cl SE if (moveAmount > 0) { stopIndex = 22; } else { stopIndex = 21; } } else if (busStop.id.equals("SN120520") && id == 326) { // U1 // By // the // station if (direction.equals(forwardDirection)) { stopIndex = 7; } else { stopIndex = 80; } } else if (busStop.id.equals("HA030183") && id == 326) { // U1 // Up // past // Wessex // Lane if (direction.equals(forwardDirection)) { stopIndex = 35; } else { stopIndex = 50; } } else if (busStop.id.equals("HA030212") && id == 326) { // U1 // At // Eastleigh if (moveAmount > 0) { stopIndex = 43; } else { stopIndex = 42; } } else if (busStop.id.equals("SN120171") && id == 354) { // U9 if (moveAmount > 0) { stopIndex = 0; } else { stopIndex = 73; } } else { Log.e(TAG, "Error, unknown bus stop " + busStop.id + " (" + busStop.description + ") that appears mutiple times in " + toString()); throw new RuntimeException("Error, unknown bus stop " + busStop.id + " that appears mutiple times in " + toString()); } Log.v(TAG, "Selecting " + stopIndex + " for " + busStop.id + " as direction == " + direction); } } } if (moveAmount > 0) { Log.v(TAG, "Moving forward " + moveAmount + " stops from " + busStop + " (" + stopIndex + "/" + routeStopsFound.size() + ")"); int stopWanted = stopIndex + moveAmount; if (stopWanted > routeStopsFound.size()) { Log.v(TAG, "Off the end of the route"); stopWanted = stopWanted % (routeStopsFound.size() - 1); } Log.v(TAG, " Stop wanted " + stopWanted); BusStop busStopWanted = routeStopsFound.get(stopWanted).busStop; busStopDao.refresh(busStopWanted); Log.v(TAG, " Moving to " + busStopWanted + " (" + stopWanted + ") in route " + this); return busStopWanted; } else { Log.v(TAG, "stopIndex " + stopIndex); int stopWanted = stopIndex + moveAmount; if (stopWanted < 0) { stopWanted = routeStopsFound.size() - (Math.abs(stopWanted) % routeStopsFound.size()); } Log.v(TAG, "stopWanted " + stopWanted); busStopDao.refresh(routeStopsFound.get(stopWanted).busStop); Log.v(TAG, "Moving backwards " + moveAmount + " stops from " + busStop + " to " + routeStopsFound.get(stopWanted).busStop + " in route " + this); return routeStopsFound.get(stopWanted).busStop; } } catch (SQLException e) { e.printStackTrace(); } Log.e(TAG, "Error moving in route"); return null; } /** * Untested? * * @param context * @param busStop * @param moveAmount * @return */ List getRouteSection(final Context context, String direction) { DatabaseHelper helper = OpenHelperManager.getHelper(context, DatabaseHelper.class); if (forwardDirection != null) { if (direction != null) { } else { throw new NullPointerException("direction is null"); } } List busStops = new ArrayList(); try { Dao routeStopsDao = helper.getRouteStopsDao(); Dao busStopDao = helper.getBusStopDao(); QueryBuilder routeStopsQueryBuilder = routeStopsDao.queryBuilder(); routeStopsQueryBuilder.where().eq(RouteStop.ROUTE_ID_FIELD_NAME, this.id); PreparedQuery routeStopsPreparedQuery = routeStopsQueryBuilder.prepare(); List routeStopsFound = routeStopsDao.query(routeStopsPreparedQuery); Collections.sort(routeStopsFound); int startStopSeq = -1; int endStopSeq = -1; if (id == 326) { // U1 if (direction.equals("E")) { startStopSeq = 1; endStopSeq = 43; } else if (direction.equals(forwardDirection)) { startStopSeq = 1; endStopSeq = 36; } else if (direction.equals(reverseDirection)) { startStopSeq = 51; endStopSeq = 88; } else { Log.e(TAG, "Error, unrecognised direction " + direction); } } else if (id == 468) { // U1N startStopSeq = 1; endStopSeq = 29; } else if (id == 329) { // U2 if (direction.equals(forwardDirection)) { startStopSeq = 1; endStopSeq = 22; } else if (direction.equals(reverseDirection)) { startStopSeq = 23; endStopSeq = 43; } else { Log.e(TAG, "Error, unrecognised direction " + direction); } } else if (id == 327) { // U6 if (direction.equals(forwardDirection)) { startStopSeq = 1; endStopSeq = 44; } else if (direction.equals(reverseDirection)) { startStopSeq = 45; endStopSeq = 93; } else { Log.e(TAG, "Error, unrecognised direction " + direction); } } else if (id == 354) { // U9 Calendar rightNow = Calendar.getInstance(); if (rightNow.get(Calendar.HOUR_OF_DAY) < 12) { startStopSeq = 1; endStopSeq = 40; // TODO: Guess, and untested } else { startStopSeq = 41; // TODO: Guess, and untested endStopSeq = 74; } } else { Log.e(TAG, "Error, unrecognised route " + id); } for (RouteStop routeStop : routeStopsFound) { if (routeStop.sequence >= startStopSeq && routeStop.sequence <= endStopSeq) { busStopDao.refresh(routeStop.busStop); busStops.add(routeStop.busStop); } } return busStops; } catch (SQLException e) { e.printStackTrace(); } Log.e(TAG, "Error moving in route"); return null; } List getRouteBusStops(final Context context) { DatabaseHelper helper = OpenHelperManager.getHelper(context, DatabaseHelper.class); List busStops = new ArrayList(); try { Dao routeStopsDao = helper.getRouteStopsDao(); Dao busStopDao = helper.getBusStopDao(); QueryBuilder routeStopsQueryBuilder = routeStopsDao.queryBuilder(); routeStopsQueryBuilder.where().eq(RouteStop.ROUTE_ID_FIELD_NAME, this.id); PreparedQuery routeStopsPreparedQuery = routeStopsQueryBuilder.prepare(); List routeStopsFound = routeStopsDao.query(routeStopsPreparedQuery); Collections.sort(routeStopsFound); for (RouteStop routeStop : routeStopsFound) { busStopDao.refresh(routeStop.busStop); busStops.add(routeStop.busStop); } return busStops; } catch (SQLException e) { e.printStackTrace(); } Log.e(TAG, "Error moving in route"); return null; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + id; return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; BusRoute other = (BusRoute) obj; if (id != other.id) return false; return true; } }