//********************************************************
// KissMe.java 
// Made by John Eriksson 1997  
//
// john_eriksson_sw@hotmail.com
// 
// This code is free to use and modify!!!
//
// HAPPY HACKING!
//********************************************************

//--------------------------------------------------------
// IMPORTS
//--------------------------------------------------------
import java.applet.*;
import java.awt.*;

//========================================================
// KissMe Class
//========================================================
public class KissMe extends Applet implements Trigger 
{
String s_face;    
String s_lips;
String s_sound;

Image face;
Image lips;

int lips_y=0;
int lips_x=0;
int lips_w=0;
int lips_h=0;
int lips_delay=0;

boolean lips_on=false;

boolean loading_gfx=true;

Graphics g_buffer;
Image    i_buffer;

static AudioClip sound;

Ticker ticker=null;

//--------------------------------------------------------
// INIT - Get parameter, load sound.
//--------------------------------------------------------
public void init() 
{

   //*** Get the parameters.
   String att = getParameter("face");
   s_face = (att == null) ? "face.jpg" : att;
   att = getParameter("lips");
   s_lips = (att == null) ? "lips.gif" : att;
   att = getParameter("sound");
   s_sound = (att == null) ? "kiss.au" : att;
   att = getParameter("delay");
   lips_delay = (att == null) ? 0 : (Integer.valueOf(att).intValue());
 
   //*** Get soundclip.
   sound= getAudioClip(getCodeBase(), s_sound);
}


//--------------------------------------------------------
// LOAD_GFX - Load the graphics
//--------------------------------------------------------
public void load_gfx()
{
   //*** Load the images.
   lips = getImage(getCodeBase(),s_lips);
   face = getImage(getCodeBase(),s_face);

   //*** Make sure the images are loaded before we continue.
   MediaTracker tracker = new MediaTracker(this);
   tracker.addImage(face,7);
   tracker.addImage(lips,8);
   try {
      tracker.waitForAll();
   }
   catch(InterruptedException ex){}

   //*** Create the doublebuffer.
   int w=face.getWidth(this);
   int h=face.getHeight(this);
   i_buffer=createImage(w,h);
   g_buffer=i_buffer.getGraphics();

   //*** Get size of the lips-image.
   lips_w=lips.getWidth(this);
   lips_h=lips.getHeight(this);
   loading_gfx=false;
   repaint();
}

//--------------------------------------------------------
// UPDATE - Overides the standard update to avoid flicker
//--------------------------------------------------------
public void update (Graphics g)
{
   //*** Just call paint.
   paint(g);
}

//--------------------------------------------------------
// PAINT - Draw graphics on screen.
//         Uses separate buffer to avoid flicker. 
//--------------------------------------------------------
public void paint(Graphics g) 
{

   if(loading_gfx) {
      g.drawString("Loading images...",10,20);
      load_gfx();
   }
   else {
      //*** Draw face-image to the doublebuffer.
      g_buffer.drawImage(face,0,0,this);

      //*** Draw lips-image to teh doublebuffer.
      if(lips_on)
         g_buffer.drawImage(lips,lips_x,lips_y,this);

      //*** Display the doublebuffer.
      g.drawImage(i_buffer,0,0,this);
   }
}

//--------------------------------------------------------
// MOUSEEXIT - If the lips-image is not removed by the
//             timer. It will be removed when mouse exits
//             applet.
//--------------------------------------------------------
public boolean mouseExit (Event e, int x, int y)
{
   //*** Remove lips if dalay isn't used.
   if(lips_delay<=0) {
      lips_on=false;
      repaint();
   }
   return(true);
}

//--------------------------------------------------------
// MOUSEDOWN - Lets kiss :o) and make some sound.
//--------------------------------------------------------
public boolean mouseDown (Event e, int x, int y)
{

   //*** PLay sound if any.
   if(sound!=null)
      sound.play();

   //*** Stop the ticker object if it's runing.
   if(ticker!=null) {  
      ticker.stop();
      ticker=null;
   }

   //*** Create a new ticker object if delay > 0.
   if(lips_delay>0)
      ticker=new Ticker(lips_delay,this);

   //*** Setup lips-image to be painted.
   lips_on=true;
   lips_x=x-(lips_w/2);
   lips_y=y-(lips_h/2);
   repaint();

   return(true);
}

//--------------------------------------------------------
// TICK - Called by Trigger object when it's time.
//--------------------------------------------------------
public void tick() 
{
   //*** Turn of lips-image
   lips_on=false;
   repaint();
   if(ticker!=null) {  
      ticker.stop();
      ticker=null;
   }
}
}

//========================================================
// Trigger Interface
//========================================================
interface Trigger 
{
   public abstract void tick();
}

//========================================================
// Ticker Class
//========================================================
class Ticker extends Thread 
{
public int period; //milli seconds
protected Trigger trigger;

//--------------------------------------------------------
// TICKER - Called when creating a new Ticker object.
//--------------------------------------------------------
public Ticker (int period, Trigger trigger) 
{
   //*** Init ticker object and start it.
   this.period = period;
   this.trigger = trigger;
   this.start();
}

//--------------------------------------------------------
// RUN - Main loop of ticker.
//--------------------------------------------------------
public void run() 
{
   for(;;) {
      try {
         //*** Sleep until we should wake up.
         sleep(period);
      } 
      catch (InterruptedException e) {
         System.err.println("Ticker thread interrupted: " + e);
      }

      //*** Call the creators trigger if we have one.
      if (trigger != null) {
         trigger.tick();
      }
   }
}
}

