org.onebusaway.gtfs.impl.calendar.CalendarServiceImpl Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of onebusaway-gtfs Show documentation
Show all versions of onebusaway-gtfs Show documentation
A Java library for reading and writing General Transit Feed Spec feeds
/**
* Copyright (C) 2011 Brian Ferris
*
* 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.gtfs.impl.calendar;
import java.util.ArrayList;
import java.util.Collections;
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.TimeZone;
import org.onebusaway.gtfs.model.AgencyAndId;
import org.onebusaway.gtfs.model.calendar.CalendarServiceData;
import org.onebusaway.gtfs.model.calendar.LocalizedServiceId;
import org.onebusaway.gtfs.model.calendar.ServiceDate;
import org.onebusaway.gtfs.model.calendar.ServiceIdIntervals;
import org.onebusaway.gtfs.model.calendar.ServiceInterval;
import org.onebusaway.gtfs.services.calendar.CalendarService;
import org.onebusaway.gtfs.services.calendar.CalendarServiceDataFactory;
/**
* An implementation of {@link CalendarService}. Requires a pre-computed
* {@link CalendarServiceData} bundle for efficient operation.
*
* @author bdferris
*
*/
public class CalendarServiceImpl implements CalendarService {
private CalendarServiceDataFactory _factory;
private volatile CalendarServiceData _data;
public CalendarServiceImpl() {
}
public CalendarServiceImpl(CalendarServiceDataFactory factory) {
_factory = factory;
}
public void setDataFactory(CalendarServiceDataFactory factory) {
_factory = factory;
}
public void setData(CalendarServiceData data) {
_data = data;
}
/****
* {@link CalendarService} Interface
****/
@Override
public Set getServiceIds() {
CalendarServiceData allData = getData();
return allData.getServiceIds();
}
@Override
public Set getServiceDatesForServiceId(AgencyAndId serviceId) {
Set dates = new HashSet();
CalendarServiceData allData = getData();
List serviceDates = allData.getServiceDatesForServiceId(serviceId);
if (serviceDates != null)
dates.addAll(serviceDates);
return dates;
}
@Override
public Set getServiceIdsOnDate(ServiceDate date) {
CalendarServiceData allData = getData();
return allData.getServiceIdsForDate(date);
}
@Override
public TimeZone getTimeZoneForAgencyId(String agencyId) {
CalendarServiceData data = getData();
return data.getTimeZoneForAgencyId(agencyId);
}
@Override
public LocalizedServiceId getLocalizedServiceIdForAgencyAndServiceId(
String agencyId, AgencyAndId serviceId) {
TimeZone timeZone = getTimeZoneForAgencyId(agencyId);
if (timeZone == null)
return null;
return new LocalizedServiceId(serviceId, timeZone);
}
public List getDatesForLocalizedServiceId(
LocalizedServiceId localizedServiceId) {
CalendarServiceData data = getData();
return list(data.getDatesForLocalizedServiceId(localizedServiceId));
}
@Override
public boolean isLocalizedServiceIdActiveOnDate(
LocalizedServiceId localizedServiceId, Date serviceDate) {
// TODO : Make this more efficient?
CalendarServiceData data = getData();
List dates = data.getDatesForLocalizedServiceId(localizedServiceId);
return Collections.binarySearch(dates, serviceDate) >= 0;
}
@Override
public List getServiceDateArrivalsWithinRange(
LocalizedServiceId serviceId, ServiceInterval interval, Date from, Date to) {
return getServiceDates(getData(), serviceId, interval,
ServiceIdOp.ARRIVAL_OP, to, from, false);
}
@Override
public Map> getServiceDateArrivalsWithinRange(
ServiceIdIntervals serviceIdIntervals, Date from, Date to) {
return getServiceDates(serviceIdIntervals, ServiceIdOp.ARRIVAL_OP, to,
from, false);
}
@Override
public List getServiceDateDeparturesWithinRange(
LocalizedServiceId serviceId, ServiceInterval interval, Date from, Date to) {
return getServiceDates(getData(), serviceId, interval,
ServiceIdOp.DEPARTURE_OP, from, to, false);
}
@Override
public Map> getServiceDateDeparturesWithinRange(
ServiceIdIntervals serviceIdIntervals, Date from, Date to) {
return getServiceDates(serviceIdIntervals, ServiceIdOp.DEPARTURE_OP, from,
to, false);
}
@Override
public List getServiceDatesWithinRange(LocalizedServiceId serviceId,
ServiceInterval interval, Date from, Date to) {
return getServiceDates(getData(), serviceId, interval, ServiceIdOp.BOTH_OP,
from, to, false);
}
@Override
public Map> getServiceDatesWithinRange(
ServiceIdIntervals serviceIdIntervals, Date from, Date to) {
return getServiceDates(serviceIdIntervals, ServiceIdOp.BOTH_OP, from, to,
false);
}
@Override
public List getNextDepartureServiceDates(LocalizedServiceId serviceId,
ServiceInterval interval, long targetTime) {
Date target = new Date(targetTime);
return getServiceDates(getData(), serviceId, interval,
ServiceIdOp.DEPARTURE_OP, target, target, true);
}
@Override
public Map> getNextDepartureServiceDates(
ServiceIdIntervals serviceIdIntervals, long targetTime) {
Date target = new Date(targetTime);
return getServiceDates(serviceIdIntervals, ServiceIdOp.DEPARTURE_OP,
target, target, true);
}
@Override
public List getPreviousArrivalServiceDates(
LocalizedServiceId serviceId, ServiceInterval interval, long targetTime) {
Date target = new Date(targetTime);
return getServiceDates(getData(), serviceId, interval,
ServiceIdOp.ARRIVAL_OP, target, target, true);
}
@Override
public Map> getPreviousArrivalServiceDates(
ServiceIdIntervals serviceIdIntervals, long targetTime) {
Date target = new Date(targetTime);
return getServiceDates(serviceIdIntervals, ServiceIdOp.ARRIVAL_OP, target,
target, true);
}
/****
* Private Methods
****/
protected CalendarServiceData getData() {
if (_data == null) {
synchronized (this) {
if (_data == null) {
_data = _factory.createData();
}
}
}
return _data;
}
private Map> getServiceDates(
ServiceIdIntervals serviceIdIntervals, ServiceIdOp op, Date from,
Date to, boolean includeNextDate) {
CalendarServiceData allData = getData();
Map> results = new HashMap>();
for (Map.Entry entry : serviceIdIntervals) {
LocalizedServiceId serviceId = entry.getKey();
ServiceInterval interval = entry.getValue();
List serviceDates = getServiceDates(allData, serviceId, interval,
op, from, to, includeNextDate);
if (!serviceDates.isEmpty())
results.put(serviceId, serviceDates);
}
return results;
}
private List getServiceDates(CalendarServiceData allData,
LocalizedServiceId serviceId, ServiceInterval interval, ServiceIdOp op,
Date from, Date to, boolean includeNextDateIfNeeded) {
List serviceDates = allData.getDatesForLocalizedServiceId(serviceId);
List resultsForServiceId = new ArrayList();
Date nextDate = null;
if (serviceDates == null)
return resultsForServiceId;
Date target = op.shiftTime(interval, from);
int index = search(serviceDates, op, 0, serviceDates.size(), target);
if (index == serviceDates.size())
index--;
while (0 <= index) {
Date serviceDate = op.getServiceDate(serviceDates, index);
int rc = op.compareInterval(interval, serviceDate, from, to);
if (rc > 0) {
nextDate = serviceDate;
} else if (rc == 0) {
resultsForServiceId.add(serviceDate);
} else if (rc < 0) {
break;
}
index--;
}
if (includeNextDateIfNeeded && resultsForServiceId.isEmpty()
&& nextDate != null)
resultsForServiceId.add(nextDate);
return resultsForServiceId;
}
private int search(List serviceDates, ServiceIdOp op, int indexFrom,
int indexTo, Date key) {
if (indexTo == indexFrom)
return indexFrom;
int index = (indexFrom + indexTo) / 2;
Date serviceDate = op.getServiceDate(serviceDates, index);
int rc = op.compare(key, serviceDate);
if (rc == 0)
return index;
if (rc < 0)
return search(serviceDates, op, indexFrom, index, key);
else
return search(serviceDates, op, index + 1, indexTo, key);
}
private static final List list(List values) {
if (values == null)
return Collections.emptyList();
return values;
}
}