import java.awt.*;
import java.awt.geom.*;
import java.lang.Math;
import java.util.*;
import java.lang.*;
import java.text.*;

/**
* <strong>Clase que Implementa la representacion de un rectangulo 
* bi-dimensional.<strong>
* @author Thomas Genet
*/
class Rectangulo extends Forma
{
/**
*Contiene el ancho del rectangulo.
*/
private double ancho;
/**
*Contiene el alto del rectangulo.
*/
private double alto;
/**
*Contiene la inclinacion del rectangulo.
*/
private double inclinacion;
/**
*Contiene el punto central del rectangulo.
*/
private Point centro = new Point(0, 0);
/**
* Contiene las cuatro esquinas del Rectangulo.
*/
private Point[] corner;
private static final int NUMBER_OF_CORNER = 4;

/**
* Index de la primera esquina en el arreglo corner.
*/
private static final int PRIMERA_ESQUINA = 0;
/**
* Index de la secunda esquina en el arreglo corner.
*/
private static final int SECUNDA_ESQUINA = 1;
/**
* Index de la tercera esquina en el arreglo corner.
*/
private static final int TERCERA_ESQUINA = 2;
/**
* Index de la cuarta esquina en el arreglo corner.
*/
private static final int CUARTA_ESQUINA = 3;

private static final int NUMBER_OF_SIDE = 4;
/**
* Arreglo de Rectangle2D que contiene los cuadraditos verdes de selección del
* Rectangulo.
*/
private Rectangle2D[] greenSquare;
/*
* Formato usado para visualizar las coordenadas del centro en el metodo
* toString.
*/
private DecimalFormat miformato = new DecimalFormat("###.###");

/**
* Construye un Rectangulo con el Ancho y el Alto especificado,
* su primera esquina (arriba izquierda) esta en (0;0).
* @param w Ancho del rectangulo.
* @param h Alto del rectangulo.
*/
public Rectangulo (double w, double h)
{
 corner = new Point[NUMBER_OF_CORNER];
 corner[PRIMERA_ESQUINA] = new Point(0, 0);
 corner[SECUNDA_ESQUINA] = new Point(0, h);
 corner[TERCERA_ESQUINA] = new Point(w, h);
 corner[CUARTA_ESQUINA] = new Point(w, 0);
 ancho = w;
 alto = h;
 inclinacion = 0;
}

/**
* Metodo que permite saber si el punto dado en parametro pertenece a uno de los
* cuadraditos de seleccion delRectangulo.
* @return True si el punto dado en parametro pertenece a uno de los cuadraditos
* de seleccion del Rectangulo, False sino.
*/
public boolean isItInAGreenSquare(Point p)
{
Point2D p2 = new Point2D.Double(p.X, p.Y);
for (int i = 0; i < corner.length; i++)
if (greenSquare[i].contains(p2))
return true;
return false;
}
/**
* Construye un Rectangulo con el Ancho y el Alto especificado,
* su primera esquina (arriba izquierda) esta en el punto dado en parametro.
* @param p Punto donde se ubiqua la primera esquina del Rectangulo.
* @param w Ancho del rectangulo.
* @param h Alto del rectangulo.
*/
public Rectangulo (Point p, double w, double h)
    {
    corner = new Point[NUMBER_OF_CORNER];
    corner[PRIMERA_ESQUINA] = new Point(p.X, p.Y);
    corner[SECUNDA_ESQUINA] = new Point(p.X, p.Y + h);
    corner[TERCERA_ESQUINA] = new Point(p.X + w, p.Y + h);
    corner[CUARTA_ESQUINA] = new Point(p.X + w, p.Y);
    ancho = w;
    alto = h;
    inclinacion = 0;
    }


/**
* Metodo que dibuja un cuadradito a cada esquina del Rectangulo para mostrar
* que este está seleccionado.
* @param g Graphics donde se dibujan los 4 cuadraditos.
*/
public void select (Graphics g)
{
greenSquare = new Rectangle2D[NUMBER_OF_CORNER];
g.setColor(Color.green);
Graphics2D g2 = (Graphics2D)g;
 for (int i = 0; i < corner.length; i++)
   {
   greenSquare[i] = new Rectangle2D.Double(corner[i].X - 2,
   corner[i].Y - 2, SIZE_OF_SQUARE, SIZE_OF_SQUARE);
   g2.draw(greenSquare[i]);
   }
g.setColor(Color.black);
}

/**
* Metodo que permite saber si el punto dado en parametro pertenece
* al Rectangulo.
* @param punto Punto cuya coordenadas son revisadas para comprobar si 
* pertenecen o no al Rectangulo.
* @return True si punto hace parte del Rectangulo, False sino.
*/
public boolean isSelected(Point punto)
{


Linea[] linea;
linea = new Linea[NUMBER_OF_SIDE];
for (int i = 0; i < linea.length; i++)
 { 
  linea[i] = new Linea(corner[i], corner[(i + 1) % corner.length]);
  if (linea[i].isSelected(punto)) return true;
 }
 
return false;
}

/**
* Metodo que dibuja el Rectangulo en el Graphics2D dado en parametro.
* @param g2d Graphics2D donde el Rectangulo se dibuja.
*/
  public void paintComponent(Graphics2D g2d)
    {
     for (int i = 0; i < corner.length; i++)
     g2d.draw(new Line2D.Double(corner[i].X, corner[i].Y,
     corner[(i + 1) % corner.length].X, corner[(i + 1) % corner.length].Y));
    }

/**
* Metodo que permite cambiar las coordenadas de la tercera esquina del
* Rectangulo.
* @param p Tercera esquina del Rectangulo.
*/
  public void setThirdCorner(Point p)
    {
    corner[TERCERA_ESQUINA] = new Point(p.X, p.Y);
    corner[SECUNDA_ESQUINA].X = corner[PRIMERA_ESQUINA].X;
    corner[SECUNDA_ESQUINA].Y = corner[TERCERA_ESQUINA].Y;
    corner[CUARTA_ESQUINA].X = corner[TERCERA_ESQUINA].X;
    corner[CUARTA_ESQUINA].Y = corner[PRIMERA_ESQUINA].Y;
    }

/**
* Metodo que permite acceder a la inclinacion del rectangulo.
* @return la inclinacion del rectangulo.
*/
double inclinacion()
{
return inclinacion;
}

/**
* Metodo que permite acceder al ancho del rectangulo.
* @return el ancho del rectangulo.
*/
double ancho()
{
return ancho;
}

/**
* Metodo que permite acceder al alto del rectangulo.
* @return el alto del rectangulo.
*/
double alto()
{
return alto;
} 

/**
*Metodo que permite acceder al punto central del rectangulo.
*@return el punto central del rectangulo.
*/
Point centro()
{
return centro;
}


/** Escala el rectangulo respecto al punto c en un factor dado.
* @param c Punto respecto del cual se hace el escalamiento.
* @param factor Factor usado en el escalamiento. >1 corresponde a amplificación,
*<1 corresponde a reducción.
*/

public void escalar (Point c, double factor)
{
centro.escalar(c , factor);
for (int i = 0; i < corner.length; i++)
corner[i].escalar(c, factor);
ancho = ancho * factor;
alto = alto * factor;
}

/** Traslada el rectangulo desplazandolo en sentido X e Y.
* @param deltaX desplazamiento en sentido horizontal.
* @param deltaY desplazamiento en sentido vertical.
*/
public void trasladar(double deltaX, double deltaY)
{
centro.X += deltaX;
centro.Y += deltaY;
for (int i = 0; i < corner.length; i++)
 {
 corner[i].X += deltaX;
 corner[i].Y += deltaY;
 }
}

/** Rota el rectangulo respecto al punto c en un ángulo dado.
* @param c Punto respecto del cual se hace la rotación.
* @param deltaAngulo ángulo de rotación en radianes.
*/
public void rotar(Point c, double deltaAngulo)
{
centro.rotar(c , deltaAngulo);

for (int i = 0; i < corner.length; i++)
corner[i].rotar(c, deltaAngulo);

this.inclinacion += deltaAngulo;
while (this.inclinacion > 2 * Math.PI) inclinacion -= 2 * Math.PI;
}

/**
* Describe el rectangulo en un String.
* @return una string segun el formato:"Este es un Rectangulo:
* Centro("+centro.X+";"+centro.Y+"), Ancho = "+ancho+", Alto = "+alto +",
* Inclinacion = "+inclinacion().
*/
public String toString()
{
String str = new String();
str = "Este es un Rectangulo:Centro" + centro.toString() + ", Ancho = "
+ ancho + ", Alto = " + alto + ", Inclinacion = " + this.inclinacion();
return str;
}

/**
* Compara la forma dada en parametro con el Rectangulo.
* @param f Forma comparada con el rectangulo.
* @return True si la forma es un rectangulo identico al rectangulo pendiente,
* False sino.
*/
public boolean equals (Forma f)
{
if (this == f) return true;
if (f == null) return false;
if (getClass() != f.getClass()) return false;
Rectangulo otro = (Rectangulo)f;
return ((ancho == otro.ancho()) && (alto == otro.alto())
&& (centro.equals(otro.centro())) && (inclinacion == otro.inclinacion));
}

/**
* Duplica el Rectangulo.
* @return Un rectangulo identico al rectangulo pendiente.
*/
public Forma clone()
{
Rectangulo copia = new Rectangulo(ancho , alto);
copia.centro = centro.clone();
copia.inclinacion = this.inclinacion();
return copia;
}

}
