/* An applet to put rotatable image into a page
   The rotatable image class is RotateImage.java
   */
   
import java.applet.Applet;
import java.awt.Image;
import java.awt.Event;
import java.awt.Graphics;
import java.awt.Color;
import java.io.StreamTokenizer;
import java.awt.MediaTracker;
import java.awt.image.IndexColorModel;
import java.awt.image.ColorModel;
import java.awt.image.MemoryImageSource;

public class RotateImageApp extends Applet implements Runnable {
   RotateImage rotImage;
   Image gotimg;
   boolean painted = true;
   int prevx, prevy;
   float xtheta, ytheta;
   Matrix3D pixmat = new Matrix3D();
   Image backBuffer;
   Graphics backGC;
   MediaTracker tracker;
   Thread rotImageThread;
   int sizex = 200, sizey = 200;
   /* width and height of the rotatable image */
   int w,h;
   boolean mousedragged = false;
   
   public void init() {
      resize(sizex,sizey);
      tracker = new MediaTracker(this);
      String imgname = getParameter("img");
      try {
         gotimg = getImage( getDocumentBase(), imgname );
         tracker.addImage(gotimg, 0);
         tracker.waitForID(0);
         w = 40;
         h = 50;
         }
      catch (Exception e) {
         System.out.println("error processing: " + e);
         e.printStackTrace();
         }
      rotImage = new RotateImage(gotimg, this, w, h);
      /* depending on the initial position of the image, it will
         be given an initial rotation and translation */
      //rotImage.mat.unit();
      int depth = 50; // z-distance of the image from the center
      //rotImage.mat.translate( -(w/2), -(h/2), depth );
      pixmat.unit();
      backBuffer = createImage(sizex,sizey);
      backGC = backBuffer.getGraphics();
      setBackground(Color.lightGray);
      }
      
   public void run() {
      repaint();
      }
      
   public void start() {
      if (rotImageThread == null) {
         rotImageThread = new Thread(this);
         rotImageThread.start();
         }
      }
      
   public void stop() {
      rotImageThread = null;
      }
      
   public void update(Graphics g) {
      if (backBuffer == null)
         g.clearRect(0, 0, sizex, sizey);
      paint(g);
      }
      
   public void paint(Graphics g) {
      rotImage.mat.unit();
      rotImage.mat.translate( -(w/2), -(h/2), 20 );
      rotImage.mat.mult(pixmat);
      rotImage.mat.translate(sizex / 2, sizey / 2, 0);
      rotImage.transformed = false;
      if (backBuffer != null) {
         backGC.setColor(getBackground());
         backGC.fillRect(0, 0, sizex, sizey);
         rotImage.paint(backGC);
         g.drawImage(backBuffer, 0, 0, this);
         } 
      else {
         rotImage.paint(g);
         }
      setPainted();
      }
   
   public boolean mouseDown(Event e, int x, int y) {
      prevx = x;
      prevy = y;
      return true;
      }

   public boolean mouseDrag(Event e, int x, int y) {
      Matrix3D tmat = new Matrix3D();
      tmat.unit();
      float xtheta = (y - prevy) * (360.0f / sizex);
      float ytheta = (x - prevx) * (360.0f / sizey);
      tmat.xrot(xtheta);
      tmat.yrot(ytheta);
      pixmat.mult(tmat);
      if (painted) {
         painted = false;
         repaint();
      }
      prevx = x;
      prevy = y;
      return true;
      }
 
   private synchronized void setPainted() {
      painted = true;
      notifyAll();
      }

   private synchronized void waitPainted() {
      //System.out.println("inside");
      while (!painted) {
         try {
            wait();
            }
         catch (InterruptedException e) {}
         }
      painted = false;
      }
   }
