package Utils;

public class Range2D<TComparable extends Comparable<TComparable>>
{
    public Range2D(TComparable horizontalStart, TComparable horizontalStop, TComparable verticalStart, TComparable verticalStop)
    {
        if (Comparer.isLeftStrictlyGreaterThanRight(horizontalStart, horizontalStop))
        {
            throw new IllegalArgumentException("horizontalStart > horizontalStop");
        }
        else if (Comparer.isLeftStrictlyGreaterThanRight(verticalStart, verticalStop))
        {
            throw new IllegalArgumentException("verticalStart > verticalStop");
        }
        else
        {
            this._horizontalRange = new Range1D<TComparable>(horizontalStart, horizontalStop);
            this._verticalRange = new Range1D<TComparable>(verticalStart, verticalStop);
        }
    }

    public static <TComparable extends Comparable<TComparable>> Range2D<TComparable> Create(TComparable horizontalStart, TComparable horizontalStop, TComparable verticalStart, TComparable verticalStop)
    {
        return new Range2D<TComparable>(horizontalStart, horizontalStop, verticalStart, verticalStop);
    }

    private final Range1D<TComparable> _horizontalRange;
    private final Range1D<TComparable> _verticalRange;

    public TComparable getHorizontalStart()
    {
        return this.getHorizontalRange().getStart();
    }
    public TComparable getHorizontalStop()
    {
        return this.getHorizontalRange().getStop();
    }
    public TComparable getVerticalStart()
    {
        return this.getVerticalRange().getStart();
    }
    public TComparable getVerticalStop()
    {
        return this.getVerticalRange().getStop();
    }

    public Range1D<TComparable> getHorizontalRange()
    {
        return this._horizontalRange;
    }
    public Range1D<TComparable> getVerticalRange()
    {
        return this._verticalRange;
    }

    public boolean intersects(Range2D<TComparable> interval)
    {
        return
        this.getVerticalRange().intersects(interval.getVerticalRange()) ||
        this.getHorizontalRange().intersects(interval.getHorizontalRange());
    }

    public boolean includes(Range2D<TComparable> interval)
    {
        return
        this.getVerticalRange().includes(interval.getVerticalRange()) &&
        this.getHorizontalRange().includes(interval.getHorizontalRange());
    }

    public boolean strictlyIncludes(Range2D<TComparable> interval)
    {
        return
        this.getVerticalRange().strictlyIncludes(interval.getVerticalRange()) &&
        this.getHorizontalRange().strictlyIncludes(interval.getHorizontalRange());
    }

    public boolean includes(Pair<TComparable, TComparable> value)
    {
        return
        this.getHorizontalRange().includes(value.getValue1()) &&
        this.getVerticalRange().includes(value.getValue2());
    }

    public boolean strictlyIncludes(Pair<TComparable, TComparable> value)
    {
        return
        this.getHorizontalRange().strictlyIncludes(value.getValue1()) &&
        this.getVerticalRange().strictlyIncludes(value.getValue2());
    }
}
