import java.awt.*;
import java.awt.event.*;
import java.util.*;


public class SensitivePolygon 
    extends Polygon 
    implements MouseMotionListener, MouseListener
{
    boolean isActive;
    Vector listeners;
    protected Color fillColor;
    protected Color lineColor;
    protected Color fillColorInside;
    protected Color lineColorInside;

    protected Component canvas;
    private   Graphics  cacheGraphics;

    /**
     * Create this sensitive polygon, with 0 points.
     * and default colors.
     */
    public SensitivePolygon(Component myCanvas) {
	super();
	isActive = false;
	listeners = new Vector();
	fillColor = Color.cyan;
	lineColor = Color.gray;
	fillColorInside = Color.blue;
	lineColorInside = Color.black;

	canvas = myCanvas;
	cacheGraphics = null;

	canvas.addMouseListener(this);
	canvas.addMouseMotionListener(this);
    }

    protected Graphics getGraphics() {
	if (cacheGraphics == null) {
	    if (canvas != null) {
		cacheGraphics = canvas.getGraphics();
	    }
	}
	return cacheGraphics;
    }

    /**
     * Add a mouse listener to this sensitive polygon. 
     */
    public synchronized void addMouseListener(MouseListener m) {
	listeners.addElement(m);
    }

    public synchronized void removeMouseListener(MouseListener m) {
	listeners.removeElement(m);
    }



    // ************************************************************
    public void mouseClicked(MouseEvent e) { 
	if (isActive) notifyListeners(MouseEvent.MOUSE_CLICKED, e);
    }
    public void mousePressed(MouseEvent e) {
	if (isActive) notifyListeners(MouseEvent.MOUSE_PRESSED, e);
    }
    public void mouseReleased(MouseEvent e) {
	if (isActive) notifyListeners(MouseEvent.MOUSE_RELEASED, e);
    }
    public void mouseEntered(MouseEvent e) { 
	boolean prev = isActive;
	processPoint(e.getPoint()); 
	if (isActive && !prev) 
	    notifyListeners(MouseEvent.MOUSE_ENTERED, e);
    }
    public void mouseExited(MouseEvent e) { 
	boolean prev = isActive;
	processPoint(e.getPoint()); 
	if (!isActive && prev) 
	    notifyListeners(MouseEvent.MOUSE_EXITED, e);
    }
    public void mouseDragged(MouseEvent e) { 
	boolean prev = isActive;
	processPoint(e.getPoint()); 
	if (!isActive && prev) 
	    notifyListeners(MouseEvent.MOUSE_EXITED, e);
	if (isActive && !prev) 
	    notifyListeners(MouseEvent.MOUSE_ENTERED, e);
    }
    public void mouseMoved(MouseEvent e) { 
	boolean prev = isActive;
	processPoint(e.getPoint()); 
	if (!isActive && prev) 
	    notifyListeners(MouseEvent.MOUSE_EXITED, e);
	if (isActive && !prev) 
	    notifyListeners(MouseEvent.MOUSE_ENTERED, e);
    }

    public void paint(Graphics g) {
	if (g != null) {
	    synchronized(g) {
		Color fi = ((isActive)?(fillColorInside):(fillColor));
		Color li = ((isActive)?(lineColorInside):(lineColor));
		if (fi != null) {
		    g.setColor(fi);
		    g.fillPolygon(this);
		}
		if (li != null) {
		    g.setColor(li);
		    g.drawPolygon(this);
		}
	    }
	}
	return;
    }

    protected void processPoint(Point pt) {
	if (npoints < 3) {
	    isActive = false;
	    return;
	}
	if (contains(pt)) {
	    if (!isActive) {
		// state change, possibly do redraw as activated
		isActive = true;
		paint(getGraphics());
	    }
	}
	else {
	    if (isActive) {
		// state change, possibly do redraw as at rest
		isActive = false;
		paint(getGraphics());
	    }
	}
    }

    protected void notifyListeners(int id, MouseEvent evt) {
	MouseListener m;
	for(Enumeration e = listeners.elements(); e.hasMoreElements(); ) {
	    m = (MouseListener)(e.nextElement());
	    switch (id) {
	    case MouseEvent.MOUSE_PRESSED:
		m.mousePressed(evt);
		break;
	    case MouseEvent.MOUSE_RELEASED:
		m.mouseReleased(evt);
		break;
	    case MouseEvent.MOUSE_ENTERED:
		m.mouseEntered(evt);
		break;
	    case MouseEvent.MOUSE_EXITED:
		m.mouseExited(evt);
		break;
	    case MouseEvent.MOUSE_CLICKED:
		m.mouseClicked(evt);
		break;
	    default:
		break;
	    }
	}
	return;
    }

    /**
     * Set the fill color for the polygon when it is at rest.
     */
    public void setFillColor(Color c) { fillColor = c; }

    /**
     * Get the fill color for the polygon when it is at rest.
     */
    public Color getFillColor() { return fillColor; }

    /**
     * Set the outline color for the polygon when it is at rest.
     */
    public void setLineColor(Color c) { lineColor = c; }

    /**
     * Get the outline color for the polygon when it is at rest.
     */
    public Color getLineColor() { return lineColor; }

    /**
     * Set the fill color for the polygon when it is activated.
     */
    public void setFillColorActive(Color c) { fillColorInside = c; }

    /**
     * Get the fill color for the polygon when it is activated.
     */
    public Color getFillColorActive() { return fillColorInside; }

    /**
     * Set the outline color for the polygon when it is activated.
     */
    public void setLineColorActive(Color c) { lineColorInside = c; }

    /**
     * Get the outline color for the polygon when it is activated.
     */
    public Color getLineColorActive() { return lineColorInside; }




    static SensitivePolygon sp1, sp2, sp3;

    public static void main(String [] args) {
	Frame f;
	Canvas c;

	f = new Frame("SensitivePolygon Test");
	c = new Canvas() {
		public void paint(Graphics g) {
		    super.paint(g);
		    sp1.paint(g);
		    sp2.paint(g);
		}
	    };
	c.setBackground(Color.pink);
	c.setSize(300,300);
	f.add(c);
	f.pack();
	f.addWindowListener(new WindowAdapter() {
		public void windowClosing(WindowEvent e) {
		    System.exit(0);
		}
	    });

	sp1 = new SensitivePolygon(c);
	sp1.addPoint(20,30);
	sp1.addPoint(60,35);
	sp1.addPoint(120,130);
	sp1.addPoint(20,133);
	sp1.addPoint(20,30);

	sp2 = new SensitivePolygon(c);
	sp2.addPoint(200,200);
	sp2.addPoint(260,200);
	sp2.addPoint(260,240);
	sp2.addPoint(200,240);
	sp2.addPoint(200,200);
	sp2.setFillColor(Color.red);
	sp2.setLineColor(Color.black);

	sp3 = new SensitivePolygon(c);
	sp3.addPoint(0,220);
	sp3.addPoint(100,220);
	sp3.addPoint(0,290);
	sp3.addPoint(0,220);
	sp3.setFillColor(null);
	sp3.setFillColorActive(null);
	sp3.setLineColor(Color.pink);
	sp3.setLineColorActive(Color.green);

	sp2.addMouseListener(new MouseAdapter() {
		public void mouseEntered(MouseEvent e) {
		    System.out.println("sp2 entered");
		}
		public void mouseExited(MouseEvent e) {
		    System.out.println("sp2 exited");
		}
		public void mousePressed(MouseEvent e) {
		    System.out.println("sp2 pressed");
		}
		public void mouseReleased(MouseEvent e) {
		    System.out.println("sp2 released");
		}
	    });
	sp1.addMouseListener(new MouseAdapter() {
		public void mouseEntered(MouseEvent e) {
		    System.out.println("sp1 entered");
		}
		public void mouseExited(MouseEvent e) {
		    System.out.println("sp1 exited");
		}
		public void mousePressed(MouseEvent e) {
		    System.out.println("sp1 pressed");
		}
		public void mouseReleased(MouseEvent e) {
		    System.out.println("sp1 released");
		}
	    });

	f.show();
    }
}
