package org.opentripplanner.profile;
import java.util.Collection;
import java.util.Iterator;
import java.util.Set;
import jersey.repackaged.com.google.common.collect.Lists;
import jersey.repackaged.com.google.common.collect.Sets;
import org.opentripplanner.routing.edgetype.TripPattern;
import org.opentripplanner.routing.vertextype.TransitStop;
/** represents a state in profile routing */
public class ProfileState implements Cloneable {
public int lowerBound;
public int upperBound;
public Type accessType;
/** the trip patterns used to access this stop */
public TripPattern[] patterns;
/** the location of this state */
public TransitStop stop;
/** the previous state, or null if this is the initial access leg */
public ProfileState previous;
/** the patterns that should be boarded from this state */
public Collection<TripPattern> targetPatterns;
/**
* Propagate this state along a ride with the given min and max times, to the given transit stop.
* It is the responsibility of the caller to set accessType and stop appropriately.
*/
public ProfileState propagate (int deltaMin, int deltaMax) {
ProfileState ret;
try {
ret = (ProfileState) this.clone();
} catch (CloneNotSupportedException e) {
// this can't happen
throw new RuntimeException(e);
}
ret.previous = this;
ret.lowerBound += deltaMin;
ret.upperBound += deltaMax;
ret.targetPatterns = null;
return ret;
}
/**
* Propagate this state along a segment with a definite time (e.g. a street segment)
*/
public ProfileState propagate (int delta) {
return propagate(delta, delta);
}
/** two ways to create a profile state: the initial state, reached via an on-street mode, and subsequent states reached via transit */
public static enum Type {
STREET, TRANSIT, TRANSFER;
}
/** Merge the other profile state into this one, in place */
public void mergeIn(ProfileState other) {
if (this.lowerBound < 0 || other.lowerBound < 0 || this.upperBound < 0 || other.upperBound < 0)
throw new IllegalStateException("Invalid bound");
this.lowerBound = Math.min(this.lowerBound, other.lowerBound);
// the upper bound of a common trunk is the _minimum_ upper bound of all its constituents
this.upperBound = Math.min(this.upperBound, other.upperBound);
}
public boolean containsPattern(TripPattern pattern) {
if (patterns == null)
return false;
for (TripPattern tp : patterns) {
if (tp == pattern)
return true;
}
return false;
}
/** merge all the profile states into a new ProfileState. Assumes that each state consists of a single pattern unique among the states. */
public static ProfileState merge (Collection<ProfileState> states, boolean retainPatterns) {
ProfileState ret = new ProfileState();
ret.lowerBound = ret.upperBound = Integer.MAX_VALUE;
if (retainPatterns)
ret.patterns = new TripPattern[states.size()];
{
int i = 0;
for (Iterator<ProfileState> it = states.iterator(); it.hasNext(); i++) {
ProfileState state = it.next();
if (ret.stop == null) ret.stop = state.stop;
if (state.lowerBound < ret.lowerBound) ret.lowerBound = state.lowerBound;
// Yes, we want the _minimum_ upper bound: you will never take a journey that is longer than the minimum
// upper bound, in either the perfect information case or the min-upper-bound case.
if (state.upperBound < ret.upperBound) ret.upperBound = state.upperBound;
if (retainPatterns)
ret.patterns[i] = state.patterns[0];
}
}
return ret;
}
}