/* 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.bike_rental;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Currency;
import java.util.List;
import org.opentripplanner.common.model.P2;
import org.opentripplanner.routing.core.Fare;
import org.opentripplanner.routing.core.Fare.FareType;
import org.opentripplanner.routing.core.State;
import org.opentripplanner.routing.core.WrappedCurrency;
import org.opentripplanner.routing.services.ChainedFareService;
import org.opentripplanner.routing.services.FareService;
import org.opentripplanner.routing.spt.GraphPath;
import org.opentripplanner.routing.vertextype.BikeRentalStationVertex;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TimeBasedBikeRentalFareService implements ChainedFareService, Serializable {
private static final long serialVersionUID = 5226621661906177942L;
private static Logger log = LoggerFactory.getLogger(TimeBasedBikeRentalFareService.class);
private FareService next;
// Each entry is <max time, cents at that time>; the list is sorted in
// ascending time order
private List<P2<Integer>> pricing_by_second;
private String currency;
/*
* A list of <time>,<cents> time can be a number of seconds, or m:s, or h:m:s
*/
public void setPricing(List<String> pricing) {
pricing_by_second = new ArrayList<P2<Integer>>();
for (String pair : pricing) {
String[] strings = pair.split(",");
String[] hms = strings[0].split(":");
int seconds = 0;
for (String field : hms) {
seconds *= 60;
int fieldValue = Integer.parseInt(field);
seconds += fieldValue;
}
pricing_by_second.add((new P2<Integer>(seconds, Integer.parseInt(strings[1]))));
}
Collections.sort(pricing_by_second, new Comparator<P2<Integer>>() {
@Override
public int compare(P2<Integer> arg0, P2<Integer> arg1) {
return arg0.getFirst() - arg1.getFirst();
}
});
int seconds = -1;
int lastCost = 0;
for (P2<Integer> bracket : pricing_by_second) {
int maxTime = bracket.getFirst();
int cost = bracket.getSecond();
if (maxTime == seconds) {
throw new RuntimeException("Bike share pricing has two entries for " + maxTime);
}
if (cost < lastCost) {
log.warn("Bike share pricing has pathological pricing; keeping the bike for a "
+ maxTime + " is cheaper than keeping it for " + seconds);
}
seconds = maxTime;
lastCost = cost;
}
}
@Override
public Fare getCost(GraphPath path) {
int cost = 0;
long start = -1;
for (State state : path.states) {
if (state.getVertex() instanceof BikeRentalStationVertex
&& state.getBackState().getVertex() instanceof BikeRentalStationVertex) {
if (start == -1) {
start = state.getTimeSeconds();
} else {
int time_on_bike = (int) (state.getTimeSeconds() - start);
int ride_cost = -1;
for (P2<Integer> bracket : pricing_by_second) {
int time = bracket.getFirst();
if (time_on_bike < time) {
ride_cost = bracket.getSecond();
break;
}
}
if (ride_cost == -1) {
log.warn("Bike rental has no associated pricing (too long?) : "
+ time_on_bike + " seconds");
} else {
cost += ride_cost;
}
start = -1;
}
}
}
if (next == null) {
Fare fare = new Fare();
fare.addFare(FareType.regular, new WrappedCurrency(Currency.getInstance(currency)),
cost);
return fare;
}
if (cost == 0) {
return next.getCost(path);
}
Fare fare = next.getCost(path);
if (fare == null) {
fare = new Fare();
fare.addFare(FareType.regular, new WrappedCurrency(Currency.getInstance(currency)),
cost);
return fare;
}
fare.addCost(cost);
return fare;
}
@Override
public void setNextService(FareService service) {
this.next = service;
}
public void setCurrency(String currency) {
this.currency = currency;
}
}