/* App3DRotate.java 
 * Author: David Wanqian Liu
 * Date: Dec 20, 1995
 */


import java.applet.Applet;
import java.awt.*;
import java.io.*;
import java.net.*;



public class  App3DRotate extends Applet implements Runnable {
  Model3DPolyMesh model;
  Matrix3D tmat = new Matrix3D();
  Vertex origin;
  Choice Ylm_amp,Ylm_mode;
  Label lbl_Amp,lbl_Mode;

  String message = null;
  String curr_Mode = "00";
  String new_Mode = new String(curr_Mode);
  String curr_Amp = "0.0";
  String new_Amp = new String(curr_Mode);
  boolean norotate = true;


  public void init() {
    String srot = getParameter("norotate");
    if (srot != null)
      norotate = srot.startsWith("t");

    String modelname = getParameter("model");
    if (modelname == null)
      modelname = "model.obj";

    resize(size().width <= 20 ? 400 : size().width,
	   size().height <= 20 ? 400 : size().height);

    setLayout(new FlowLayout(FlowLayout.RIGHT,10,0));

    InputStream is = null;

    /* Read input data file, create 3D model, and scale the model to
       the size of Applet */
    try {
      Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
      is = new URL(getDocumentBase(), modelname).openStream();

      Model3DInputFilePolyMesh polymesh = new Model3DInputFilePolyMesh(is);
      model = new Model3DPolyMesh(polymesh.vertices, polymesh.nvertices,
				  polymesh.edges, polymesh.nedges,
				  polymesh.faces, polymesh.nfaces);
      origin = model.defineBB(size().width, size().height);

      /* Init the model with some angle */
      tmat.unit();
      tmat.translate(-origin.x, -origin.y, -origin.z);
      tmat.yrot(45.0f);
      tmat.xrot(90.0f);
      tmat.translate(origin.x, origin.y, origin.z);
      model.transform(tmat);
/*
*/

    } catch(Exception e) {
      model = null;
      message = e.toString();
      e.printStackTrace();
    }

    /* Close input data file */
    try {
      if (is != null) is.close();
    } catch(Exception e) {
    }
    //Add choice menu for Ylm mode 
    lbl_Mode = new Label("Ylm mode");
    add (lbl_Mode);
    Ylm_mode = new Choice();
    Ylm_mode.addItem("00");
    Ylm_mode.addItem("10");
    Ylm_mode.addItem("11");
    Ylm_mode.addItem("20");
    Ylm_mode.addItem("21");
    Ylm_mode.addItem("22");
    Ylm_mode.addItem("30");
    Ylm_mode.addItem("31");
    Ylm_mode.addItem("32");
    Ylm_mode.addItem("33");
    Ylm_mode.select("00");
//    add (Ylm_mode);
    add ("Ylm_Mode",Ylm_mode);
         //System.out.println("Ylm_mode = "+Ylm_mode.toString());

    //Add choice menu for Ylm amp 
    lbl_Amp = new Label("Ylm amp");
    add (lbl_Amp);
    Ylm_amp = new Choice();
    Ylm_amp.addItem("0.0");
    Ylm_amp.addItem("10.0");
    Ylm_amp.addItem("25.0");
    Ylm_amp.addItem("50.0");
    Ylm_amp.addItem("100.0");
    Ylm_amp.addItem("200.0");
    Ylm_amp.addItem("300.0");
    Ylm_amp.addItem("400.0");
    Ylm_amp.select("0.0");
//    add (Ylm_amp);
    add ("Ylm_Mode",Ylm_amp);

         //System.out.println("Ylm_amp = "+Ylm_amp.toString());
         //System.out.println("Ylm_amp = "+Ylm_amp.paramString());
         Ylm_amp.list();
         //System.out.println("Number of components = "+String.valueOf(countComponents()));


  }


  Thread artist=null;

  public void start() {
    if (artist == null) {
      artist = new Thread(this);
      artist.start();
    }
  }
  
  public void stop() {
    artist.stop();
    artist = null;
  }
  
  public void run() {
    while (artist != null) {
      proc();

      try {Thread.sleep(100);} 
      catch (InterruptedException e){}
    }
    artist = null;
  }
  
  public synchronized void proc() {


    if (norotate) {

      repaint();
      return;
    }


    if (message != null) {
      repaint();
      return;
    }

    /* Create tranformation matrix to rotate the model */

    tmat.unit();
    tmat.translate(-origin.x, -origin.y, -origin.z);
    tmat.xrot(-90.0f);
    tmat.yrot(-45.0f);
    tmat.xrot(5.0f);
    tmat.yrot(45.0f);
    tmat.xrot(90.0f);
    tmat.translate(origin.x, origin.y, origin.z);
      
    model.transform(tmat);
    
    repaint();

  }    


  int prevx, prevy;
  float xtheta, ytheta;

  public boolean mouseDown(Event e, int x, int y) {
    prevx = x;
    prevy = y;
    return true;
  }


  public boolean mouseDrag(Event e, int x, int y) {
    if (message != null) {
      repaint();
      return true;
    }

    float xtheta = (prevy - y) * 360.0f / size().width;
    float ytheta = (prevx - x) * 360.0f / size().height;

    /* Create tranformation matrix to rotate the model */
    tmat.unit();
    tmat.translate(-origin.x, -origin.y, -origin.z);
    tmat.xrot(xtheta);
    tmat.yrot(ytheta);
    tmat.translate(origin.x, origin.y, origin.z);
	
    model.transform(tmat);
    
    repaint();

    prevx = x;
    prevy = y;

    return true;
  }

  public boolean action(Event evt, Object arg) {
   //Check to see whether a new constraint has been selected from the menu.
//         //System.out.println("evt.id = "+evt.id);
     if(evt.target==Ylm_mode) {
//         System.out.println("evt = "+evt.target.toString());
         handleModeChoice((String) arg);
     }
     else if(evt.target==Ylm_amp) {
         //System.out.println("evt = "+evt.target.toString());
         handleAmpChoice((String) arg);
     }
      return true;
   }

   void handleModeChoice(String constraint) {
      int mode;
      float amp;
      new_Mode = constraint;
      if( !(new_Mode.equals(curr_Mode))){
         Float famp;
         Integer imode;
         curr_Mode = new String(new_Mode);
         imode = Integer.valueOf(new_Mode);
         mode = imode.intValue();
         famp = Float.valueOf(curr_Amp);
         amp = famp.floatValue();
         //System.out.println("mode = "+mode+"  amp = "+amp);
         model.Ylm(mode,amp);
         tmat.unit();
         model.transform(tmat);
         repaint();
      }
   }

   void handleAmpChoice(String constraint) {
      new_Amp = constraint;
      if( !(new_Amp.equals(curr_Amp))){
         Float famp;
         Integer imode;
         int mode;
         float amp,scale,old_amp;
         imode = Integer.valueOf(curr_Mode);
         mode = imode.intValue();
         famp = Float.valueOf(new_Amp);
         amp = famp.floatValue();
         famp = Float.valueOf(curr_Amp);
         old_amp = famp.floatValue();
         curr_Amp = new String(new_Amp);
         scale = (1.0f + 0.01f*old_amp)/(1.0f + 0.01f*amp);
         model.Ylm(mode,amp);
//         System.out.println("amp = "+amp+"  old_amp = "+old_amp);
//         System.out.println("scale = "+scale);
         //System.out.println("xorigin = "+origin.x+"  yorigin = "+origin.y+"  zorigin = "+origin.z);
         tmat.unit();
         tmat.translate(-origin.x, -origin.y, -origin.z);
         tmat.scale(scale);
         tmat.translate(origin.x, origin.y, origin.z);
         model.transform(tmat);
         repaint();
      }
   }

  /* Double buffering for update */
  Image offscreen;
  Graphics offgraphics;
  Dimension offscreensize;

   

  public synchronized void update(Graphics g) {
  
    /* Create an image buffer for updating screen */
    Dimension d = size();
    if ((offscreen == null) ||
        (d.width != offscreensize.width) ||
        (d.height != offscreensize.height)) {
      offscreen = createImage(d.width, d.height);
      offscreensize = d;
      offgraphics = offscreen.getGraphics();
      offgraphics.setFont(getFont());
    }

    /* Use the last used color to fill the background.
       This will give the effect of laser reflecting from the sphere.
       */
      offgraphics.setColor(Color.white);
      offgraphics.fillRect(0, 0, d.width, d.height);

    if (model != null) {
      model.paint(offgraphics);
      g.drawImage(offscreen, 0, 0, null);
    } 

    if (message != null) {
      g.drawString("Error in model:", 5, 20);
      g.drawString(message, 15, 40);
    }
  }
}
