package pl.edu.agh.logic;
import static com.google.common.collect.Lists.newArrayList;
import static pl.edu.agh.spatial.HaversineDistanceCalculator.EARTH_DISTANCE_CALCULATOR;
import java.util.Date;
import java.util.List;
import com.google.common.collect.Lists;
import com.vividsolutions.jts.geom.Coordinate;
public class Path {
private List<PointMatching> matchings;
private double cost;
private Path(Coordinate point, Road road, Date time) {
matchings = Lists.<PointMatching> newArrayList(new PointMatching(point, road, time));
cost = calculateCost(matchings);
}
private Path(List<PointMatching> matchings) {
this.matchings = Lists.<PointMatching> newArrayList(matchings);
cost = calculateCost(matchings);
}
private Path(Path other) {
this.matchings = newArrayList(other.matchings);
this.cost = other.cost;
}
private Road getLastRoad() {
return matchings.get(matchings.size() - 1).getRoad();
}
private Coordinate getLastPoint() {
return matchings.get(matchings.size() - 1).getPoint();
}
public double getCost() {
return cost;
}
public double getRelativeCost() {
return calculateCost(matchings) / matchings.size();
}
public double getRelativeCostOfLastMatchings(int matchingsNumber) {
int number = Math.min(matchingsNumber, matchings.size());
return calculateCost(matchings.subList(matchings.size() - number, matchings.size())) / number;
}
private double calculateCost(List<PointMatching> calculatedMatchings) {
double result = 0;
for (PointMatching matching : calculatedMatchings) {
result += matching.getCost();
}
return result;
}
public Path copy() {
return new Path(this);
}
public static Path createPath(Coordinate point, Road road, Date time) {
return new Path(point, road, time);
}
public static Path createPath(List<PointMatching> matchings) {
return new Path(matchings);
}
public Path matchPointToLastRoad(Coordinate point, Date time) {
return matchPointToRoad(point, getLastRoad(), time);
}
public Path matchPointToRoad(Coordinate point, Road road, Date time) {
PointMatching matching = new PointMatching(point, road, time);
matchings.add(matching);
cost += matching.getCost();
return this;
}
public boolean hasPointReachedEndOfLastRoad(Coordinate point, double toleranceFactor) {
double lastRoadLength = getLastRoad().getLength();
double distanceBetweenPointsMatchedToLastRoad = calculateDistanceBetweenPointsMatchedToLastRoad();
return (distanceBetweenPointsMatchedToLastRoad + EARTH_DISTANCE_CALCULATOR.distance(getLastPoint(), point)) > (toleranceFactor * lastRoadLength);
}
private double calculateDistanceBetweenPointsMatchedToLastRoad() {
double distance = 0.0;
Road lastRoad = getLastRoad();
for (int i = matchings.size() - 2; i >= 0; i--) {
if (!matchings.get(i).getRoad().equals(lastRoad)) {
return distance;
}
distance += EARTH_DISTANCE_CALCULATOR
.distance(matchings.get(i).getPoint(), matchings.get(i + 1).getPoint());
}
return distance;
}
public int getPointsNumber() {
return matchings.size();
}
public int getSource() {
return matchings.get(0).getRoad().getSource();
}
public int getTarget() {
return getLastRoad().getTarget();
}
public List<PointMatching> getMatchings() {
return java.util.Collections.unmodifiableList(matchings);
}
public Coordinate getStartPoint() {
return matchings.get(0).getPoint();
}
public Coordinate getEndPoint() {
return getLastPoint();
}
}