package glug.model.time; import static com.madgag.interval.Bound.*; import static com.madgag.interval.Bound.MAX; import static com.madgag.interval.Bound.MIN; import static com.madgag.interval.IntervalClosure.CLOSED_OPEN; import static com.madgag.interval.IntervalClosure.OPEN_CLOSED; import static java.lang.Math.min; import com.madgag.interval.Bound; import org.joda.time.Duration; import org.joda.time.Interval; import com.madgag.interval.AbstractInterval; import com.madgag.interval.IntervalClosure; public class LogInterval extends AbstractInterval<LogInstant> { private final LogInstant start,end; public LogInterval(LogInstant a, LogInstant b) { if (a==null || b==null) { throw new IllegalArgumentException(); } if (a.isAfter(b)) { //throw new IllegalArgumentException(); this.start = b; this.end = a; } else { this.start = a; this.end = b; } } public LogInterval(Duration duration, LogInstant logInstantAtEnd) { this.start = new LogInstant(logInstantAtEnd.getMillis() - duration.getMillis(),logInstantAtEnd.getLogLine()); // TODO De-hack? this.end = logInstantAtEnd; } public LogInterval(Interval interval) { this(interval.toDuration(), new LogInstant(interval.getEnd().toInstant())); } public LogInstant getStart() { return start; } public LogInstant getEnd() { return end; } /** * Is this time interval entirely after the specified interval. * <p> * Intervals are inclusive of the start instant and exclusive of the end. */ public boolean isAfter(LogInterval otherLogInterval) { return !otherLogInterval.end.isAfter(start); } public boolean isAfter(LogInstant otherInstant) { return start.isAfter(otherInstant); } /** * Is this time interval before the specified millisecond instant. * <p> * Intervals are inclusive of the start instant and exclusive of the end. * */ public boolean isBefore(LogInstant otherInstant) { return !end.isAfter(otherInstant); } public boolean isBefore(LogInterval otherInterval) { return isBefore(otherInterval.getStart()); } public LogInterval union(LogInterval otherInterval) { if (otherInterval==null) { return this; } if (contains(otherInterval)) { return this; } if (otherInterval.contains(this)) { return otherInterval; } LogInstant unionStart=start.isBefore(otherInterval.start)?start:otherInterval.start; LogInstant unionEnd=end.isAfter(otherInterval.end)?end:otherInterval.end; return new LogInterval(unionStart,unionEnd); } public long toDurationMillis() { return end.getMillis()-start.getMillis(); } public static long durationInMillisOf(com.madgag.interval.Interval<LogInstant> interval) { return interval.get(MAX).getMillis() - interval.get(MIN).getMillis(); } @Override public String toString() { String diffString = diff(start.getRecordedInstant().toString(),end.getRecordedInstant().toString()); return diffString+":lines="+start.getLogLine()+"-"+end.getLogLine(); } private String diff(String s1, String s2) { int maxIndex = min(s1.length(), s2.length()); int index = 0; for (; index < maxIndex && s1.charAt(index) == s2.charAt(index); ++index) { } return s1.substring(0, index)+"["+s1.substring(index)+"|"+s2.substring(index)+"]"; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((end == null) ? 0 : end.hashCode()); result = prime * result + ((start == null) ? 0 : start.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; LogInterval other = (LogInterval) obj; if (end == null) { if (other.end != null) return false; } else if (!end.equals(other.end)) return false; if (start == null) { if (other.start != null) return false; } else if (!start.equals(other.start)) return false; return true; } public Interval toJodaInterval() { return new Interval(start.getMillis(),end.getMillis()); } public static Interval toJodaInterval(com.madgag.interval.Interval<LogInstant> interval) { return new LogInterval(interval.get(MIN),interval.get(MAX)).toJodaInterval(); } public LogInterval overlap(LogInterval otherLogInterval) { if (!overlaps(otherLogInterval)) { return null; } if (contains(otherLogInterval)) { return otherLogInterval; } if (otherLogInterval.contains(this)) { return this; } LogInstant overlapStart = start.isAfter(otherLogInterval.start)?start:otherLogInterval.start; LogInstant overlapEnd = end.isBefore(otherLogInterval.end)?end:otherLogInterval.end; return new LogInterval(overlapStart,overlapEnd); } public static LogInterval intervalContainingDeltaFor(LogInterval intervalA, LogInterval intervalB) { if (intervalA==null || intervalB==null) { return intervalA!=null?intervalA:intervalB; } if (intervalA.start.equals(intervalB.start)) { return new LogInterval(intervalA.end,intervalB.end); } if (intervalA.end.equals(intervalB.end)) { return new LogInterval(intervalA.start,intervalB.start); } return intervalA.union(intervalB); } @Override public LogInstant get(Bound bound) { return bound==MIN?start:end; } @Override public IntervalClosure getClosure() { return CLOSED_OPEN; } }