package org.helioviewer.jhv.base.interval;

import java.util.ArrayList;

import javax.annotation.Nonnull;

import org.helioviewer.jhv.time.TimeUtils;

public class Interval implements Comparable<Interval> {

    public final long start;
    public final long end;

    public Interval(long _start, long _end) {
        start = _start;
        end = _end;
    }

    public boolean containsInclusive(Interval other) {
        return containsPointInclusive(other.start) && containsPointInclusive(other.end);
    }

    public boolean containsPointInclusive(long time) {
        return time >= start && time <= end;
    }

    public boolean overlaps(Interval otherInterval) {
        return start <= otherInterval.end && end >= otherInterval.start;
    }

    public boolean overlapsInclusive(Interval other) {
        return containsPointInclusive(other.start) || containsPointInclusive(other.end) || other.containsPointInclusive(start) || other.containsPointInclusive(end);
    }

    /**
     * Returns the value that is as close as possible to the given value, but
     * still contained in the interval. If the given value is outside the
     * interval, the the interval's closest 'edge' is returned.
     */
    public long squeeze(long value) {
        if (containsPointInclusive(value)) {
            return value;
        }
        if (value <= start) {
            return start;
        }
        return end;
    }

    public static Interval makeCompleteDay(long start, long end) {
        long now = System.currentTimeMillis();
        if (end > now) {
            end = now;
        }
        return new Interval(TimeUtils.floorDay(start), TimeUtils.floorDay(end) + TimeUtils.DAY_IN_MILLIS);
    }

    public static ArrayList<Interval> splitInterval(Interval interval, int days) {
        ArrayList<Interval> intervals = new ArrayList<>();
        long startDate = interval.start;

        while (true) {
            long newStartDate = startDate + TimeUtils.DAY_IN_MILLIS * days;
            if (interval.containsPointInclusive(newStartDate)) {
                intervals.add(new Interval(startDate, newStartDate));
                startDate = newStartDate;
            } else {
                intervals.add(new Interval(startDate, interval.end));
                break;
            }
        }

        return intervals;
    }

    @Override
    public boolean equals(Object o) {
        if (!(o instanceof Interval))
            return false;
        Interval s = (Interval) o;
        return start == s.start && end == s.end;
    }

    @Override
    public int hashCode() {
        int result = (int) (start ^ (start >>> 32));
        return 31 * result + (int) (end ^ (end >>> 32));
    }

    @Override
    public String toString() {
        return "[" + start + ',' + end + ')';
    }

    @Override
    public int compareTo(@Nonnull Interval o) {
        if (start < o.start) {
            return -1;
        }
        if (start == o.start && end < o.end) {
            return -1;
        }
        if (start == o.start && end == o.end) {
            return 0;
        }
        return 1;
    }

}

@@ -300,24 +300,135 @@
 ong _end) %7B%0A
+        if (_end %3C _start)%0A            throw new IllegalArgumentException(%22End cannot be earlier than start%22);%0A
         star

Check arguments in Interval constructor