/**
* 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.transit_data_federation.impl.otp.graph.tp;
import java.util.List;
import org.onebusaway.collections.tuple.Pair;
import org.onebusaway.transit_data_federation.impl.otp.GraphContext;
import org.onebusaway.transit_data_federation.impl.otp.ItineraryWeightingLibrary;
import org.onebusaway.transit_data_federation.impl.otp.OBAStateEditor;
import org.onebusaway.transit_data_federation.impl.otp.OBATraverseOptions;
import org.onebusaway.transit_data_federation.impl.otp.graph.AbstractEdge;
import org.onebusaway.transit_data_federation.model.TargetTime;
import org.onebusaway.transit_data_federation.services.ArrivalAndDeparturePairQuery;
import org.onebusaway.transit_data_federation.services.ArrivalAndDepartureService;
import org.onebusaway.transit_data_federation.services.realtime.ArrivalAndDepartureInstance;
import org.onebusaway.transit_data_federation.services.transit_graph.StopEntry;
import org.opentripplanner.routing.core.EdgeNarrative;
import org.opentripplanner.routing.core.State;
import org.opentripplanner.routing.core.TraverseOptions;
import org.opentripplanner.routing.core.Vertex;
public class TPArrivalReverseEdge extends AbstractEdge {
private final TPState _pathState;
public TPArrivalReverseEdge(GraphContext context, TPState pathState) {
super(context);
_pathState = pathState;
}
@Override
public State traverse(State s0) {
TraverseOptions options = s0.getOptions();
if (options.isArriveBy())
return traverseReverse(s0);
else
return traverseForward(s0);
}
private State traverseForward(State s0) {
/**
* We alight from our current vehicle to the stop. However, we don't
* actually know which vehicle. Hopefully this method will only ever be
* called in the GraphPath.optimize(), where the traverseBack() method has
* previously been called.
*/
TPDepartureVertex fromVertex = null;
TPArrivalVertex toVertex = new TPArrivalVertex(_context, _pathState);
EdgeNarrative narrative = narrative(s0, fromVertex, toVertex);
return s0.edit(this, narrative).makeState();
}
private State traverseReverse(State s0) {
OBATraverseOptions obaOpts = (OBATraverseOptions) s0.getOptions();
ArrivalAndDepartureService adService = _context.getArrivalAndDepartureService();
Vertex toV = new TPArrivalVertex(_context, _pathState);
Pair<StopEntry> stopPair = _pathState.getStops();
TargetTime targetTime = new TargetTime(s0.getTime(), obaOpts.currentTime);
ArrivalAndDeparturePairQuery query = new ArrivalAndDeparturePairQuery();
query.setResultCount(obaOpts.numItineraries);
query.setApplyRealTime(obaOpts.useRealtime);
query.setIncludePrivateService(false);
/**
* Recall that the stopPair is in reverse order (toStop => fromStop)
*/
List<Pair<ArrivalAndDepartureInstance>> instances = adService.getPreviousArrivalsForStopPair(
stopPair.getSecond(), stopPair.getFirst(), targetTime, query);
State results = null;
for (Pair<ArrivalAndDepartureInstance> pair : instances) {
/**
* For now, we skip real-time arrival that might have been included that
* are beyond our range (ex. vehicle running late)
*/
ArrivalAndDepartureInstance arrival = pair.getSecond();
if (arrival.getBestArrivalTime() > s0.getTime())
break;
Vertex fromV = new TPBlockArrivalVertex(_context, _pathState,
pair.getFirst(), pair.getSecond());
EdgeNarrative narrative = narrative(s0, fromV, toV);
OBAStateEditor edit = (OBAStateEditor) s0.edit(this, narrative);
int dwellTime = computeWaitTime(s0, pair);
edit.incrementTimeInSeconds(-dwellTime);
double w = ItineraryWeightingLibrary.computeWeightForWait(s0, dwellTime);
edit.incrementWeight(w);
if (arrival.getBlockSequence() != null)
edit.appendTripSequence(arrival.getBlockSequence());
else
edit.appendTripSequence(arrival.getBlockTrip());
State s1 = edit.makeState();
results = s1.addToExistingResultChain(results);
}
return results;
}
/****
*
****/
private int computeWaitTime(State s0, Pair<ArrivalAndDepartureInstance> pair) {
return (int) ((s0.getTime() - pair.getSecond().getBestArrivalTime()) / 1000);
}
}