/**
* Copyright (C) 2011 Brian Ferris <bdferris@onebusaway.org>
*
* 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.presentation.impl;
import org.onebusaway.exceptions.InvalidSelectionServiceException;
import org.onebusaway.presentation.model.StopSelectionBean;
import org.onebusaway.presentation.model.StopSelectionTreeBean;
import org.onebusaway.presentation.services.LocationNameSplitStrategy;
import org.onebusaway.presentation.services.SelectionNameTypes;
import org.onebusaway.presentation.services.StopSelectionService;
import org.onebusaway.transit_data.model.NameBean;
import org.onebusaway.transit_data.model.StopBean;
import org.onebusaway.transit_data.model.StopGroupBean;
import org.onebusaway.transit_data.model.StopGroupingBean;
import org.onebusaway.transit_data.model.StopsForRouteBean;
import org.onebusaway.transit_data.model.TransitDataConstants;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
@Component
class StopSelectionServiceImpl implements StopSelectionService {
private boolean _splitStopNames = false;
private LocationNameSplitStrategy _locationNameSplitStrategy;
public void setLocationNameSplitStrategy(
LocationNameSplitStrategy locationNameSplitStrategy) {
_locationNameSplitStrategy = locationNameSplitStrategy;
}
public StopSelectionBean getSelectedStops(StopsForRouteBean stopsForRoute,
List<Integer> selectionIndices) throws InvalidSelectionServiceException {
StopSelectionBean selection = new StopSelectionBean();
StopSelectionTreeBean tree = getStopsForRouteAsStopSelectionTree(stopsForRoute);
visitTree(tree, selection, selectionIndices, 0);
return selection;
}
/****
* Private Methods
****/
private StopSelectionTreeBean getStopsForRouteAsStopSelectionTree(
StopsForRouteBean stopsForRoute) {
StopSelectionTreeBean tree = new StopSelectionTreeBean();
StopGroupingBean byDirection = getGroupingByType(stopsForRoute,
TransitDataConstants.STOP_GROUPING_TYPE_DIRECTION);
Map<String, StopBean> stopsById = getStopsById(stopsForRoute);
if (byDirection != null) {
groupByDirection(tree, stopsForRoute, byDirection, stopsById);
} else {
groupByStop(tree, stopsForRoute.getStops());
}
return tree;
}
private StopGroupingBean getGroupingByType(StopsForRouteBean stopsForRoute,
String type) {
List<StopGroupingBean> groupings = stopsForRoute.getStopGroupings();
for (StopGroupingBean grouping : groupings) {
if (grouping.getType().equals(type))
return grouping;
}
return null;
}
private void groupByDirection(StopSelectionTreeBean tree,
StopsForRouteBean stopsForRoute, StopGroupingBean byDirection,
Map<String, StopBean> stopsById) {
List<StopGroupBean> groups = byDirection.getStopGroups();
if (groups.isEmpty()) {
groupByStop(tree, stopsForRoute.getStops());
return;
}
for (StopGroupBean group : groups) {
StopSelectionTreeBean subTree = tree.getSubTree(group.getName());
List<StopBean> stops = new ArrayList<StopBean>();
for (String stopId : group.getStopIds())
stops.add(stopsById.get(stopId));
groupByStop(subTree, stops);
}
}
private void groupByStop(StopSelectionTreeBean tree, Iterable<StopBean> stops) {
for (StopBean stop : stops) {
StopSelectionTreeBean subTree = tree;
if (_splitStopNames) {
List<NameBean> names = _locationNameSplitStrategy.splitLocationNameIntoParts(stop.getName());
for (NameBean name : names)
subTree = subTree.getSubTree(name);
} else {
NameBean name = new NameBean(SelectionNameTypes.STOP_NAME,
stop.getName());
subTree = subTree.getSubTree(name);
}
// As a last resort, we extend the tree by the stop number (guaranteed to
// be unique)
String code = stop.getCode() != null ? stop.getCode() : stop.getId();
NameBean name = new NameBean(SelectionNameTypes.STOP_DESCRIPTION,
"Stop # " + code);
subTree = subTree.getSubTree(name);
subTree.setStop(stop);
}
}
private Map<String, StopBean> getStopsById(StopsForRouteBean stopsForRoute) {
Map<String, StopBean> stopsById = new HashMap<String, StopBean>();
for (StopBean stop : stopsForRoute.getStops())
stopsById.put(stop.getId(), stop);
return stopsById;
}
private void visitTree(StopSelectionTreeBean tree,
StopSelectionBean selection, List<Integer> selectionIndices, int index)
throws InvalidSelectionServiceException {
// If we have a stop, we have no choice but to return
if (tree.hasStop()) {
selection.setStop(tree.getStop());
return;
}
Set<NameBean> names = tree.getNames();
// If we've only got one name, short circuit
if (names.size() == 1) {
NameBean next = names.iterator().next();
selection.addSelected(next);
StopSelectionTreeBean subtree = tree.getSubTree(next);
visitTree(subtree, selection, selectionIndices, index);
return;
}
if (index >= selectionIndices.size()) {
for (NameBean name : names) {
StopBean stop = getStop(tree.getSubTree(name));
if (stop != null) {
selection.addNameWithStop(name, stop);
} else {
selection.addName(name);
}
}
List<StopBean> stops = tree.getAllStops();
for (StopBean stop : stops)
selection.addStop(stop);
return;
} else {
int i = 0;
int selectionIndex = selectionIndices.get(index);
for (NameBean name : names) {
if (selectionIndex == i) {
selection.addSelected(name);
tree = tree.getSubTree(name);
visitTree(tree, selection, selectionIndices, index + 1);
return;
}
i++;
}
}
// If we made it here...
throw new InvalidSelectionServiceException();
}
private StopBean getStop(StopSelectionTreeBean tree) {
if (tree.hasStop())
return tree.getStop();
if (tree.getNames().size() == 1) {
NameBean next = tree.getNames().iterator().next();
return getStop(tree.getSubTree(next));
}
return null;
}
}