/**
* Copyright (C) 2011 Brian Ferris <bdferris@onebusaway.org>
* Copyright (C) 2011 Google, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onebusaway.transit_data_federation.impl.beans;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TimeZone;
import java.util.TreeMap;
import org.onebusaway.collections.Counter;
import org.onebusaway.collections.FactoryMap;
import org.onebusaway.container.cache.Cacheable;
import org.onebusaway.gtfs.model.AgencyAndId;
import org.onebusaway.gtfs.model.calendar.ServiceDate;
import org.onebusaway.transit_data.model.RouteBean;
import org.onebusaway.transit_data.model.StopCalendarDayBean;
import org.onebusaway.transit_data.model.StopCalendarDaysBean;
import org.onebusaway.transit_data.model.StopRouteDirectionScheduleBean;
import org.onebusaway.transit_data.model.StopRouteScheduleBean;
import org.onebusaway.transit_data.model.StopTimeGroupBean;
import org.onebusaway.transit_data.model.StopTimeInstanceBean;
import org.onebusaway.transit_data.model.schedule.FrequencyInstanceBean;
import org.onebusaway.transit_data_federation.model.narrative.TripNarrative;
import org.onebusaway.transit_data_federation.services.AgencyAndIdLibrary;
import org.onebusaway.transit_data_federation.services.AgencyService;
import org.onebusaway.transit_data_federation.services.ExtendedCalendarService;
import org.onebusaway.transit_data_federation.services.beans.RouteBeanService;
import org.onebusaway.transit_data_federation.services.beans.StopScheduleBeanService;
import org.onebusaway.transit_data_federation.services.blocks.BlockIndexService;
import org.onebusaway.transit_data_federation.services.blocks.BlockStopTimeIndex;
import org.onebusaway.transit_data_federation.services.blocks.FrequencyBlockStopTimeIndex;
import org.onebusaway.transit_data_federation.services.blocks.InstanceState;
import org.onebusaway.transit_data_federation.services.narrative.NarrativeService;
import org.onebusaway.transit_data_federation.services.transit_graph.BlockConfigurationEntry;
import org.onebusaway.transit_data_federation.services.transit_graph.BlockStopTimeEntry;
import org.onebusaway.transit_data_federation.services.transit_graph.BlockTripEntry;
import org.onebusaway.transit_data_federation.services.transit_graph.FrequencyBlockStopTimeEntry;
import org.onebusaway.transit_data_federation.services.transit_graph.FrequencyEntry;
import org.onebusaway.transit_data_federation.services.transit_graph.ServiceIdActivation;
import org.onebusaway.transit_data_federation.services.transit_graph.StopEntry;
import org.onebusaway.transit_data_federation.services.transit_graph.TransitGraphDao;
import org.onebusaway.transit_data_federation.services.transit_graph.TripEntry;
import org.onebusaway.transit_data_federation.services.tripplanner.StopTimeInstance;
import org.onebusaway.utility.text.NaturalStringOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
class StopScheduleBeanServiceImpl implements StopScheduleBeanService {
private static final int DEFAULT_CONTINUES_AS_THRESHOLD = 7 * 60;
private static StopTimeBeanComparator _stopTimeComparator = new StopTimeBeanComparator();
private static FrequencyBeanComparator _frequencyComparator = new FrequencyBeanComparator();
private static DirectionComparator _directionComparator = new DirectionComparator();
private static StopRouteScheduleBeanComparator _stopRouteScheduleComparator = new StopRouteScheduleBeanComparator();
private AgencyService _agencyService;
private TransitGraphDao _graph;
private ExtendedCalendarService _calendarService;
private RouteBeanService _routeBeanService;
private NarrativeService _narrativeService;
private BlockIndexService _blockIndexService;
private int _continuesAsThreshold = DEFAULT_CONTINUES_AS_THRESHOLD;
@Autowired
public void setAgencyService(AgencyService agencyService) {
_agencyService = agencyService;
}
@Autowired
public void setTransitGraphDao(TransitGraphDao graph) {
_graph = graph;
}
@Autowired
public void setCalendarService(ExtendedCalendarService calendarService) {
_calendarService = calendarService;
}
@Autowired
public void setRouteBeanService(RouteBeanService routeBeanService) {
_routeBeanService = routeBeanService;
}
@Autowired
public void setNarrativeService(NarrativeService narrativeService) {
_narrativeService = narrativeService;
}
@Autowired
public void setBlockIndexService(BlockIndexService blockIndexService) {
_blockIndexService = blockIndexService;
}
/**
* When determining if one trip "continues as" another, we have a time
* threshold to determine if a rider is likely to actually stay on that bus.
* The idea is that if the time delay between the previous trip and the next
* trip, it's likely that there is a layover in there that the user wouldn't
* stick around for.
*
* @param continuesAsThreshold - time in seconds
*/
public void setContinuesAsThreshold(int continuesAsThreshold) {
_continuesAsThreshold = continuesAsThreshold;
}
@Cacheable
public StopCalendarDaysBean getCalendarForStop(AgencyAndId stopId) {
TimeZone timeZone = _agencyService.getTimeZoneForAgencyId(stopId.getAgencyId());
StopEntry stopEntry = _graph.getStopEntryForId(stopId);
Set<ServiceIdActivation> serviceIds = new HashSet<ServiceIdActivation>();
for (BlockStopTimeIndex index : _blockIndexService.getStopTimeIndicesForStop(stopEntry))
serviceIds.add(index.getServiceIds());
for (FrequencyBlockStopTimeIndex index : _blockIndexService.getFrequencyStopTimeIndicesForStop(stopEntry))
serviceIds.add(index.getServiceIds());
SortedMap<ServiceDate, Set<ServiceIdActivation>> serviceIdsByDate = getServiceIdsByDate(serviceIds);
Counter<Set<ServiceIdActivation>> counts = new Counter<Set<ServiceIdActivation>>();
for (Set<ServiceIdActivation> ids : serviceIdsByDate.values())
counts.increment(ids);
int total = counts.size();
Map<Set<ServiceIdActivation>, Integer> idsToGroup = new HashMap<Set<ServiceIdActivation>, Integer>();
for (Set<ServiceIdActivation> ids : counts.getSortedKeys())
idsToGroup.put(ids, total--);
List<StopCalendarDayBean> beans = new ArrayList<StopCalendarDayBean>(
serviceIdsByDate.size());
for (Map.Entry<ServiceDate, Set<ServiceIdActivation>> entry : serviceIdsByDate.entrySet()) {
StopCalendarDayBean bean = new StopCalendarDayBean();
ServiceDate serviceDate = entry.getKey();
Date date = serviceDate.getAsDate(timeZone);
bean.setDate(date);
Integer indexId = idsToGroup.get(entry.getValue());
bean.setGroup(indexId);
beans.add(bean);
}
return new StopCalendarDaysBean(timeZone.getID(), beans);
}
@Cacheable
public List<StopRouteScheduleBean> getScheduledArrivalsForStopAndDate(
AgencyAndId stopId, ServiceDate date) {
StopEntry stopEntry = _graph.getStopEntryForId(stopId);
Map<AgencyAndId, List<StopTimeInstance>> stopTimesByRouteCollectionId = new FactoryMap<AgencyAndId, List<StopTimeInstance>>(
new ArrayList<StopTimeInstance>());
Map<AgencyAndId, List<StopTimeInstance>> frequenciesByRouteCollectionId = new FactoryMap<AgencyAndId, List<StopTimeInstance>>(
new ArrayList<StopTimeInstance>());
groupStopTimeInstancesByRouteCollectionId(stopEntry, date,
stopTimesByRouteCollectionId, frequenciesByRouteCollectionId);
groupFrequencyInstancesByRouteCollectionId(stopEntry, date,
frequenciesByRouteCollectionId);
Set<AgencyAndId> routeIds = new HashSet<AgencyAndId>();
routeIds.addAll(stopTimesByRouteCollectionId.keySet());
routeIds.addAll(frequenciesByRouteCollectionId.keySet());
List<StopRouteScheduleBean> beans = new ArrayList<StopRouteScheduleBean>();
for (AgencyAndId routeId : routeIds) {
StopRouteScheduleBean routeScheduleBean = new StopRouteScheduleBean();
beans.add(routeScheduleBean);
RouteBean route = _routeBeanService.getRouteForId(routeId);
routeScheduleBean.setRoute(route);
Map<String, StopTimeByDirectionEntry> stopTimesByDirection = new FactoryMap<String, StopTimeByDirectionEntry>(
new StopTimeByDirectionEntry());
List<StopTimeInstance> stopTimesForRoute = stopTimesByRouteCollectionId.get(routeId);
for (StopTimeInstance sti : stopTimesForRoute) {
BlockStopTimeEntry bst = sti.getStopTime();
BlockTripEntry blockTrip = sti.getTrip();
BlockConfigurationEntry blockConfig = blockTrip.getBlockConfiguration();
TripEntry trip = blockTrip.getTrip();
AgencyAndId tripId = trip.getId();
AgencyAndId serviceId = trip.getServiceId().getId();
TripNarrative narrative = _narrativeService.getTripForId(tripId);
StopTimeInstanceBean stiBean = new StopTimeInstanceBean();
stiBean.setTripId(AgencyAndIdLibrary.convertToString(tripId));
stiBean.setServiceDate(sti.getServiceDate());
stiBean.setArrivalTime(sti.getArrivalTime());
stiBean.setDepartureTime(sti.getDepartureTime());
stiBean.setServiceId(AgencyAndIdLibrary.convertToString(serviceId));
stiBean.setArrivalEnabled(bst.getBlockSequence() > 0);
stiBean.setDepartureEnabled(bst.getBlockSequence() + 1 < blockConfig.getStopTimes().size());
String directionId = trip.getDirectionId();
if (directionId == null)
directionId = "0";
String tripHeadsign = narrative.getTripHeadsign();
TripHeadsignStopTimeGroupKey groupKey = new TripHeadsignStopTimeGroupKey(
tripHeadsign);
ContinuesAsStopTimeGroupKey continuesAsGroupKey = getContinuesAsGroupKeyForStopTimeInstance(sti);
StopTimeByDirectionEntry stopTimesForDirection = stopTimesByDirection.get(directionId);
stopTimesForDirection.addEntry(stiBean, tripHeadsign, groupKey,
continuesAsGroupKey);
}
List<StopTimeInstance> frequenciesForRoute = frequenciesByRouteCollectionId.get(routeId);
for (StopTimeInstance sti : frequenciesForRoute) {
BlockStopTimeEntry blockStopTime = sti.getStopTime();
BlockTripEntry blockTrip = blockStopTime.getTrip();
TripEntry trip = blockTrip.getTrip();
BlockConfigurationEntry blockConfig = blockTrip.getBlockConfiguration();
AgencyAndId tripId = trip.getId();
AgencyAndId serviceId = trip.getServiceId().getId();
TripNarrative narrative = _narrativeService.getTripForId(tripId);
FrequencyInstanceBean bean = new FrequencyInstanceBean();
bean.setTripId(AgencyAndIdLibrary.convertToString(tripId));
bean.setServiceDate(sti.getServiceDate());
bean.setStartTime(sti.getServiceDate()
+ sti.getFrequency().getStartTime() * 1000);
bean.setEndTime(sti.getServiceDate() + sti.getFrequency().getEndTime()
* 1000);
bean.setHeadwaySecs(sti.getFrequency().getHeadwaySecs());
bean.setServiceId(AgencyAndIdLibrary.convertToString(serviceId));
bean.setArrivalEnabled(blockStopTime.getBlockSequence() > 0);
bean.setDepartureEnabled(blockStopTime.getBlockSequence() + 1 < blockConfig.getStopTimes().size());
String directionId = trip.getDirectionId();
if (directionId == null)
directionId = "0";
StopTimeByDirectionEntry stopTimesForDirection = stopTimesByDirection.get(directionId);
stopTimesForDirection.addEntry(bean, narrative.getTripHeadsign());
}
for (StopTimeByDirectionEntry stopTimesForDirection : stopTimesByDirection.values()) {
StopRouteDirectionScheduleBean directionBean = new StopRouteDirectionScheduleBean();
directionBean.getStopTimes().addAll(
stopTimesForDirection.getStopTimes());
directionBean.getFrequencies().addAll(
stopTimesForDirection.getFrequencies());
String headsign = stopTimesForDirection.getBestHeadsign();
directionBean.setTripHeadsign(headsign);
Collections.sort(directionBean.getStopTimes(), _stopTimeComparator);
Collections.sort(directionBean.getFrequencies(), _frequencyComparator);
List<StopTimeGroupBean> groups = new ArrayList<StopTimeGroupBean>();
applyTripHeadsignStopTimeGroups(stopTimesForDirection, groups);
applyContinuesAsStopTimeGroups(stopTimesForDirection, groups);
directionBean.setGroups(groups);
routeScheduleBean.getDirections().add(directionBean);
}
Collections.sort(routeScheduleBean.getDirections(), _directionComparator);
}
Collections.sort(beans, _stopRouteScheduleComparator);
return beans;
}
/****
* Private Methods
****/
private SortedMap<ServiceDate, Set<ServiceIdActivation>> getServiceIdsByDate(
Set<ServiceIdActivation> allServiceIds) {
SortedMap<ServiceDate, Set<ServiceIdActivation>> serviceIdsByDate = new TreeMap<ServiceDate, Set<ServiceIdActivation>>();
serviceIdsByDate = FactoryMap.createSorted(serviceIdsByDate,
new HashSet<ServiceIdActivation>());
for (ServiceIdActivation serviceIds : allServiceIds) {
Set<ServiceDate> dates = _calendarService.getServiceDatesForServiceIds(serviceIds);
for (ServiceDate date : dates) {
serviceIdsByDate.get(date).add(serviceIds);
}
}
return serviceIdsByDate;
}
private static class StopTimeBeanComparator implements
Comparator<StopTimeInstanceBean> {
public int compare(StopTimeInstanceBean o1, StopTimeInstanceBean o2) {
long t1 = o1.getDepartureTime();
long t2 = o2.getDepartureTime();
return new Long(t1).compareTo(new Long(t2));
}
}
private static class FrequencyBeanComparator implements
Comparator<FrequencyInstanceBean> {
public int compare(FrequencyInstanceBean o1, FrequencyInstanceBean o2) {
long t1 = o1.getStartTime();
long t2 = o2.getStartTime();
return new Long(t1).compareTo(new Long(t2));
}
}
private void groupStopTimeInstancesByRouteCollectionId(StopEntry stopEntry,
ServiceDate date,
Map<AgencyAndId, List<StopTimeInstance>> stopTimesByRouteCollectionId,
Map<AgencyAndId, List<StopTimeInstance>> frequenciesByRouteCollectionId) {
Map<AgencyAndId, Set<FrequencyEntry>> frequencyLabelsByRouteCollectionId = new FactoryMap<AgencyAndId, Set<FrequencyEntry>>(
new HashSet<FrequencyEntry>());
for (BlockStopTimeIndex index : _blockIndexService.getStopTimeIndicesForStop(stopEntry)) {
ServiceIdActivation serviceIds = index.getServiceIds();
Set<ServiceDate> serviceDates = _calendarService.getServiceDatesForServiceIds(serviceIds);
if (!serviceDates.contains(date))
continue;
Date serviceDate = date.getAsDate(serviceIds.getTimeZone());
for (BlockStopTimeEntry stopTime : index.getStopTimes()) {
BlockTripEntry blockTrip = stopTime.getTrip();
TripEntry trip = blockTrip.getTrip();
AgencyAndId routeCollectionId = trip.getRouteCollection().getId();
FrequencyEntry frequencyLabel = trip.getFrequencyLabel();
InstanceState state = new InstanceState(serviceDate.getTime(),
frequencyLabel);
StopTimeInstance sti = new StopTimeInstance(stopTime, state);
if (frequencyLabel == null) {
stopTimesByRouteCollectionId.get(routeCollectionId).add(sti);
} else if (frequencyLabelsByRouteCollectionId.get(routeCollectionId).add(
frequencyLabel)) {
frequenciesByRouteCollectionId.get(routeCollectionId).add(sti);
}
}
}
}
private void groupFrequencyInstancesByRouteCollectionId(StopEntry stopEntry,
ServiceDate date,
Map<AgencyAndId, List<StopTimeInstance>> frequenciesByRouteCollectionId) {
for (FrequencyBlockStopTimeIndex index : _blockIndexService.getFrequencyStopTimeIndicesForStop(stopEntry)) {
ServiceIdActivation serviceIds = index.getServiceIds();
Set<ServiceDate> serviceDates = _calendarService.getServiceDatesForServiceIds(serviceIds);
if (!serviceDates.contains(date))
continue;
Date serviceDate = date.getAsDate(serviceIds.getTimeZone());
for (FrequencyBlockStopTimeEntry entry : index.getFrequencyStopTimes()) {
BlockStopTimeEntry stopTime = entry.getStopTime();
BlockTripEntry blockTrip = stopTime.getTrip();
TripEntry trip = blockTrip.getTrip();
AgencyAndId routeCollectionId = trip.getRouteCollection().getId();
InstanceState state = new InstanceState(serviceDate.getTime(),
entry.getFrequency());
StopTimeInstance sti = new StopTimeInstance(stopTime, state);
frequenciesByRouteCollectionId.get(routeCollectionId).add(sti);
}
}
}
private ContinuesAsStopTimeGroupKey getContinuesAsGroupKeyForStopTimeInstance(
StopTimeInstance instance) {
BlockTripEntry blockTrip = instance.getTrip();
AgencyAndId lineId = getContinuesAsLineId(blockTrip);
return new ContinuesAsStopTimeGroupKey(lineId);
}
private AgencyAndId getContinuesAsLineId(BlockTripEntry blockTrip) {
BlockTripEntry nextTrip = blockTrip.getNextTrip();
if (nextTrip == null)
return null;
TripEntry prevTrip = blockTrip.getTrip();
AgencyAndId prevLineId = prevTrip.getRouteCollection().getId();
AgencyAndId nextLineId = nextTrip.getTrip().getRouteCollection().getId();
if (prevLineId.equals(nextLineId))
return null;
List<BlockStopTimeEntry> stopTimes = blockTrip.getStopTimes();
BlockStopTimeEntry prevStopTime = stopTimes.get(stopTimes.size() - 1);
List<BlockStopTimeEntry> nextStopTimes = nextTrip.getStopTimes();
BlockStopTimeEntry nextStopTime = nextStopTimes.get(0);
int prevTime = prevStopTime.getStopTime().getDepartureTime();
int nextTime = nextStopTime.getStopTime().getArrivalTime();
if (nextTime - prevTime > _continuesAsThreshold)
return null;
return nextLineId;
}
private void applyTripHeadsignStopTimeGroups(
StopTimeByDirectionEntry stopTimesForDirection,
List<StopTimeGroupBean> groups) {
Counter<TripHeadsignStopTimeGroupKey> keyCounts = stopTimesForDirection.getTripHeadsignKeyCounts();
List<TripHeadsignStopTimeGroupKey> sortedKeys = keyCounts.getSortedKeys();
for (int i = 0; i < sortedKeys.size() - 1; i++) {
TripHeadsignStopTimeGroupKey key = sortedKeys.get(i);
StopTimeGroupBean group = new StopTimeGroupBean();
String groupId = Integer.toString(groups.size());
group.setId(groupId);
String tripHeadsign = key.getTripHeadsign();
group.setTripHeadsign(tripHeadsign);
applyGroupIdForGroupKey(stopTimesForDirection, key, groupId);
groups.add(group);
}
}
private void applyContinuesAsStopTimeGroups(
StopTimeByDirectionEntry stopTimesForDirection,
List<StopTimeGroupBean> groups) {
Counter<ContinuesAsStopTimeGroupKey> keyCounts = stopTimesForDirection.getContinuesAsKeyCounts();
List<ContinuesAsStopTimeGroupKey> sortedKeys = keyCounts.getSortedKeys();
for (ContinuesAsStopTimeGroupKey key : sortedKeys) {
AgencyAndId lineId = key.getLineId();
if (lineId == null)
continue;
StopTimeGroupBean group = new StopTimeGroupBean();
String groupId = Integer.toString(groups.size());
group.setId(groupId);
RouteBean route = _routeBeanService.getRouteForId(lineId);
group.setContinuesAs(route);
applyGroupIdForGroupKey(stopTimesForDirection, key, groupId);
groups.add(group);
}
}
private void applyGroupIdForGroupKey(
StopTimeByDirectionEntry stopTimesForDirection, Object key, String groupId) {
List<StopTimeInstanceBean> stopTimesForGroup = stopTimesForDirection.getStopTimesForGroupKey(key);
for (StopTimeInstanceBean stiBean : stopTimesForGroup) {
List<String> groupIds = stiBean.getGroupIds();
if (groupIds == null) {
groupIds = new ArrayList<String>();
stiBean.setGroupIds(groupIds);
}
groupIds.add(groupId);
}
}
private static class StopRouteScheduleBeanComparator implements
Comparator<StopRouteScheduleBean> {
public int compare(StopRouteScheduleBean o1, StopRouteScheduleBean o2) {
String a = getNameForRoute(o1.getRoute());
String b = getNameForRoute(o2.getRoute());
return NaturalStringOrder.compareNatural(a, b);
}
private static String getNameForRoute(RouteBean route) {
String name = route.getShortName();
if (name == null)
name = route.getLongName();
if (name == null)
name = route.getId();
return name;
}
}
private static class DirectionComparator implements
Comparator<StopRouteDirectionScheduleBean> {
@Override
public int compare(StopRouteDirectionScheduleBean o1,
StopRouteDirectionScheduleBean o2) {
String tripA = o1.getTripHeadsign();
String tripB = o2.getTripHeadsign();
if (tripA == null)
tripA = "";
if (tripB == null)
tripB = "";
return tripA.compareTo(tripB);
}
}
public static class StopTimeByDirectionEntry {
private List<StopTimeInstanceBean> _stopTimes = new ArrayList<StopTimeInstanceBean>();
private List<FrequencyInstanceBean> _frequencies = new ArrayList<FrequencyInstanceBean>();
private Counter<String> _headsigns = new Counter<String>();
private Counter<TripHeadsignStopTimeGroupKey> _tripHeadsignKeyCounts = new Counter<TripHeadsignStopTimeGroupKey>();
private Counter<ContinuesAsStopTimeGroupKey> _continuesAsKeyCounts = new Counter<ContinuesAsStopTimeGroupKey>();
private Map<Object, List<StopTimeInstanceBean>> _stopTimesByGroupKey = new FactoryMap<Object, List<StopTimeInstanceBean>>(
new ArrayList<StopTimeInstanceBean>());
public Collection<? extends StopTimeInstanceBean> getStopTimes() {
return _stopTimes;
}
public Collection<FrequencyInstanceBean> getFrequencies() {
return _frequencies;
}
public void addEntry(StopTimeInstanceBean sti, String headsign,
TripHeadsignStopTimeGroupKey groupKey,
ContinuesAsStopTimeGroupKey continuesAsGroupKey) {
_stopTimes.add(sti);
_headsigns.increment(headsign);
_tripHeadsignKeyCounts.increment(groupKey);
_continuesAsKeyCounts.increment(continuesAsGroupKey);
_stopTimesByGroupKey.get(groupKey).add(sti);
_stopTimesByGroupKey.get(continuesAsGroupKey).add(sti);
}
public void addEntry(FrequencyInstanceBean fi, String headsign) {
_frequencies.add(fi);
// We weight the frequency-based headsign count by the estimated number of
// trips in the interval
int rangeInSeconds = (int) ((fi.getEndTime() - fi.getStartTime()) / 1000);
int count = rangeInSeconds / fi.getHeadwaySecs();
_headsigns.increment(headsign, count);
}
public String getBestHeadsign() {
return _headsigns.getMax();
}
public Counter<TripHeadsignStopTimeGroupKey> getTripHeadsignKeyCounts() {
return _tripHeadsignKeyCounts;
}
public Counter<ContinuesAsStopTimeGroupKey> getContinuesAsKeyCounts() {
return _continuesAsKeyCounts;
}
public List<StopTimeInstanceBean> getStopTimesForGroupKey(Object key) {
return _stopTimesByGroupKey.get(key);
}
}
private static class TripHeadsignStopTimeGroupKey {
private final String tripHeadsign;
public TripHeadsignStopTimeGroupKey(String tripHeadsign) {
this.tripHeadsign = tripHeadsign;
}
public String getTripHeadsign() {
return tripHeadsign;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((tripHeadsign == null) ? 0 : tripHeadsign.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
TripHeadsignStopTimeGroupKey other = (TripHeadsignStopTimeGroupKey) obj;
if (tripHeadsign == null) {
if (other.tripHeadsign != null)
return false;
} else if (!tripHeadsign.equals(other.tripHeadsign))
return false;
return true;
}
}
private static class ContinuesAsStopTimeGroupKey {
private final AgencyAndId _lineId;
public ContinuesAsStopTimeGroupKey(AgencyAndId lineId) {
_lineId = lineId;
}
public AgencyAndId getLineId() {
return _lineId;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((_lineId == null) ? 0 : _lineId.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ContinuesAsStopTimeGroupKey other = (ContinuesAsStopTimeGroupKey) obj;
if (_lineId == null) {
if (other._lineId != null)
return false;
} else if (!_lineId.equals(other._lineId))
return false;
return true;
}
}
}