/**
* Copyright (C) 2013 - 2015 the enviroCar community
*
* This file is part of the enviroCar app.
*
* The enviroCar app is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The enviroCar app 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 the enviroCar app. If not, see http://www.gnu.org/licenses/.
*/
package org.envirocar.core.entity;
import org.envirocar.core.exception.FuelConsumptionException;
import org.envirocar.core.exception.NoMeasurementsException;
import org.envirocar.core.exception.UnsupportedFuelTypeException;
import org.envirocar.core.logging.Logger;
import org.envirocar.core.trackprocessing.TrackStatisticsProcessor;
import org.envirocar.core.trackprocessing.TrackStatisticsProvider;
import org.envirocar.core.util.TrackMetadata;
import java.util.ArrayList;
import java.util.List;
/**
* TODO JavaDoc
*
* @author dewall
*/
public class TrackImpl implements Track, TrackStatisticsProvider {
private static final Logger LOG = Logger.getLogger(TrackImpl.class);
private TrackStatisticsProcessor STATISTICS_PROCESSOR;
protected TrackId trackID;
protected String remoteID;
protected String name;
protected String description;
protected Car car;
protected Long lastModified;
protected Long startTime;
protected Long endTime;
protected TrackMetadata metadata;
protected Track.TrackStatus trackStatus = Track.TrackStatus.ONGOING;
protected List<Measurement> measurements = new ArrayList<Measurement>();
protected DownloadState downloadState;
protected boolean isLazyLoadingMeasurements = false;
protected Double distanceOfTrack;
protected Double consumptionPerHour;
protected Double co2Average;
protected Double literPerHundredKm;
protected Double gramsPerKm;
/**
* Default constructor with downloaded state.
*/
public TrackImpl() {
this(DownloadState.DOWNLOADED);
}
/**
* Constructor.
*
* @param downloadState the state of the track whether it is a re
*/
public TrackImpl(DownloadState downloadState) {
this.downloadState = downloadState;
}
@Override
public TrackId getTrackID() {
return trackID;
}
@Override
public void setTrackID(TrackId trackID) {
this.trackID = trackID;
}
@Override
public String getRemoteID() {
return remoteID;
}
@Override
public void setRemoteID(String remoteID) {
this.remoteID = remoteID;
}
@Override
public boolean isLazyLoadingMeasurements() {
return false;
}
@Override
public void setLazyMeasurements(boolean lazyLoadingMeasurements) {
this.isLazyLoadingMeasurements = lazyLoadingMeasurements;
}
@Override
public Track carbonCopy() {
Track track = new TrackImpl(downloadState);
track.setTrackID(trackID);
track.setRemoteID(remoteID);
track.setName(name);
track.setDescription(description);
track.setCar(car);
track.setStartTime(startTime);
track.setEndTime(endTime);
track.setMetadata(metadata);
track.setTrackStatus(trackStatus);
track.setMeasurements(new ArrayList<>(measurements));
track.setLazyMeasurements(isLazyLoadingMeasurements);
return track;
}
@Override
public boolean isDownloaded() {
return car != null;
}
@Override
public boolean isDownloading() {
return downloadState == DownloadState.DOWNLOADING;
}
@Override
public DownloadState getDownloadState() {
return this.downloadState;
}
@Override
public void setDownloadState(DownloadState downloadState) {
this.downloadState = downloadState;
}
@Override
public String getName() {
return name;
}
@Override
public void setName(String name) {
this.name = name;
}
@Override
public String getDescription() {
return description;
}
@Override
public void setDescription(String description) {
this.description = description;
}
@Override
public Car getCar() {
return car;
}
@Override
public void setCar(Car car) {
this.car = car;
this.STATISTICS_PROCESSOR = new TrackStatisticsProcessor(car.getFuelType());
}
@Override
public boolean isLocalTrack() {
return remoteID == null;
}
@Override
public boolean isRemoteTrack() {
return !isLocalTrack();
}
@Override
public Long getLastModified() {
return lastModified;
}
@Override
public void setLastModified(long lastModified) {
this.lastModified = lastModified;
}
@Override
public Long getStartTime() throws NoMeasurementsException {
if (startTime == null) {
setStartTime(getFirstMeasurement().getTime());
}
return startTime;
}
@Override
public void setStartTime(Long startTime) {
this.startTime = startTime;
}
@Override
public Long getEndTime() throws NoMeasurementsException {
if (endTime == null) {
setEndTime(getLastMeasurement().getTime());
}
return endTime;
}
@Override
public void setEndTime(Long endTime) {
this.endTime = endTime;
}
@Override
public long getDuration() throws NoMeasurementsException {
return getEndTime() - getStartTime();
}
@Override
public TrackStatus getTrackStatus() {
return trackStatus;
}
@Override
public void setTrackStatus(TrackStatus trackStatus) {
this.trackStatus = trackStatus;
}
@Override
public boolean isFinished() {
return this.trackStatus == TrackStatus.FINISHED;
}
@Override
public TrackMetadata getMetadata() {
return this.metadata;
}
@Override
public void setMetadata(TrackMetadata metadata) {
this.metadata = metadata;
}
@Override
public TrackMetadata updateMetadata(TrackMetadata metadata) {
if (this.metadata != null) {
this.metadata.merge(metadata);
} else {
setMetadata(metadata);
}
return this.metadata;
}
@Override
public Measurement getFirstMeasurement() throws NoMeasurementsException {
if (measurements.isEmpty()) {
throw new NoMeasurementsException("Track with no measurements!");
}
return measurements.get(0);
}
@Override
public Measurement getLastMeasurement() throws NoMeasurementsException {
if (measurements.isEmpty()) {
throw new NoMeasurementsException("Track with no measurements!");
}
return measurements.get(measurements.size() - 1);
}
@Override
public List<Measurement> getMeasurements() {
return measurements;
}
@Override
public void setMeasurements(List<Measurement> measurements) {
// Preconditions.checkState(measurements != null && measurements.size() > 0, "A
// track is not" +
// " allowed to have empty measuremnts");
this.measurements = measurements;
}
@Override
public boolean hasProperty(Measurement.PropertyKey propertyKey) {
for(Measurement m : measurements){
if(m.hasProperty(propertyKey)) {
return true;
}
}
return false;
}
@Override
public List<Measurement.PropertyKey> getSupportedProperties() {
List<Measurement.PropertyKey> result = new ArrayList<>();
for(Measurement.PropertyKey key : Measurement.PropertyKey.values()){
if(hasProperty(key)){
result.add(key);
}
}
return result;
}
@Override
public int compareTo(Track another) {
if (downloadState == DownloadState.REMOTE) {
if (another.getDownloadState() == DownloadState.REMOTE) {
lastModified.compareTo(another.getLastModified());
} else {
return 1;
}
} else {
if (another.getDownloadState() == DownloadState.REMOTE) {
return -1;
}
}
try {
if (another.getStartTime() == null && another.getEndTime() == null) {
/*
* we cannot assume any ordering
*/
return 0;
}
} catch (NoMeasurementsException e) {
return 0;
}
try {
if (this.getStartTime() == null) {
/*
* no measurements, this is probably a relatively new track
*/
return -1;
}
} catch (NoMeasurementsException e) {
return -1;
}
try {
if (another.getStartTime() == null) {
/*
* no measurements, that is probably a relatively new track
*/
return 1;
}
} catch (NoMeasurementsException e) {
return 1;
}
try {
return (this.getStartTime() < another.getStartTime() ? 1 : -1);
} catch (NoMeasurementsException e) {
return 0;
}
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!(o instanceof TrackImpl))
return false;
TrackImpl track = (TrackImpl) o;
if (remoteID != null && track.getRemoteID() != null) {
return remoteID.equals(track.getRemoteID());
} else if (trackID != null && track.trackID != null) {
return trackID.getId() == track.trackID.getId();
} else {
if (trackID != null ? !trackID.equals(track.trackID) : track.trackID != null)
return false;
if (name != null ? !name.equals(track.name) : track.name != null) return false;
if (description != null ? !description.equals(track.description) : track.description !=
null)
return false;
if (car != null ? !car.equals(track.car) : track.car != null) return false;
if (startTime != null ? !startTime.equals(track.startTime) : track.startTime != null)
return false;
if (endTime != null ? !endTime.equals(track.endTime) : track.endTime != null)
return false;
return !(metadata != null ? !metadata.equals(track.metadata) : track.metadata != null);
}
}
@Override
public int hashCode() {
int result = trackID != null ? trackID.hashCode() : 0;
result = 31 * result + (name != null ? name.hashCode() : 0);
result = 31 * result + (description != null ? description.hashCode() : 0);
result = 31 * result + (car != null ? car.hashCode() : 0);
result = 31 * result + (startTime != null ? startTime.hashCode() : 0);
result = 31 * result + (endTime != null ? endTime.hashCode() : 0);
result = 31 * result + (metadata != null ? metadata.hashCode() : 0);
return result;
}
@Override
public double getDistanceOfTrack() {
if (distanceOfTrack == null) {
distanceOfTrack = STATISTICS_PROCESSOR.computeDistanceOfTrack(getMeasurements());
}
return distanceOfTrack;
}
@Override
public double getFuelConsumptionPerHour() throws FuelConsumptionException {
if (consumptionPerHour == null) {
consumptionPerHour = STATISTICS_PROCESSOR.getFuelConsumptionPerHour(getMeasurements());
}
return consumptionPerHour;
}
@Override
public double getCO2Average() throws FuelConsumptionException {
if (co2Average == null) {
co2Average = STATISTICS_PROCESSOR.getCO2Average(getMeasurements());
}
return co2Average;
}
@Override
public double getLiterPerHundredKm() throws FuelConsumptionException, NoMeasurementsException {
if (literPerHundredKm == null) {
literPerHundredKm = STATISTICS_PROCESSOR.getLiterPerHundredKm(
getFuelConsumptionPerHour(), getDuration(), getDistanceOfTrack());
}
return literPerHundredKm;
}
@Override
public double getGramsPerKm() throws FuelConsumptionException, NoMeasurementsException,
UnsupportedFuelTypeException {
if (gramsPerKm == null) {
gramsPerKm = STATISTICS_PROCESSOR.getGramsPerKm(getLiterPerHundredKm(), getCar()
.getFuelType());
}
return gramsPerKm;
}
}