/**
 * This file is part of LibLaserCut.
 * Copyright (C) 2011 - 2013 Thomas Oster <thomas.oster@rwth-aachen.de>
 * RWTH Aachen University - 52062 Aachen, Germany
 *
 *     LibLaserCut is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU Lesser General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 *
 *     LibLaserCut is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU Lesser General Public License for more details.
 *
 *     You should have received a copy of the GNU Lesser General Public License
 *     along with LibLaserCut.  If not, see <http://www.gnu.org/licenses/>.
 **/
package com.t_oster.liblasercut.platform;

/**
 * @author Max Gaukler <development@maxgaukler.de>
 * 
 * (not really compatible) replacement of java.awt.Rectangle,
 * This Rectangle cannot be "empty" - at minimum it needs to have one point.
 *
 * @see Point
 */
public class Rectangle {
  private int x1, x2, y1, y2;

  /**
   * integer interval helper class
   * represents the set { min, min+1, ..., max }
   * 
   * min must be < max
   */
  private class Interval
  {

    private int min,max;

    private Interval(int min, int max)
    {
      this.min = min;
      this.max = max;
      if (min>max) {
        throw new RuntimeException("Interval: min must be < max");
      }
    }

    /**
     * @return true if the other interval is equal or is a subset
     */
    private boolean isSubsetOf(Interval o)
    {
      return o.min <= min && o.max >= max;
    }

    /**
     * @return true if the other interval has at least one element in common with this
     */
    private boolean intersects(Interval o)
    {
      return (o.min >= min && o.min <= max) || (o.max >= min && o.max <= max);
    }

  }

  /**
   * construct a rectangle with the corners (x1,y1) and (x2,y2)
   */
  public Rectangle(int x1, int y1, int x2, int y2)
  {
    this.x1=Math.min(x1,x2);
    this.x2=Math.max(x1,x2);
    this.y1=Math.min(y1,y2);
    this.y2=Math.max(y1,y2);
  }

  /**
   * Construct a rectangle with the corners p1 and p2
   */
  public Rectangle(Point p1, Point p2) {
    this(p1.x,p1.y,p2.x,p2.y);
  }

  /**
   * construct a rectangle with only one point p
   */
  public Rectangle(Point p) {
    this(p,p);
  }


  /**
   * add a point to the boundary of this rectangle
   * use this iteratively to get the boundingBox
   */
  public void add (int x, int y) {
    if (x<x1) {
      this.x1=x;
    } else if (x>x2) {
      this.x2=x;
    }

    if (y<y1) {
      this.y1=y;
    } else if (y>y2) {
      this.y2=y;
    }
  }

  public void add(Point p) {
    if (p != null) {
      add(p.x, p.y);
    }
  }

  /**
   * smallest X coordinate
   * @return int
   */
  public int getXMin() {
    return x1;
  }

  /**
   * greatest X coordinate
   */
  public int getXMax() {
    return x2;
  }

  /**
   * smallest Y coordinate
   */
  public int getYMin() {
    return y1;
  }

  /**
   * greatest Y coordinate
   */
  public int getYMax() {
    return y2;
  }

  /**
   * X interval from left to right
   */
  private Interval getXInterval() {
    return new Interval(x1,x2);
  }

  /**
   * Y interval from top to bottom
   */
  private Interval getYInterval() {
    return new Interval(y1,y2);
  }

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

  @Override
  public Rectangle clone()
  {
    return new Rectangle(x1,y1,x2,y2);
  }

  /**
   * check if this is inside of (or equal) another rectangle
   * @param other
   * @return true if this rectangle is equal to or inside of the other one
   */
  public boolean isInsideOf(Rectangle other) {
    return this.getXInterval().isSubsetOf(other.getXInterval())
                    && this.getYInterval().isSubsetOf(other.getYInterval());
  }

  /**
   * check if the intersection of this rectangle with another one is not empty
   * @param other
   * @return true if rectangles have at least one point in common
   */
  public boolean intersects(Rectangle other) {
    return this.getXInterval().intersects(other.getXInterval())
            && this.getYInterval().intersects(other.getYInterval());
  }
}