package com.github.davidmoten.rtree.geometry;

import com.github.davidmoten.util.ObjectsHelper;
import com.google.common.base.Objects;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;

public final class Rectangle implements Geometry, HasGeometry {
    private final float x1, y1, x2, y2;

    protected Rectangle(float x1, float y1, float x2, float y2) {
        Preconditions.checkArgument(x2 >= x1);
        Preconditions.checkArgument(y2 >= y1);
        this.x1 = x1;
        this.y1 = y1;
        this.x2 = x2;
        this.y2 = y2;
    }

    public float x1() {
        return x1;
    }

    public float y1() {
        return y1;
    }

    public float x2() {
        return x2;
    }

    public float y2() {
        return y2;
    }

    public float area() {
        return (x2 - x1) * (y2 - y1);
    }

    public Rectangle add(Rectangle r) {
        return new Rectangle(Math.min(x1, r.x1), Math.min(y1, r.y1), Math.max(x2, r.x2),
                Math.max(y2, r.y2));
    }

    public static Rectangle create(double x1, double y1, double x2, double y2) {
        return new Rectangle((float) x1, (float) y1, (float) x2, (float) y2);
    }

    public static Rectangle create(float x1, float y1, float x2, float y2) {
        return new Rectangle(x1, y1, x2, y2);
    }

    public boolean contains(double x, double y) {
        return x >= x1 && x <= x2 && y >= y1 && y <= y2;
    }

    @Override
    public boolean intersects(Rectangle r) {
        return !(x1 > r.x2 || x2 < r.x1 || y1 > r.y2 || y2 < r.y1);
    }

    @Override
    public double distance(Rectangle r) {
        if (intersects(r))
            return 0;
        else {
            Rectangle mostLeft = x1 < r.x1 ? this : r;
            Rectangle mostRight = x1 > r.x1 ? this : r;
            double xDifference = Math.max(0,
                    mostLeft.x1 == mostRight.x1 ? 0 : mostRight.x1 - mostLeft.x2);

            Rectangle upper = y1 < r.y1 ? this : r;
            Rectangle lower = y1 > r.y1 ? this : r;

            double yDifference = Math.max(0, upper.y1 == lower.y1 ? 0 : lower.y1 - upper.y2);

            return Math.sqrt(xDifference * xDifference + yDifference * yDifference);
        }
    }

    @Override
    public Rectangle mbr() {
        return this;
    }

    @Override
    public String toString() {
        return "Rectangle [x1=" + x1 + ", y1=" + y1 + ", x2=" + x2 + ", y2=" + y2 + "]";
    }

    @Override
    public int hashCode() {
        return Objects.hashCode(x1, y1, x2, y2);
    }

    @Override
    public boolean equals(Object obj) {
        Optional<Rectangle> other = ObjectsHelper.asClass(obj, Rectangle.class);
        if (other.isPresent()) {
            return Objects.equal(x1, other.get().x1) && Objects.equal(x2, other.get().x2)
                    && Objects.equal(y1, other.get().y1) && Objects.equal(y2, other.get().y2);
        } else
            return false;
    }

    public float intersectionArea(Rectangle r) {
        if (!intersects(r))
            return 0;
        else
            return create(Math.max(x1, r.x1), Math.max(y1, r.y1), Math.min(x2, r.x2),
                    Math.min(y2, r.y2)).area();
    }

    public float perimeter() {
        return 2 * (x2 - x1) + 2 * (y2 - y1);
    }

    @Override
    public Geometry geometry() {
        return this;
    }

}
@@ -914,21 +914,16 @@
 ctangle(
-Math.
 min(x1, 
@@ -925,29 +925,24 @@
 (x1, r.x1), 
-Math.
 min(y1, r.y1
@@ -940,29 +940,24 @@
 (y1, r.y1), 
-Math.
 max(x2, r.x2
@@ -962,30 +962,9 @@
 x2),
-%0A                Math.
+ 
 max(
@@ -1786,29 +1786,24 @@
 ifference = 
-Math.
 max(0,%0A     
@@ -2019,21 +2019,16 @@
 rence = 
-Math.
 max(0, u
@@ -3027,21 +3027,16 @@
  create(
-Math.
 max(x1, 
@@ -3042,21 +3042,16 @@
  r.x1), 
-Math.
 max(y1, 
@@ -3057,21 +3057,16 @@
  r.y1), 
-Math.
 min(x2, 
@@ -3075,34 +3075,9 @@
 x2),
-%0A                    Math.
+ 
 min(
@@ -3229,24 +3229,24 @@
 eometry() %7B%0A
-
         retu
@@ -3261,9 +3261,273 @@
 %0A    %7D%0A%0A
+    private static float max(float a, float b) %7B%0A        if (a %3C b)%0A            return b;%0A        else%0A            return a;%0A    %7D%0A%0A    private static float min(float a, float b) %7B%0A        if (a %3C b)%0A            return a;%0A        else%0A            return b;%0A    %7D%0A%0A
 %7D

use simplified min and max that doesn't do NaN checks