import java.applet.*;
import java.awt.*;
import java.awt.image.*;
import java.util.Random;

public class WmapTest extends Applet implements Runnable {
  private MediaTracker tracker;
  private Image wmap;
  private Image balloon;
  private Image underBalloon;
  private Point location = new Point(545, 85);
  private Point oldLocation = new Point(-1, -1);
  private int dx = 5;
  private int dy = 0;
  private Thread runner;
  
  /*
  
  private void eraseBalloon(Graphics g) {
    g.drawImage(underBalloon, oldLocation.x, oldLocation.y, this);
  }
  
  private void saveUnderBalloon() {
    ImageFilter filter = new CropImageFilter(location.x, 
        location.y, balloon.getWidth(this), balloon.getHeight(this));
    ImageProducer producer = new FilteredImageSource(wmap.getSource(), filter);
    underBalloon = createImage(producer);
  }
  
  public void drawBalloon(Graphics g) {
    if (oldLocation.x != -1 && oldLocation.y != -1) eraseBalloon(g);
    oldLocation.x = location.x;
    oldLocation.y = location.y;
    saveUnderBalloon();
    g.drawImage(balloon, lLocation.x, location.y, this);

  }
  
  */
  
  public void run() {
    try {
      tracker.waitForAll();
    } catch (InterruptedException e) {}
    repaint();
    System.out.println("width: " + balloon.getWidth(null) + " height:" + balloon.getHeight(null));

    ExpVariateGenerator horizVar = new ExpVariateGenerator(4.0);
    ExpVariateGenerator vertVar = new ExpVariateGenerator(1.0);
    while ( true ) {
      try {
        Thread.sleep(600);
      }
      catch (InterruptedException e) {}
      // move the balloon and redraw it
      int oldx = location.x;
      int oldy = location.y;
      if (horizVar.toss()) dx = dx + (int)horizVar.nextVariate();
      else dx = dx - (int)horizVar.nextVariate();
      System.out.print("dx =" + dx);
      if (vertVar.toss()) dy = dy + (int)vertVar.nextVariate();
      else dy = dy - (int)vertVar.nextVariate();
      System.out.print("dy =" + dy);
      location.x = (oldx + dx) % wmap.getWidth(this);
      if (location.x < 0) location.x += wmap.getWidth(this);
      location.y = (oldy + dy) % wmap.getHeight(this);
      if (location.y < 0) location.y += wmap.getHeight(this);
      System.out.println(" -> (" + location.x + "," + location.y + ")");
      int minx = Math.min( 0, Math.min(oldx, location.x));
      int maxx = Math.max( wmap.getWidth(this)-balloon.getWidth(this), Math.max(oldx, location.x));
      int miny = Math.min( 0, Math.min(oldy, location.y));
      int maxy = Math.max( wmap.getHeight(this)-balloon.getHeight(this), Math.max(oldy, location.y));
      repaint(minx, miny, maxx + balloon.getWidth(this), maxy + balloon.getHeight(this));
    }
  }

  public void init() {
    tracker = new MediaTracker(this);
    wmap = getImage
         (getCodeBase(), "wmap.gif");
    tracker.addImage(wmap, 0);
    balloon = getImage
         (getCodeBase(), "trialBalloon.GIF");
    tracker.addImage(balloon, 1);
  }
  
  public void start() {
    if (runner == null) {
      runner = new Thread(this);
      runner.start();
    }
  }
  
  public void stop() {
    if (runner != null) {
      runner.stop();
      runner = null;
    }
  }
  
  public void update(Graphics g) {
    paint(g);
  }
  
  public void paint(Graphics g) {
    if (tracker.checkAll(true)) {
      g.drawImage(wmap, 0, 0, this);
      g.drawImage(balloon, location.x, location.y, this);
    }
    else 
      g.drawString("Loading Images", 100, 100);
  }
}



/** Random variate generator to generate pseudorandom numbers with an exponential distribution */
class ExpVariateGenerator {
  /** initialize with an explicit seed */
  public ExpVariateGenerator(double m, long seed) {
    mean = m;
    r = new Random(seed);
  }
  
  /** initialize with seed specified by random class (current time) */  
  public ExpVariateGenerator(double m) { 
    mean = m;
    r = new Random();
  }
  
  /** generate and return the next random variate 
      * @return the next random variate with given mean */
  double nextVariate() {
    return -mean * Math.log(r.nextDouble());
  }

  /** hacky coin-toss method */
  boolean toss() {
    return (r.nextDouble() >= 0.5) ? true : false;
  }

  
  /** used for test code */
  public static int testTrials = 5000;
  
  /** Test code */
  public static void main(String [] args) {
    double r;
    double sum = 0;
    double maxv = 0;
    double minv = 0;
    ExpVariateGenerator evr = new ExpVariateGenerator(5.0);
    r = evr.nextVariate();
    maxv = minv = r;
    sum += r;
    for (int i = 0; i < testTrials-1; i++) {
      r = evr.nextVariate();
      maxv = Math.max(maxv, r);
      minv = Math.min(minv, r);
      sum += r;
    }
    System.out.println("trials: " + testTrials + " average: " +
    	sum/testTrials + " min: " + minv + " max: " + maxv);
  }
    
  
  private double mean;
  private Random r;
}
