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

public class HJApplet
  extends Applet
{
  private TabPan tPan;
  private Panel pUI;
  private Panel pSpec;

  private Panel pType;
  private Label lType;
  private Choice chType;
  // private Label lMethod;
  // private Choice chMethod;

  private Panel pEqn;

  private Panel pFunc;
  private Label lFunc;
  private TextField tfFunc;

  private Panel pXY;
  private Label lX1;
  private TextField tfX1;
  private Label lX2;
  private TextField tfX2;

  private Panel pOper;
  private Panel pView;
  private Panel cmdPan;
  private Button b1;
  private Button b10;
  private Button b100;
  private Button bAnim;
  private Button bStop;
  private Panel pRight;
  
  private PathCanvas pCanv;
  private Panel pMsg;
  private Label lMsg;
  private TextArea taMsg;

  private TextField tfValue;

  // private Vector pfExp;
  private Variable X;
  private Variable Y;

  private HookeJeevesMinimizer hjmz;
  private String grExp[] = new String[2];

  public static final int CH_ROSENBROCK = 0;
  public static final int CH_QUADRATIC = 1;
  public static final int CH_OTHER = 2;

  private int lastSel = 0;

  private double xc=0.0, yc=0.0, rad=10.0;

  public HJApplet()
  {
    pType = new Panel();
    pType.setLayout( new FlowLayout( FlowLayout.LEFT ) );
    lType = new Label( "Type" );
    chType = new Choice();
    chType.addItem( "Rosenbrock" );
    chType.addItem( "Quadratic" );
    chType.addItem( "Other" );
    pType.add( lType );
    pType.add( chType );

    pFunc = new Panel();
    pFunc.setLayout( new FlowLayout( FlowLayout.LEFT ) );
    lFunc = new Label( "f(x1,x2)=" );
    tfFunc = new TextField( 40 );
    pFunc.add( lFunc );
    pFunc.add( tfFunc );

    pXY = new Panel();
    pXY.setLayout( new FlowLayout( FlowLayout.LEFT ) );
    lX1 = new Label( "Start x1" );
    tfX1 = new TextField( 10 );
    lX2 = new Label( "Start x2" );
    tfX2 = new TextField( 10 );
    pXY.add( lX1 );
    pXY.add( tfX1 );
    pXY.add( lX2 );
    pXY.add( tfX2 );

    pUI = new Panel();
    pUI.setLayout( new BorderLayout() );
    pSpec = new Panel();
    pSpec.setLayout( new BorderLayout() );
    pSpec.add( "North", pType );
    pSpec.add( "Center", pFunc );
    pSpec.add( "South", pXY );
    pUI.add( "North", pSpec );

    pOper = new Panel();
    pOper.setLayout( new BorderLayout() );
    cmdPan = new Panel();
    b1 = new Button( "1 Step" );
    b10 = new Button( "10 Steps" );
    // b100 = new Button( "100 Steps" );
    bAnim = new Button( "Animate" );
    bAnim.disable();
    bStop = new Button( "Stop" );
    bStop.disable();
    cmdPan.add( b1 );
    cmdPan.add( b10 );
    // cmdPan.add( b100 );
    cmdPan.add( bAnim );
    cmdPan.add( bStop );
    pCanv = new PathCanvas();
    tfValue = new TextField( 40 );
    pView = new Panel();
    pView.setLayout( new BorderLayout() );
    pView.add( "North", cmdPan );
    pView.add( "Center", pCanv );
    pView.add( "South", tfValue );
    pOper.add( "Center", pView );
    pMsg = new Panel();
    pMsg.setLayout( new BorderLayout() );
    lMsg = new Label( "Details:" );
    taMsg = new TextArea( 20, 50 );
    pMsg.add( "North", lMsg );
    pMsg.add( "Center", taMsg );
    pOper.add( "East", pMsg );

    tPan = new TabPan();
    tPan.addT( "Specification", pUI );
    tPan.addT( "Operation", pOper );

    setLayout( new BorderLayout() );
    add( "Center", tPan );

    setFnChoice( CH_ROSENBROCK );
  }

  public void setFnChoice( int ch )
  {
    switch( ch ) {
      case CH_ROSENBROCK:
        tfFunc.setText( "100*(x2-x1*x1)^2 + (1-x1)^2" );
        tfFunc.setEditable( false );

        tfX1.setText( "-1.2" );
        tfX1.setEditable( false );
        tfX2.setText( "1.0" );
        tfX2.setEditable( false );

        xc = yc = 0.0;
        rad = 1.5;
        break;
      case CH_QUADRATIC:
        tfFunc.setText( "x1*x1/100 + x2*x2" );
        tfFunc.setEditable( false );

        tfX1.setText( "8.0" );
        tfX1.setEditable( false );
        tfX2.setText( "0.6" );
        tfX2.setEditable( false );
        xc = yc = 0.0;
        rad = 10;
        break;
      default:
        tfFunc.setEditable( true );
        tfX1.setEditable( true );
        tfX2.setEditable( true );
        xc = yc = 0.0;
        rad = 10;
    }
  }

  public void showResult( Vertex v )
  {
    tfValue.setText(
      "f( " + v.coord[0] + ", " + v.coord[1]  + " ) = "  + v.val );
  }

  public void showState()
  {
    taMsg.appendText(
        "f" + hjmz.currV.toString()
            + "=" + hjmz.getCurrentFnVal() + "\n" );
    taMsg.appendText( "Number of function evaluations:" +
        hjmz.countFnEvals() + "\n" );
  }

  public void oneStep()
  {
    hjmz.next();
    pCanv.addPoint( hjmz.getCurrentX() );
    pCanv.repaint();

    taMsg.appendText( "\nIteration " + hjmz.countIterations() + ":\n" );
    showState();
  }

  public boolean handleEvent( Event evt )
  {
    int i;
    int sel = chType.getSelectedIndex();
    if( sel != lastSel ) {
      setFnChoice( sel );
      lastSel = sel;
    }
    if( evt.id == Event.LIST_SELECT ) {
      if( evt.target == chType ) {
        setFnChoice( chType.getSelectedIndex() );
      }
    }
    if( evt.id == Event.ACTION_EVENT ) {
      if( evt.target == chType ) {
        setFnChoice( chType.getSelectedIndex() );
      }
      if( evt.target == tPan ) {
        // System.out.println( evt.arg );
        Integer I = (Integer) evt.arg;
        // I = new Integer( 1 );
        if( tPan.getSelectedIndex() == 1 ) {
          taMsg.setText("START:\n");
          hjmz = new HookeJeevesMinimizer( 2 );
          hjmz.init( tfFunc.getText() );
          double x[] = new double[2];
          Double D;
          Vertex V0 = new Vertex( 2 );
          D = new Double( tfX1.getText() ); 
          x[0] = D.doubleValue();
          D = new Double( tfX2.getText() ); 
          x[1] = D.doubleValue();
          hjmz.start( new Vertex( x ), 0.5 );
          pCanv.setLimits( xc, yc, rad );
          pCanv.clear();
          pCanv.addPoint( hjmz.getCurrentX() );
          showState();
        }
      }
      if( evt.target == b1 ) {
        oneStep();
        pCanv.repaint();
      }
      if( evt.target == b10 ) {
        for( i = 0; i < 10; i++ )
          oneStep();
        pCanv.repaint();
      }
      if( evt.target == pCanv ) {
        Vertex vMouse = pCanv.getMouseVertex();
        hjmz.evalX( vMouse );
        showResult( vMouse );
      }
    }

    return super.handleEvent( evt );
  }

  public void init()
  {
  }
}
