/**
* 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.bundle.tasks.transit_graph;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.onebusaway.collections.FactoryMap;
import org.onebusaway.gtfs.model.AgencyAndId;
import org.onebusaway.gtfs.model.Route;
import org.onebusaway.gtfs.services.GtfsRelationalDao;
import org.onebusaway.transit_data_federation.bundle.services.UniqueService;
import org.onebusaway.transit_data_federation.impl.transit_graph.AgencyEntryImpl;
import org.onebusaway.transit_data_federation.impl.transit_graph.RouteCollectionEntryImpl;
import org.onebusaway.transit_data_federation.impl.transit_graph.RouteEntryImpl;
import org.onebusaway.transit_data_federation.impl.transit_graph.TransitGraphImpl;
import org.onebusaway.transit_data_federation.services.transit_graph.RouteCollectionEntry;
import org.onebusaway.transit_data_federation.services.transit_graph.RouteEntry;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* Compute {@link RouteCollectionEntry} objects from {@link RouteEntry}
* instances. Recall that route collections are virtual route objects that
* bundle potentially multiple underlying {@link RouteEntry} objects with the
* same short name, depending on the setting of
* {@link #setGroupRoutesByShortName(boolean)}.
*
* This addresses the fact that some agencies break up what riders would
* consider a single route into multiple route entries according to their own
* organizational methods (different direction, different levels of service,
* express vs local, etc).
*
* @author bdferris
*/
@Component
public class RouteCollectionEntriesFactory {
private GtfsRelationalDao _gtfsDao;
private UniqueService _uniqueService;
private boolean _groupRoutesByShortName = false;
@Autowired
public void setGtfsDao(GtfsRelationalDao gtfsDao) {
_gtfsDao = gtfsDao;
}
@Autowired
public void setUniqueService(UniqueService uniqueService) {
_uniqueService = uniqueService;
}
public void setGroupRoutesByShortName(boolean groupRoutesByShortName) {
_groupRoutesByShortName = groupRoutesByShortName;
}
public void processRouteCollections(TransitGraphImpl graph) {
if (_groupRoutesByShortName) {
createRouteShortNameRouteCollectionMapping(graph);
} else {
createOneToOneRouteCollectionMapping(graph);
}
groupRouteCollectionsByAgencyId(graph);
graph.refreshRouteCollectionMapping();
}
private void groupRouteCollectionsByAgencyId(TransitGraphImpl graph) {
Map<String, ArrayList<RouteCollectionEntry>> entriesByAgencyId = new FactoryMap<String, ArrayList<RouteCollectionEntry>>(
new ArrayList<RouteCollectionEntry>());
for (RouteCollectionEntry entry : graph.getAllRouteCollections()) {
String agencyId = entry.getId().getAgencyId();
entriesByAgencyId.get(agencyId).add(entry);
}
for (Map.Entry<String, ArrayList<RouteCollectionEntry>> entry : entriesByAgencyId.entrySet()) {
String agencyId = entry.getKey();
ArrayList<RouteCollectionEntry> routeCollections = entry.getValue();
routeCollections.trimToSize();
AgencyEntryImpl agencyEntry = graph.getAgencyForId(agencyId);
agencyEntry.setRouteCollections(routeCollections);
}
}
private void createOneToOneRouteCollectionMapping(TransitGraphImpl graph) {
for (RouteEntryImpl routeEntry : graph.getRoutes()) {
RouteCollectionEntryImpl routeCollectionEntry = new RouteCollectionEntryImpl();
routeCollectionEntry.setId(routeEntry.getId());
ArrayList<RouteEntry> routes = new ArrayList<RouteEntry>();
routes.add(routeEntry);
routes.trimToSize();
routeCollectionEntry.setChildren(routes);
graph.putRouteCollectionEntry(routeCollectionEntry);
routeEntry.setParent(routeCollectionEntry);
}
}
private void createRouteShortNameRouteCollectionMapping(TransitGraphImpl graph) {
Map<AgencyAndId, List<RouteEntryImpl>> routesByKey = new HashMap<AgencyAndId, List<RouteEntryImpl>>();
for (RouteEntryImpl routeEntry : graph.getRoutes()) {
Route route = _gtfsDao.getRouteForId(routeEntry.getId());
AgencyAndId key = getRouteCollectionIdForRoute(route);
List<RouteEntryImpl> forKey = routesByKey.get(key);
if (forKey == null) {
forKey = new ArrayList<RouteEntryImpl>();
routesByKey.put(key, forKey);
}
forKey.add(routeEntry);
}
for (Map.Entry<AgencyAndId, List<RouteEntryImpl>> entry : routesByKey.entrySet()) {
AgencyAndId key = entry.getKey();
List<RouteEntryImpl> routesForKey = entry.getValue();
ArrayList<RouteEntry> children = new ArrayList<RouteEntry>();
children.addAll(routesForKey);
children.trimToSize();
key = _uniqueService.unique(key);
RouteCollectionEntryImpl routeCollectionEntry = new RouteCollectionEntryImpl();
routeCollectionEntry.setId(key);
routeCollectionEntry.setChildren(children);
graph.putRouteCollectionEntry(routeCollectionEntry);
for (RouteEntryImpl route : routesForKey)
route.setParent(routeCollectionEntry);
}
}
private AgencyAndId getRouteCollectionIdForRoute(Route route) {
String id = trim(route.getShortName());
// If no short name is supplied, we go back to using the original route id
if (id == null || id.length() == 0)
id = route.getId().getId();
id = id.replace('/', '_');
id = id.replace('\\', '_');
return new AgencyAndId(route.getId().getAgencyId(), id);
}
private String trim(String value) {
if (value == null)
return value;
return value.trim();
}
}