/*
  GooglyEyes.java - shows googly eyes over an image of your choosing.

  Copyright (C) 1998-2005  David N. Welton <davidw@dedasys.com>

  This program is free software; you can redistribute it and/or
  modify it under the terms of the GNU General Public License as
  published by the Free Software Foundation; either version 2 of the
  License, or (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  General Public License for more details.
*/
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.applet.Applet;

/* How to use this to create your own googly-eyed applets:

<applet code="GooglyEyes.class" width="400" height="411">
  <param name="imagefile" value="billg.jpg"/>
  <param name="lefteyex" value="94"/>
  <param name="lefteyey" value="138"/>

  <param name="righteyex" value="156"/>
  <param name="righteyey" value="140"/>

  <param name="radius" value="22">
</applet>

Use a program like The Gimp to find the left and right eye coordinates
and add them as parameters to the applet.

If you use this code, it would be nice if you link back to my page on http://www.welton.it
*/


/**
 * <code>ImageCanvas</code> - the meat of the applet.
 *
 * @author <a href="mailto:davidw@dedasys.com">David N. Welton</a>
 * @version 1.0
 */
class ImageCanvas extends Canvas implements MouseMotionListener {
    Point point = null;
    Container container;
    Image image;
    boolean trueSizeKnown = false;
    Dimension minSize;
    int w, h;
    private int lastx = 0;
    private int lasty = 0;

    /* These are set by parameters to the applet. */
    private int LEFTEYEx = 0;
    private int LEFTEYEy = 0;

    private int RIGHTEYEx = 0;
    private int RIGHTEYEy = 0;

    private int EYEWIDTH = 10;
    private int HALFWIDTH = EYEWIDTH / 2;

    /* As is RADIUS */
    private int RADIUS = 25;
    private int diam = RADIUS * 2;

    /**
     * Creates a new <code>ImageCanvas</code> instance.
     *
     * @param image an <code>Image</code> value
     * @param parent a <code>Container</code> value
     * @param initialWidth an <code>int</code> value
     * @param initialHeight an <code>int</code> value
     */
    public ImageCanvas(Image image, Container parent, int initialWidth, int initialHeight) {

        if (image == null) {
            System.err.println("Canvas got invalid image object!");
            return;
        }

        this.image = image;
        container = parent;

        w = initialWidth;
        h = initialHeight;

        minSize = new Dimension(w,h);
	this.addMouseMotionListener(this);
    }

    /**
     * <code>setParams</code> attempts to set up the parameters from
     * values given in the HTML referencing this applet.  If values
     * are not defined, defaults are set up in the paint method, when
     * the image has been posted to the screen.
     *
     * @param slefteyex a <code>String</code> value
     * @param slefteyey a <code>String</code> value
     * @param srighteyex a <code>String</code> value
     * @param srighteyey a <code>String</code> value
     * @param sradius a <code>String</code> value
     */
    public void setParams (String slefteyex, String slefteyey,
			     String srighteyex, String srighteyey,
			     String sradius) {
	try {
	    LEFTEYEx = Integer.parseInt(slefteyex);
	} catch (NumberFormatException e) {
	    LEFTEYEx = -1;
	}

	try {
	    LEFTEYEy = Integer.parseInt(slefteyey);
	} catch (NumberFormatException e) {
	    LEFTEYEy = -1;
	}

	try {
	    RIGHTEYEx = Integer.parseInt(srighteyex);
	} catch (NumberFormatException e) {
	    RIGHTEYEx = -1;
	}

	try {
	    RIGHTEYEy = Integer.parseInt(srighteyey);
	} catch (NumberFormatException e) {
	    RIGHTEYEy = -1;
	}

	try {
	    RADIUS = Integer.parseInt(sradius);
	    diam = RADIUS * 2;
	} catch (NumberFormatException e) {
	    /* Do nothing - the defaults are fine. */
	}
    }

    public Dimension getPreferredSize() {
        return getMinimumSize();
    }

    public synchronized Dimension getMinimumSize() {
        return minSize;
    }

    public void mouseDragged(MouseEvent e) {
    }


    /**
     * The <code>mouseMoved</code> method sets up a drawing of the
     * eyes according to the mouse movements.
     *
     * @param e a <code>MouseEvent</code> value
     */
    public void mouseMoved(MouseEvent e) {
	int x = e.getX();
	int y = e.getY();
	drawEyes(x, y);
    }

    /**
     * The <code>drawEyes</code> method is where the eyes are actually
     * drawn.
     *
     * @param x an <code>int</code> value
     * @param y an <code>int</code> value
     */
    public void drawEyes(int x, int y) {
	Color col1 = new Color(255,255,255);
	Color col2 = new Color(0,0,0);
	int cent1x = LEFTEYEx - HALFWIDTH;
	int cent1y = LEFTEYEy - HALFWIDTH;
	int cent2x = RIGHTEYEx - HALFWIDTH;
	int cent2y = RIGHTEYEy - HALFWIDTH;
	double xratio1 = 0;
	double xratio2 = 0;
	double yratio1 = 0;
	double yratio2 = 0;
	double hyp1 = 0 ;
	double hyp2 = 0 ;
	int innerradius = RADIUS - HALFWIDTH;

	if(point == null) {
	    point = new Point (x,y);
	} else {
	    point.x = x;
	    point.y = y;
	}
	Graphics g = getGraphics();

	g.setColor(col1);
 	g.fillOval(LEFTEYEx - RADIUS , LEFTEYEy - RADIUS, diam, diam);
	g.fillOval(RIGHTEYEx - RADIUS, RIGHTEYEy - RADIUS, diam, diam);

	g.setColor(col2);
 	g.drawOval(LEFTEYEx - RADIUS, LEFTEYEy - RADIUS, diam, diam);
	g.drawOval(RIGHTEYEx - RADIUS, RIGHTEYEy - RADIUS, diam, diam);

	/* The actual work of figuring out where the eyes go, and drawing them. */
	hyp1 = Math.sqrt((x - cent1x)*(x - cent1x) + (y - cent1y)*(y - cent1y));
	hyp2 = Math.sqrt((x - cent2x)*(x - cent2x) + (y - cent2y)*(y - cent2y));
	xratio1 = (x - cent1x) / hyp1;
	xratio2 = (x - cent2x) /hyp2;
	yratio1 = (y - cent1y) /hyp1;
	yratio2 = (y - cent2y) /hyp2;

	if (hyp1 > innerradius) {
	    g.fillOval( (int)(xratio1 * innerradius) + cent1x,
			(int)(yratio1 * innerradius) + cent1y, EYEWIDTH, EYEWIDTH);
	} else {
	    g.fillOval( (x - cent1x) + cent1x, (y - cent1y) + cent1y, EYEWIDTH, EYEWIDTH);
	}

	if (hyp2 > innerradius) {
	    g.fillOval( (int)(xratio2 * innerradius) + cent2x,
			(int)(yratio2 * innerradius) + cent2y, EYEWIDTH, EYEWIDTH);
	} else {
	    g.fillOval( (x - cent2x) + cent2x, (y - cent2y) + cent2y, EYEWIDTH, EYEWIDTH);
	}
    }

    /**
     * The <code>paint</code> method takes care of drawing things on
     * the screen.
     *
     * @param g a <code>Graphics</code> value
     */
    public void paint (Graphics g) {
        if (image != null) {
            if (!trueSizeKnown) {
                int imageWidth = image.getWidth(this);
                int imageHeight = image.getHeight(this);

                if ((imageWidth > 0) && (imageHeight > 0)) {
                    trueSizeKnown = true;

		    /* Set up some defaults, that should place the
		     * eyes in a reasonable location on many
		     * photos. */
		    if (LEFTEYEx < 0) {
			LEFTEYEx = imageWidth / 3;
		    }
		    if (LEFTEYEy < 0) {
			LEFTEYEy = imageHeight / 3;
		    }
		    if (RIGHTEYEx < 0) {
			RIGHTEYEx = (imageWidth * 2) / 3;
		    }
		    if (RIGHTEYEy < 0) {
			RIGHTEYEy = imageHeight / 3;
		    }

                    w = imageWidth;
                    h = imageHeight;
                    minSize = new Dimension(w,h);
                    setSize(w, h);
                    container.validate();
                }
            }

            g.drawImage(image, 0, 0, this);
	    /* Draw the eyes the first time. */
	    drawEyes((LEFTEYEx + RIGHTEYEx) / 2,
		     (LEFTEYEy + RIGHTEYEy) / 2);
        }
	container.repaint();
    }
}

/**
 * <code>GooglyEyes</code> is the main applet class, which doesn't do
 * much more than set up the canvas.
 *
 * @author <a href="mailto:davidw@dedasys.com">David N. Welton</a>
 * @version 1.0
 */
public class GooglyEyes extends Applet {
    ImageCanvas ic = null;

    public void start() {
    }

    public void init() {
	String slex = getParameter("LEFTEYEX");
	String sley = getParameter("LEFTEYEY");

	String srex = getParameter("RIGHTEYEX");
	String srey = getParameter("RIGHTEYEY");

	String sradius = getParameter("RADIUS");
	String imagefile = getParameter("IMAGEFILE");

        Image image1 = getImage(getCodeBase(), imagefile);

        ic = new ImageCanvas(image1, this, 400, 411);
	ic.setParams(slex, sley, srex, srey, sradius);
        add(ic);
        validate();
    }
}

