package interdroid.swan.swansong;
import java.io.Serializable;
import java.util.Collections;
import java.util.List;
import android.os.Parcel;
import android.os.Parcelable;
/**
* A tuple containing a value, a timestamp. Also includes static methods for
* some calculations on lists of TimestampedValues
*
* @author roelof <rkemp@cs.vu.nl>
* @author nick <palmer@cs.vu.nl>
*/
public class TimestampedValue implements Serializable, Parcelable,
Comparable<TimestampedValue> {
/**
*
*/
private static final long serialVersionUID = -1758020216184616414L;
/** The value. */
private Object mValue;
/** The timestamp. */
private long mTimestamp;
/**
* Construct from a parcel.
*
* @param saved
* read from a parcel
*/
private TimestampedValue(final Parcel saved) {
readFromParcel(saved);
}
/**
* Instantiates a new timestamped value.
*
* @param value
* the value
*/
public TimestampedValue(final Object value) {
this(value, System.currentTimeMillis());
}
/**
* Instantiates a new timestamped value.
*
* @param value
* the value
* @param timestamp
* the timestamp
*/
public TimestampedValue(final Object value, final long timestamp) {
this.mValue = value;
this.mTimestamp = timestamp;
}
/**
* @return the value
*/
public final Object getValue() {
return mValue;
}
/**
* @return the timestamp
*/
public final long getTimestamp() {
return mTimestamp;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
@Override
public final String toString() {
return "" + mValue + " (timestamp: " + mTimestamp + ")";
}
/**
* Applies the reduction mode to the values.
*
* @param values
* the value to reduce
* @return the reduced values.
*/
public static TimestampedValue[] applyMode(
final List<TimestampedValue> values, HistoryReductionMode mode) {
switch (mode) {
case MAX:
return new TimestampedValue[] { TimestampedValue
.findMaxValue(values) };
case MIN:
return new TimestampedValue[] { TimestampedValue
.findMinValue(values) };
case MEAN:
return new TimestampedValue[] { TimestampedValue
.calculateMean(values) };
case MEDIAN:
return new TimestampedValue[] { TimestampedValue
.calculateMedian(values) };
case ALL:
case ANY:
default:
return values.toArray(new TimestampedValue[values.size()]);
}
}
/**
* Calculate mean over array of values.
*
* @param values
* an array of timestamped values (double or castable to double)
*
* @return the mean value, with the oldest timestamp of all values (it will
* be invalid when this timestamp is no longer in the history
* window)
*/
public static TimestampedValue calculateMean(
final List<TimestampedValue> values) {
double sumValues = 0.0;
for (TimestampedValue value : values) {
sumValues += (Double) value.mValue;
}
return new TimestampedValue(sumValues / values.size(),
values.get(0).mTimestamp);
}
/**
* Calculate a time weighted mean over array of values.
*
* @param values
* an array of timestamped values (double or castable to double)
*
* @return the time weighted mean value, with the oldest timestamp of all
* values (it will be invalid when this timestamp is no longer in
* the history window)
*/
public static TimestampedValue calculateTimeWeightedMean(
final TimestampedValue[] values) {
throw new RuntimeException("Not implemented");
}
/**
* @param values
* the values to search for the median in
* @return the median value, with the oldest timestamp of all values (it
* will be invalid when this timestamp is no longer in the history
* window)
*/
public static final TimestampedValue calculateMedian(
final List<TimestampedValue> values) {
long timestamp = values.get(0).getTimestamp();
Collections.sort(values);
TimestampedValue result = values.get(values.size() / 2);
result.mTimestamp = timestamp;
return result;
}
/**
* Find maximum value.
*
* @param values
* an array of timestamped values
*
* @return the timestamped maximum value
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public static TimestampedValue findMaxValue(
final List<TimestampedValue> values) {
TimestampedValue maxValue = null;
for (TimestampedValue value : values) {
if (maxValue == null) {
maxValue = value;
} else if (((Comparable) maxValue.mValue).compareTo(value.mValue) < 0) {
maxValue = value;
}
}
return maxValue;
}
/**
* Find mininimum value.
*
* @param values
* an array of timestamped values
*
* @return the timestamped minimum value
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public static TimestampedValue findMinValue(
final List<TimestampedValue> values) {
TimestampedValue minValue = null;
for (TimestampedValue value : values) {
if (minValue == null) {
minValue = value;
} else if (((Comparable) minValue.mValue).compareTo(value.mValue) > 0) {
minValue = value;
}
}
return minValue;
}
@Override
public final int describeContents() {
return 0;
}
@Override
public final void writeToParcel(final Parcel dest, final int flags) {
dest.writeLong(mTimestamp);
dest.writeValue(mValue);
}
/**
* Read from parcel.
*
* @param in
* the in
*/
private void readFromParcel(final Parcel in) {
mTimestamp = in.readLong();
mValue = in.readValue(this.getClass().getClassLoader());
}
/** The CREATOR. */
public static final TimestampedValue.Creator<TimestampedValue> CREATOR = new TimestampedValue.Creator<TimestampedValue>() {
@Override
public TimestampedValue createFromParcel(final Parcel source) {
return new TimestampedValue(source);
}
@Override
public TimestampedValue[] newArray(final int size) {
return new TimestampedValue[size];
}
};
@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
public final int compareTo(final TimestampedValue another) {
return ((Comparable) mValue)
.compareTo(((TimestampedValue) another).mValue);
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
public boolean equals(Object o) {
if (o == null) {
return false;
}
if (o instanceof TimestampedValue) {
if (mTimestamp != ((TimestampedValue) o).mTimestamp) {
return false;
}
if (mValue instanceof Comparable<?>
&& ((TimestampedValue) o).mValue instanceof Comparable<?>) {
if (((Comparable) mValue)
.compareTo((Comparable) ((TimestampedValue) o).mValue) == 0) {
return true;
}
}
}
return super.equals(o);
}
}