//******************************************************************************
// PSPA.java: Applet
//
//******************************************************************************
import java.applet.*;
import java.awt.*;
import PSPAFrame;
import NewModel3D;
import Implicit;

//==============================================================================
// Main Class for applet PSPA
//
//==============================================================================
public class PSPA extends Applet implements Runnable
{
 boolean painted = true;
 int prevx;
 int prevy;
 int model = 1;
 float xtheta;
 float xfac;
 float ytheta;
 float scalefudge = 1;
 double ulow = 0;
 double uhigh = 2;
 double vlow = 0;
 double vhigh = 2;
 int ures = 50;
 int vres = 100;
 int r1;
 int r2;
 int dx;
 int dy;
 int dz;
 

 String mdname = null;
 String message = null;

 Matrix3D amat = new Matrix3D();
 Matrix3D tmat = new Matrix3D();
 Matrix3D nmat = new Matrix3D();

 NewModel3D md;
 InterfacePanel interfacePanel;
 ImageCanvas drawArea;

 // THREAD SUPPORT:
 //  drawThread is the Thread object for the applet
 //--------------------------------------------------------------------------
 private Thread  drawThread = null;

 // STANDALONE APPLICATION SUPPORT:
 //  m_fStandAlone will be set to true if applet is run standalone
 //--------------------------------------------------------------------------
 private boolean m_fStandAlone = false;

 // STANDALONE APPLICATION SUPPORT
 //  The main() method acts as the applet's entry point when it is run
 // as a standalone application. It is ignored if the applet is run from
 // within an HTML page.
 //--------------------------------------------------------------------------
 public static void main(String args[])
 {
  // Create Toplevel Window to contain applet PSPA
  //----------------------------------------------------------------------
  PSPAFrame frame = new PSPAFrame("PSPA");

  // Must show Frame before we size it so insets() will return valid values
  //----------------------------------------------------------------------
  frame.show();
        frame.hide();
  frame.resize(frame.insets().left + frame.insets().right  + 320,
      frame.insets().top  + frame.insets().bottom + 240);

  // The following code starts the applet running within the frame window.
  // It also calls GetParameters() to retrieve parameter values from the
  // command line, and sets m_fStandAlone to true to prevent init() from
  // trying to get them from the HTML page.
  //----------------------------------------------------------------------
  PSPA applet_PSPA = new PSPA();

  frame.add("Center", applet_PSPA);
  applet_PSPA.m_fStandAlone = true;
  applet_PSPA.init();
  applet_PSPA.start();
        frame.show();
 }

 // PSPA Class Constructor
 //--------------------------------------------------------------------------
 public PSPA()
 {
 }

 // APPLET INFO SUPPORT:
 //  The getAppletInfo() method returns a string describing the applet's
 // author, copyright date, or miscellaneous information.
    //--------------------------------------------------------------------------
 public String getAppletInfo()
 {
  return "Name: PSPA\r\n" +
         "Author: Yi-Ji Huang\r\n" +
         "Created with Microsoft Visual J++ Version 1.1";
 }
 

 // The init() method is called by the AWT when an applet is first loaded or
 // reloaded.  Override this method to perform whatever initialization your
 // applet needs, such as initializing data structures, loading images or
 // fonts, creating frame windows, setting the layout manager, or adding UI
 // components.
    //--------------------------------------------------------------------------
 public void init()
 {
        // If you use a ResourceWizard-generated "control creator" class to
        // arrange controls in your applet, you may want to call its
        // CreateControls() method from within this method. Remove the following
        // call to resize() before adding the call to CreateControls();
        // CreateControls() does its own resizing.
        //----------------------------------------------------------------------

  Implicit i = new Implicit();

  // Set the Layout Manager

  setLayout(new GridLayout(0,1));

  //Instantiate the user interface and canvas components
  interfacePanel = new InterfacePanel(this);
  add(interfacePanel);
  drawArea = new ImageCanvas();
  add(drawArea);
  validate();

  //Initialize the drawing surface
  amat.yrot(20);
  amat.xrot(20);
  resize(size().width <= 20 ? 400 : size().width,size().height <= 20 ? 400 : size().height);
  tmat.yrot(-20);
  tmat.xrot(20);
  drawArea.setRotate(tmat);
 }

 // Place additional applet clean up code here.  destroy() is called when
 // when you applet is terminating and being unloaded.
 //-------------------------------------------------------------------------
 public void destroy()
 {
  // TODO: Place applet cleanup code here
 }

 // PSPA Paint Handler
 //--------------------------------------------------------------------------
 public void paint(Graphics g)
 {
  if ((md != null))
  {
   md.mat.unit();
   md.mat.translate(-(md.xmin + md.xmax) / 2,-(md.ymin + md.ymax) / 2,-(md.zmin + md.zmax) / 2);
   md.mat.mult(amat);
   md.mat.scale(xfac, -xfac, 8 * xfac / size().width);
   md.mat.translate(drawArea.size().width/2, drawArea.size().height/2,8);
   md.transformed = false;
   md.transform();
   drawArea.draw(md.tvert,md.nvert,md.con,md.ncon);
 
   drawArea.repaint();
   validate();
   setPainted();
  }
  else if (message != null)
  {
   g.drawString("Error in model:", 3, 20);
   g.drawString(message, 10, 40);
  }
  interfacePanel.Ulabel3.setText("");
 }

 private synchronized void setPainted() {
  painted = true;
  notifyAll();
 }

 //  The start() method is called when the page containing the applet
 // first appears on the screen. The AppletWizard's initial implementation
 // of this method starts execution of the applet's thread.
 //--------------------------------------------------------------------------
 public void start()
 {
  if (drawThread == null && md == null && message == null)
  {
   drawThread = new Thread(this);
   drawThread.start();
  }
 }
 
 //  The stop() method is called when the page containing the applet is
 // no longer on the screen. The AppletWizard's initial implementation of
 // this method stops execution of the applet's thread.
 //--------------------------------------------------------------------------
 public void stop()
 {
  if (drawThread != null)
  {
   drawThread.stop();
   drawThread = null;
  }

  // TODO: Place additional applet stop code here
 }

 // THREAD SUPPORT
 //  The run() method is called when the applet's thread is started. If
 // your applet performs any ongoing activities without waiting for user
 // input, the code for implementing that behavior typically goes here. For
 // example, for an applet that performs animation, the run() method controls
 // the display of images.
 //--------------------------------------------------------------------------
 public void run()
 {
   try
   {
    // TODO:  Add additional thread-specific code here
    // Create a new 3D model of the surface
    Thread.currentThread().setPriority(Thread.MIN_PRIORITY);

    if (interfacePanel.cb1.getState() == true)
    {
     interfacePanel.Ulabel3.setText("Drawing surface. Please wait...");
     String XC = interfacePanel.XtextField.getText();
     String YC = interfacePanel.YtextField.getText();
     String ZC = interfacePanel.ZtextField.getText();
    NewModel3D m = new NewModel3D (model,ulow,uhigh,vlow,vhigh,ures,vres,
      r1, r2, dx, dy, dz, " "," "," ");

     interfacePanel.Ulabel3.setText(m.message);
     initModel(m);

     Thread.sleep(50);
    }
   }
   catch (Exception e)
   {
    //       InterruptedException is thrown by Thread.sleep(),
    //   meaning that another thread has interrupted this one
       md = null;
    message = e.toString();
    stop();
   }
  repaint();
 }

 // MOUSE SUPPORT:
 //  The mouseDown() method is called if the mouse button is pressed
 // while the mouse cursor is over the applet's portion of the screen.
 //--------------------------------------------------------------------------
 public boolean mouseDown(Event evt, int x, int y)
 {
  prevx = x;
  prevy = y;
  return true;
 }

 // MOUSE SUPPORT:
 //  The mouseUp() method is called if the mouse button is released
 // while the mouse cursor is over the applet's portion of the screen.
 //--------------------------------------------------------------------------
 public boolean mouseUp(Event evt, int x, int y)
 {
  return true;
 }

 // MOUSE SUPPORT:
 //  The mouseDrag() method is called if the mouse cursor moves over the
 // applet's portion of the screen while the mouse button is being held down.
 //--------------------------------------------------------------------------
 public boolean mouseDrag(Event evt, int x, int y)
 {
     tmat.unit();
  float xtheta = (prevy - y) * 360.0f / size().width;
  float ytheta = (x - prevx) * 360.0f / size().height;
  tmat.xrot(xtheta);
  tmat.yrot(ytheta);
  amat.mult(tmat);
  tmat.unit();
  tmat.xrot(xtheta);
  tmat.yrot(-ytheta);
  drawArea.setRotate(tmat);
  if (painted)
  {
   painted = false;
   repaint();
  }
  prevx = x;
  prevy = y;

  return true;
 }

 // MOUSE SUPPORT:
 //  The mouseMove() method is called if the mouse cursor moves over the
 // applet's portion of the screen and the mouse button isn't being held down.
 //--------------------------------------------------------------------------
 public boolean mouseMove(Event evt, int x, int y)
 {
  return true;
 }

 public void initModel(NewModel3D Model)
 {
  md = Model;
  Model.findBB();
  float xw = Model.xmax - Model.xmin;
  float yw = Model.ymax - Model.ymin;
  float zw = Model.zmax - Model.zmin;
  if (yw > xw)
   xw = yw;
  if (zw > xw)
   xw = zw;
  float f1 = drawArea.size().width / xw;
  float f2 = drawArea.size().height / xw;
  xfac = 0.7f * (f1 < f2 ? f1 : f2) * scalefudge;
 }

 // Redraw the surface on the canvas everytime a change is made in one of the input fields.
 public void draw(Event e, int value)
 {
  model = value;
  try
  {
   interfacePanel.Ulabel3.setText("Drawing surface. Please wait...");
   NewModel3D m = new NewModel3D (model,ulow,uhigh,vlow,vhigh,ures,vres,
    r1, r2, dx, dy, dz,interfacePanel.XtextField.getText(),interfacePanel.YtextField.getText(),interfacePanel.ZtextField.getText());
   interfacePanel.Ulabel3.setText(m.message);
   initModel(m);
  }
  catch(Exception ex)
  {
   md = null;
   message = ex.toString();
  }
  repaint();
 }
}