import java.awt.event.*;
import java.awt.*;

/**
* <strong> Clase que implementa el ActionListener para
* el escalamiento de Figuras Geométricas.<strong>
*/
public class SizeHandler implements ActionListener
{
  private Dibujo dibujo;
/**
* Punto respecto del cual se hace el escalamiento, el utilisador lo fija al
* presionar el Mouse en la pantalla después de haber seleccionado Manipular
* Escalar en el Menu.
*/
  private Point ancla;
/**
* Es la distancia entre el ancla y el punto donde el utilisador presiona
* el Mouse después de haber fijado el ancla.
*/
  private double largoReferencia;
/**
* Cruz que aparece al lugar donde se fija el ancla.
*/
  private Cruz cruz;
 /**
 * estado permite saber a que nivel del escalamiento estamos.
 * estado == INICI0_NUEVO_ESCALAMIENTO : el utilisador seleccionó Escalar en
 * el Menu Manipular pero no presionó el Mouse sobre la pantalla todavía.
 * estado == ANCLA_FIJADA : el utilisador presionó el Mouse sobre la pantalla
 * y fijó el ancla, pero no presionó el Mouse otra vez para definir
 * largoReferencia.
 * estado == TERMINO_ESCALAMIENTO : el utilisador definó largoReferencia al
 * presionar el mouse una secunda vez y está "drageando" el Mouse para
 * definir el factor de escalamiento.
 */
  private int estado;
  private static final int INICIO_NUEVO_ESCALAMIENTO = 0;
  private static final int ANCLA_FIJADA = 1;
  private static final int TERMINO_ESCALAMIENTO = 2;
  
/**
* Construye un SizeHandler que permite actuar sobre el
* Dibujo dado en parametro.
* @param dib Dibujo sobre lo cual SizeHandler va a actuar.
*/
 public SizeHandler(Dibujo dib)
    {
      dibujo = dib;
      cruz = new Cruz();
    }
 
/**
* Metodo que cambia los MouseListener y MouseMotionListener asociados al
* Dibujo cuando el utilisador executa un acción.
* Los nuevos MouseListener y MouseMotionListener asociados al dibujo son
* respectivamente, después del llamado a este metodo, MouseHandler y
* MouseMotionHandler, clases internas a SizeHandler.
* Después del llamado a este metodo estado == INICIO_NUEVO_ESCALAMIENTO.
* @param e ActionEvent que produzcó el llamado a este metodo.
*/ 
 public void actionPerformed(ActionEvent e)
    {
      dibujo.changeMouseListener(new MouseHandler());
      dibujo.changeMouseMotionListener(new MouseMotionHandler());
      estado = INICIO_NUEVO_ESCALAMIENTO;
    }
  
/**
* Clase que maneja los eventos del Mouse después que el utilisador
* haya seleccionado Manipular Escalar en el menu.  
*/
class MouseHandler extends MouseAdapter
  {
  
 /**
* Cuando el utilisador hace clic con el Mouse en la pantalla después de haber
* seleccionado Manipular Escalar en el Menu, se graba las coordenadas del
* punto como las del ancla del escalamiento y se dibuja una cruz en este
* lugar. Despues del llamado a este metodo estado == ANCLA_FIJADA.
* @param event Evento que produzcó el llamado a este metodo.
*/
    public void mouseClicked(MouseEvent event)
      {
        if (estado == INICIO_NUEVO_ESCALAMIENTO)
        {
          ancla = new Point(event.getPoint());
          dibujo.remueva(cruz);
          cruz.setPoint(ancla);
          dibujo.incorpore(cruz);
          estado = ANCLA_FIJADA;
        }
      }
    
/*
* Cuando el utilisador presiona el Mouse después de haber fijado el ancla, se
* mide la distancia entre el ancla y la posición del Mouse para definir
* largoDistancia. Si ya se definó largoReferencia y el factor de escalamiento
* (estado == TERMINO_ESCALAMIENTO) el estado se vuelve igual a 
* INICIO_NUEVO_ESCALAMIENTO. 
* @param event Evento que produzcó el llamado a este metodo.
*/
public void mousePressed (MouseEvent event)
      {
        if (estado == ANCLA_FIJADA)
        {
          Point p = new Point(event.getPoint());
          double x = p.X - ancla.X;
          double y = p.Y - ancla.Y;
          largoReferencia = Math.sqrt(x * x + y * y);
        }
        if (estado == TERMINO_ESCALAMIENTO)
            estado = INICIO_NUEVO_ESCALAMIENTO;
      }

/**
* Cuando el utilisador deja de presionar el Mouse después de haber
* definido el factor de escalamiento, se remueva la cruz y estado se vuelve
* igual a TERMINO_ESCALAMIENTO. 
* @param event Evento que produzcó el llamado a este metodo.
*/ 
    public void mouseReleased(MouseEvent event)
      {
        if (estado == ANCLA_FIJADA)
        {
          dibujo.remueva(cruz);
          estado = TERMINO_ESCALAMIENTO;
        }
      }
  }
/**
* Clase que maneja los eventos de Movimiento del Mouse después que el
* utilisador haya seleccionado Manipular Escalar en el menu.  
*/ 
  class MouseMotionHandler extends MouseMotionAdapter
  {
/**
* Cuando el utilisador "drag" el Mouse, el factor de escalamiento se vuelve
* igual a la distancia del Mouse al ancla dividida por el largoReferencia. Se
* escala la Figura, tras largoReferencia se vuelve igual a la distancia del
*  Mouse al ancla.
* @param event Evento del Mouse que produzcó el llamado a este metodo.
*/  
  public void mouseDragged(MouseEvent event)
      {
        if (estado == ANCLA_FIJADA)
        {
          Point p = new Point(event.getPoint());
          double x = p.X - ancla.X;
          double y = p.Y - ancla.Y;
          double distanciaAlAncla = Math.sqrt(x * x + y * y);
          double factorEscala = distanciaAlAncla / largoReferencia;
          dibujo.escalar(ancla, factorEscala);
          largoReferencia = distanciaAlAncla;
        }
      }
  }

}

