package com.plectix.simulator.streaming;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;
/*package*/ final class SegmentCovering {
/**
* This is the time segment with LiveDataPoints as ends.
*/
private static final class Segment implements Comparable<Segment> {
private LiveDataPoint firstPoint;
private LiveDataPoint secondPoint;
private double length;
public Segment(LiveDataPoint firstPoint, LiveDataPoint secondPoint) {
this.firstPoint = firstPoint;
this.secondPoint = secondPoint;
length = secondPoint.getEventTime() - firstPoint.getEventTime();
}
@Override
public final int compareTo(Segment segment) {
if (segment == this) {
return 0;
}
int result = Double.compare(this.length, segment.length);
if (result == 0) {
return (int)(this.firstPoint.getEventNumber() - segment.secondPoint.getEventNumber());
}
return result;
}
@Override
public final boolean equals(Object o) {
return this == o;
}
public final String toString() {
return firstPoint.getEventTime() + "||" + secondPoint.getEventTime();
}
public final void replaceDataWith(Segment s) {
firstPoint = s.firstPoint;
secondPoint = s.secondPoint;
length = s.length;
}
}
// pairs of segments, value following the key (they have one common point)
private TreeMap<Segment, Segment> covering = new TreeMap<Segment, Segment>();
private SegmentCovering() {
}
/**
* This method returns segment covering for the queue of LiveDataPoints (sorted by time!).
* <br>Input queue should contain more than 2 points.
* @param points input queue of LiveDataPoints
* @return segment covering for this queue
*/
public static final SegmentCovering getCovering(Collection<LiveDataPoint> points) {
SegmentCovering covering = new SegmentCovering();
Iterator<LiveDataPoint> iterator = points.iterator();
LiveDataPoint zeroPoint = iterator.next();
LiveDataPoint firstPoint = iterator.next();
Segment segment1 = new Segment(zeroPoint, firstPoint);
Segment segment2 = null;
// previousPoint -> point
while (iterator.hasNext()) {
LiveDataPoint secondPoint = iterator.next();
segment2 = new Segment(firstPoint, secondPoint);
if (segment1.length > 0) {
covering.addSegments(segment1, segment2);
}
zeroPoint = firstPoint;
firstPoint = secondPoint;
segment1 = segment2;
}
return covering;
}
// segment2 is the next after the segment1
private final void addSegments(Segment segment1, Segment segment2) {
covering.put(segment1, segment2);
}
/**
* This method takes the shortest segment in the covering and removes LiveDataPoint,
* which is the right end of this segment. <br>
* One exception - we don't see the most right segment. It can be the shortest one
* or whatever, we never delete it's ending points.
* @return LiveDataPoint we want to delete
*/
public final LiveDataPoint pop() {
if (covering.isEmpty()) {
return null;
}
Map.Entry<Segment, Segment> firstEntry = covering.pollFirstEntry();
Segment leftSegment = firstEntry.getKey();
Segment rightSegment = firstEntry.getValue();
LiveDataPoint removedPoint = leftSegment.secondPoint;
covering.remove(leftSegment);
Segment newBiggerSegment = new Segment(leftSegment.firstPoint, rightSegment.secondPoint);
// leftSegment maybe left in covering as a value, so we just change it's data
leftSegment.replaceDataWith(newBiggerSegment);
Segment theOneChangedByRightSegment = covering.remove(rightSegment);
if (theOneChangedByRightSegment != null) {
// leftSegment is now representing new bigger segment
covering.put(leftSegment, theOneChangedByRightSegment);
}
return removedPoint;
}
}