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 representation de lineas 
*bi-dimensionales.<strong>
*@author Thomas Genet
*/
class Linea extends Forma
{
/**
* Primero punto de la linea.
*/
private Point a;
/**
* Segundo punto de la linea.
*/
private Point b;
/**
* Contiene el largo de la linea
*/
private double largo;
/**
*Contiene la pendiente de la linea en radianes.
*/
private double pendiente;
/*
* Formato usado para visualizar las informaciones de la linea.
*/
private DecimalFormat miformato = new DecimalFormat("###.###");


/**
* Arreglo de Rectangle2D que contiene los cuadraditos verdes de selección
* de la Linea.
*/
private Rectangle2D[] greenSquare;


/*
* Constructor
* Construye una linea entre los dos puntos dados en parametros.
* @param a Primer extremo de la linea.
* @param b Segundo extremo de la linea.
*/

public Linea (Point a1, Point b1)
{
a = new Point (a1.X, a1.Y);
b = new Point (b1.X, b1.Y);
largo = this.getDistancia();
pendiente = this.getPendiente();
}

/**
* Metodo que permite acceder al primer punto de la linea. 
* @return El primer punto de la linea.
*/
public Point a()
{
return a;
}

/**
* Metodo que permite cambiar el segundo punto de la Linea.
* @param s Segundo punto de la Linea.
*/
public void setSecondPoint(Point s)
{
b.X = s.X;
b.Y = s.Y;
}
/**
* Metodo que permite acceder al segundo punto de la linea. 
* @return El segundo punto de la linea.
*/
public Point b()
{
return b;
}


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

double m, p;
m = (b.Y - a.Y) / (b.X - a.X);
p = a.Y - m * a.X;
return ((punto.Y >= m * punto.X + p - 2) && (punto.Y <= m * punto.X + p + 2));
}

/**
* Metodo que dibuja un cuadradito verde a cada extremidad de la Linea para
* mostrar que esta está seleccionada.
* @param g Graphics donde se dibujan los 2 cuadraditos verdes.
*/
public void select(Graphics g)
{
g.setColor(Color.green);

greenSquare = new Rectangle2D[2];
greenSquare[0] = new Rectangle2D.Double(a.X - 2, a.Y - 2, SIZE_OF_SQUARE,
SIZE_OF_SQUARE);
greenSquare[1] = new Rectangle2D.Double(b.X - 2, b.Y - 2, SIZE_OF_SQUARE,
SIZE_OF_SQUARE);
Graphics2D g2 = (Graphics2D) g;
for (int i = 0; i < 2; i++)
g2.draw(greenSquare[i]);
g.setColor(Color.black);
}


/**
* Metodo que permite saber si el punto dado en parametro pertenece a uno de los
* cuadraditos verdes de seleccion de la Linea. 
* @return True si el punto dado en parametro pertenece a uno de los cuadraditos
* de seleccion de la Linea, False sino.
*/
public boolean isItInAGreenSquare(Point p)
{
 Point2D p2 = new Point2D.Double(p.X, p.Y);
for (int i = 0; i < 2; i++)
if (greenSquare[i].contains(p2))
return true;
return false;
}

/**
* Metodo que permite conocer el largo de la linea.
* @return El largo de la linea.
*/
public double getDistancia()
{
largo = Math.sqrt((a.X - b.X) * (a.X - b.X) + (a.Y - b.Y) * (a.Y - b.Y));
return largo;
}

/**
* Metodo que permite conocer el pendiente de la linea en radianes.
* @return El pendiente de la linea en radianes.
*/
public double getPendiente()
{
if (a.Y == b.Y)
{
  if (a.X < b.X) return -Math.PI / 2;
  if (a.X > b.X) return (Math.PI) / 2;
  else return 0;
}
else return ((Math.signum(b.Y - a.Y) - 1) / 2) * Math.PI
+ Math.signum(a.X - b.X) * Math.signum((b.X - a.X) * (b.Y - a.Y))
* Math.asin((b.X - a.X) / this.getDistancia());
}

/** Escala la linea respecto al punto central en un factor dado.
* @param centro 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 centro, double factor)
{
a.escalar(centro , factor);
b.escalar(centro , factor);
largo = this.getDistancia();
}

/** Traslada la linea desplazandola en sentido X e Y.
* @param deltaX desplazamiento en sentido horizontal.
* @param deltaY desplazamiento en sentido vertical.
*/
public void trasladar(double deltaX, double deltaY)
{
a.X += deltaX;
b.X += deltaX;
a.Y += deltaY;
b.Y += deltaY;
}

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

/**
* Describe la linea en un String.
* @return Una Sring que contiene las informaciones de la linea.
*/
public String toString()
{
String str = new String();
str = "Este es una linea:a=" + a.toString() + ", b=" + b.toString() + ", Largo="
+ miformato.format(this.getDistancia()) + ", Pendiente=" + this.getPendiente();
return str;
}

/**
*Compara la forma dada en parametro con esta linea.
*@param f Forma comparada con esta linea.
*@return True si las dos formas son iguales, False sino.
*/
public boolean equals (Forma f)
{
if (this == f) return true;
if (f == null) return false;
if (getClass() != f.getClass()) return false;
Linea otra = (Linea)f;
return (a.equals(otra.a()) && (b.equals(otra.b())));
}

/**
* Duplica la linea.
* @return una linea identica a esta linea.
*/
public Forma clone()
{
Linea copia = new Linea(a , b);
return copia;
}

/**
* Metodo que dibuja la Linea en el Graphics2D dado en parametro.
* @param g2d Graphics2D donde la Linea se dibuja.
*/
public void paintComponent(Graphics2D g2d)
{
g2d.draw(new Line2D.Double(a.X, a.Y, b.X, b.Y));
}




}
