import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

/**
 * A RectanglePanel can be used to display and edit a Rectangle.
 * 
 * @author  Prof. David Bernstein, James Madison University
 *
 */
public class RectanglePanel extends JPanel 
    implements MouseListener, MouseMotionListener
{
  private static final long serialVersionUID = 1L;

  private int               draggedCorner;
  private Rectangle         rect;
  
  /**
   * Explicit value constructor.
   * 
   * @param rect  The Rectangle to display/edit
   */
  public RectanglePanel(Rectangle rect)
  {
    this.rect = rect;
    addMouseListener(this);
    addMouseMotionListener(this);
  }

  /**
   * Handle mouseClicked messages.
   * 
   * @param e The event that generated the message
   */
  public void mouseClicked(MouseEvent e)
  {
    Point p = e.getPoint();

    if (!rect.isSelected())
    {
      if   (rect.contains(p)) rect.setSelected(true);
      else rect.setSelected(false);

      repaint();
    }
  }

  /**
   * Handle mouseDragged messages.
   * 
   * @param e The event that generated the message
   */
  public void mouseDragged(MouseEvent e)
  {
    if (rect.isSelected())
    {
      Point finish = e.getPoint();

      int xMin = rect.getX();
      int yMin = rect.getY();
      int xMax = xMin + rect.getWidth();
      int yMax = yMin + rect.getHeight();
      
      if (draggedCorner == 0)
      {
        xMin = finish.x;
        yMin = finish.y;
      }
      else if (draggedCorner == 1)
      {
        xMax = finish.x;
        yMin = finish.y;
      }
      else if (draggedCorner == 2)
      {
        xMax = finish.x;
        yMax = finish.y;
      }
      else if (draggedCorner == 3)
      {
        xMin = finish.x;
        yMax = finish.y;
      }
      
      rect.setX(Math.min(xMin, xMax));
      rect.setY(Math.min(yMin, yMax));
      rect.setWidth(Math.abs(xMax - xMin));
      rect.setHeight(Math.abs(yMax - yMin));
      
      repaint();
    }
  }

  /**
   * Handle mouseEntered messages.
   * 
   * @param e The event that generated the message
   */
  public void mouseEntered(MouseEvent e)
  {
  }

  /**
   * Handle mouseExited messages.
   * 
   * @param e The event that generated the message
   */
  public void mouseExited(MouseEvent e)
  {
  }

  /**
   * Handle mouseMoved messages.
   * 
   * @param e The event that generated the message
   */
  public void mouseMoved(MouseEvent e)
  {
  }

  /**
   * Handle mousePressed messages.
   * 
   * @param e The event that generated the message
   */
  public void mousePressed(MouseEvent e)
  {
    if (rect.isSelected())
    {
      Point p = e.getPoint();
      Point[] corners = rect.corners();
      double min = Double.POSITIVE_INFINITY;
      for (int i=0; i<corners.length; i++)
      {
        double d = p.distance(corners[i]);
        if (d < min)
        {
          min = d;
          draggedCorner = i;
        }
      }
    }
  }

  /**
   * Handle mouseReleased messages.
   * 
   * @param e The event that generated the message
   */
  public void mouseReleased(MouseEvent e)
  {
    if (rect.isSelected())
    {
      rect.setSelected(false);
      repaint();
    }
  }

  /**
   * Render this component.
   * 
   * @param g  The rendering engine to use
   */
  public void paint(Graphics g)
  {
    super.paint(g);
    rect.paint(g);
  }
}
