/* This program is free software: you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public License
as published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
package org.opentripplanner.routing.core;
import java.io.Serializable;
import java.util.HashSet;
import org.onebusaway.gtfs.model.AgencyAndId;
import org.onebusaway.gtfs.model.Stop;
/**
* A StopMatcher is a collection of stops based on IDs and agency IDs.
*
* We currently only support full stop IDs (agency ID + stop ID).
* Support for other matching expression (or other types of stop banning) can be easily added later on.
*/
public class StopMatcher implements Cloneable, Serializable {
private static final long serialVersionUID = 1274704742132971135L;
/**
* Set of full matching stop ids (agency ID + stop ID)
*/
private HashSet<AgencyAndId> agencyAndStopIds = new HashSet<AgencyAndId>();
private StopMatcher() {
}
/**
* Return an empty matcher (which matches no stops).
*/
public static StopMatcher emptyMatcher() {
return new StopMatcher();
}
/**
* Returns whether this matcher is empty
* @return true when this matcher is empty, false otherwise
*/
public boolean isEmpty() {
return agencyAndStopIds.isEmpty();
}
/**
* Build a new StopMatcher from a string representation.
*
* @param stopList is a comma-separated list of stops, each of the format [agencyId]_[stopId]
* @return A StopMatcher
* @throws IllegalArgumentException if the string representation is invalid.
*/
public static StopMatcher parse(String stopList) {
if (stopList == null)
return emptyMatcher();
StopMatcher retval = new StopMatcher();
int n = 0;
for (String stopString : stopList.split(",")) {
if (stopString.isEmpty()) {
continue;
}
n++;
try {
AgencyAndId stopId = AgencyAndId.convertFromString(stopString);
retval.agencyAndStopIds.add(stopId);
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException("Wrong stop spec format: " + stopString);
}
}
if (n == 0) {
return emptyMatcher();
}
return retval;
}
/**
* Function to determine whether this StopMatcher matches a particular stop.
* When a stop has a parent stop, it is also matched when its parent stop is matched.
* @param stop is the stop to match using its ID
* @return true when the stop is matched
*/
public boolean matches(Stop stop) {
// Don't bother with an empty matcher
if (this.isEmpty()) {
return false;
}
else if (stop != null) {
// Check whether stop is matched
if (matches(stop.getId())) {
return true;
}
// Check whether parent stop is matched
else if (stop.getParentStation() != null
&& !stop.getParentStation().isEmpty()) {
// This stop has a parent
AgencyAndId parentId = new AgencyAndId(stop.getId().getAgencyId(), stop.getParentStation());
if (matches(parentId)) {
return true;
}
}
}
return false;
}
/**
* Function to determine whether this StopMatcher matches a particular stop id.
* Warning: this function does not check for parent stops.
* @param stopId is the stop id
* @return true when stop id is matched
*/
private boolean matches(AgencyAndId stopId) {
if (agencyAndStopIds.contains(stopId)) {
return true;
}
return false;
}
/**
* Returns string representation of this matcher
* @return string representation of this matcher
*/
public String asString() {
StringBuilder builder = new StringBuilder();
for (AgencyAndId agencyAndId : agencyAndStopIds) {
builder.append(agencyAndId.toString());
builder.append(",");
}
// Remove last comma
if (builder.length() > 0) {
builder.setLength(builder.length() - 1);
}
return builder.toString();
}
@Override
public String toString() {
return String.format(
"StopMatcher<agencyAndStopIds=%s>",
agencyAndStopIds);
}
@Override
public boolean equals(Object another) {
if (another == null || !(another instanceof StopMatcher)) {
return false;
}
if (another == this) {
return true;
}
StopMatcher anotherMatcher = (StopMatcher) another;
return agencyAndStopIds.equals(anotherMatcher.agencyAndStopIds);
}
@Override
public int hashCode() {
return agencyAndStopIds.hashCode();
}
@Override
public StopMatcher clone() {
try {
return (StopMatcher) super.clone();
} catch (CloneNotSupportedException e) {
/* this will never happen since our super is the cloneable object */
throw new RuntimeException(e);
}
}
}