package org.helioviewer.jhv.base.interval;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

public class Interval implements Comparable<Interval> {

    public Date start;

    public Date end;

    private Interval(Interval other) {
        this.start = other.start;
        this.end = other.end;
    }

    public Interval(Date start, Date end) {
        this.start = start;
        this.end = end;
        if (start == null || end == null) {
            Thread.dumpStack();
            System.exit(1);
        }
    }

    public boolean contains(Interval other) {
        return this.containsPoint(other.start) && this.containsPoint(other.end);
    }

    public boolean containsFully(Interval other) {
        return this.containsPointFully(other.start) && this.containsPointFully(other.end);
    }

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

    public boolean containsPoint(Date time) {
        // start inclusive, end exclusive!
        assert start.compareTo(end) <= 0;
        return (time.compareTo(this.start) >= 0) && (time.compareTo(this.end) < 0);
        // return (time >= this.start) && (time < this.end);
    }

    public boolean containsPointFully(Date time) {
        assert start.compareTo(end) <= 0;
        return (time.compareTo(this.start) > 0) && (time.compareTo(this.end) < 0);
    }

    public boolean containsPointInclusive(Date time) {
        assert start.compareTo(end) <= 0;
        return (time.compareTo(this.start) >= 0) && (time.compareTo(this.end) <= 0);
    }

    public boolean overlaps(Interval other) {
        return (this.containsPoint(other.start) || this.containsPoint(other.end)) || (other.containsPoint(this.start) || other.containsPoint(this.end));
    }

    public boolean overlapsInclusive(Interval other) {
        return (this.containsPointInclusive(other.start) || this.containsPointInclusive(other.end)) || (other.containsPointInclusive(this.start) || other.containsPointInclusive(this.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 Date squeeze(Date value) {
        if (this.containsPointInclusive(value)) {
            return value;
        } else if (value.compareTo(start) < 0) {
            return start;
        } else if (value.compareTo(end) > 0) {
            return end;
        }
        // this case should never occur
        assert false;
        return value;
    }

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

    @Override
    public int compareTo(Interval other) {
        return this.start.compareTo(other.start);
    }

    /**
     * Returns the intersection of this and the given interval.
     * <p>
     * If both intervals do not overlap the current interval will be returned.
     * If the current interval is not valid, the given interval is returned.
     *
     * @param other
     *            the interval to get the intersection with current one
     * @return the intersected interval, or in special cases, the given or the
     *         current interval
     * */
    public Interval intersectInterval(Interval other) {
        Interval result = new Interval(this);
        if (!this.isValid()) {
            result = new Interval(other);
        } else if (this.overlaps(other)) {
            if (this.start.compareTo(other.start) < 0) {
                result.start = other.start;
            }
            if (this.end.compareTo(other.end) > 0) {
                result.end = other.end;
            }
        }
        return result;
    }

    public static ArrayList<Interval> splitInterval(final Interval interval, int days) {
        final ArrayList<Interval> intervals = new ArrayList<Interval>();

        final Calendar calendar = new GregorianCalendar();
        Date startDate = interval.start;

        while (true) {
            calendar.clear();
            calendar.setTime(startDate);
            calendar.add(Calendar.DAY_OF_MONTH, days);

            final Date newStartDate = calendar.getTime();

            if (interval.containsPointInclusive(newStartDate)) {
                intervals.add(new Interval(startDate, calendar.getTime()));
                startDate = newStartDate;
            } else {
                intervals.add(new Interval(startDate, interval.end));
                break;
            }
        }

        return intervals;
    }

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

    @Override
    public int hashCode() {
        return (this.start.toString() + " - " + this.end.toString()).hashCode();
    }

    private boolean isValid() {
        if (this.start.compareTo(this.end) > 0) {
            return false;
        }
        return true;
    }

}

@@ -228,25 +228,24 @@
 Date start;%0A
-%0A
     public D
@@ -258,118 +258,8 @@
 d;%0A%0A
-    private Interval(Interval other) %7B%0A        this.start = other.start;%0A        this.end = other.end;%0A    %7D%0A%0A
     
@@ -502,1276 +502,321 @@
 ains
-(Interval other) %7B%0A        return this.containsPoint(other.start) && this.containsPoint(other.end);%0A    %7D%0A%0A    public boolean containsFully(Interval other) %7B%0A        return this.containsPointFully(other.start) && this.containsPointFully(other.end);%0A    %7D%0A%0A    public boolean containsInclusive(Interval other) %7B%0A        return this.containsPointInclusive(other.start) && this.containsPointInclusive(other.end);%0A    %7D%0A%0A    public boolean containsPoint(Date time) %7B%0A        // start inclusive, end exclusive!%0A        assert start.compareTo(end) %3C= 0;%0A        return (time.compareTo(this.start) %3E= 0) && (time.compareTo(this.end) %3C 0);%0A        // return (time %3E= this.start) && (time %3C this.end);%0A    %7D%0A%0A    public boolean containsPointFully(Date time) %7B%0A        assert start.compareTo(end) %3C= 0;%0A        return (time.compareTo(this.start) %3E 0) && (time.compareTo(this.end) %3C 0);%0A    %7D%0A%0A    public boolean containsPointInclusive(Date time) %7B%0A        assert start.compareTo(end) %3C= 0;%0A        return (time.compareTo(this.start) %3E= 0) && (time.compareTo(this.end) %3C= 0);%0A    %7D%0A%0A    public boolean overlaps(Interval other) %7B%0A        return (this.containsPoint(other.start) %7C%7C this.containsPoint(other.end)) %7C%7C (other.containsPoint(this.start) %7C%7C other.containsPoint(this.end)
+Inclusive(Interval other) %7B%0A        return this.containsPointInclusive(other.start) && this.containsPointInclusive(other.end);%0A    %7D%0A%0A    public boolean containsPointInclusive(Date time) %7B%0A        assert start.compareTo(end) %3C= 0;%0A        return (time.compareTo(this.start) %3E= 0) && (time.compareTo(this.end) %3C= 0
 );%0A 
@@ -1881,947 +1881,8 @@
  %7D%0A%0A
-    /**%0A     * Returns the intersection of this and the given interval.%0A     * %3Cp%3E%0A     * If both intervals do not overlap the current interval will be returned.%0A     * If the current interval is not valid, the given interval is returned.%0A     *%0A     * @param other%0A     *            the interval to get the intersection with current one%0A     * @return the intersected interval, or in special cases, the given or the%0A     *         current interval%0A     * */%0A    public Interval intersectInterval(Interval other) %7B%0A        Interval result = new Interval(this);%0A        if (!this.isValid()) %7B%0A            result = new Interval(other);%0A        %7D else if (this.overlaps(other)) %7B%0A            if (this.start.compareTo(other.start) %3C 0) %7B%0A                result.start = other.start;%0A            %7D%0A            if (this.end.compareTo(other.end) %3E 0) %7B%0A                result.end = other.end;%0A            %7D%0A        %7D%0A        return result;%0A    %7D%0A%0A
     
@@ -3095,152 +3095,6 @@
  %7D%0A%0A
-    private boolean isValid() %7B%0A        if (this.start.compareTo(this.end) %3E 0) %7B%0A            return false;%0A        %7D%0A        return true;%0A    %7D%0A%0A
 %7D%0A

remove unused methods