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

public class CGApplet
  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 pGrad;
  private Label lG1;
  private TextField tfG1;
  private Label lG2;
  private TextField tfG2;

  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 GradientMinimizer gmz;
  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;

  public static final int ALG_SD = 0;
  public static final int ALG_CGFR = 1;
  public static final int ALG_CGPR = 2;

  private int lastSel = 0;

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

  public CGApplet()
  {
    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" );
    lMethod = new Label( "   Method to be used" );
    chMethod = new Choice();
    chMethod.addItem( "Steepest Descent" );
    chMethod.addItem( "CG Fletcher-Powell" );
    chMethod.addItem( "CG Polak-Ribiere" );
    pType.add( lType );
    pType.add( chType );
    pType.add( lMethod );
    pType.add( chMethod );

    pEqn = new Panel();
    pEqn.setLayout( new BorderLayout() );

    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 );

    pGrad = new Panel();
    pGrad.setLayout( new FlowLayout( FlowLayout.LEFT ) );
    lG1 = new Label( "f1(x1,x2)=" );
    tfG1 = new TextField( 28 );
    lG2 = new Label( "f2(x1,x2)=" );
    tfG2 = new TextField( 28 );
    pGrad.add( lG1 );
    pGrad.add( tfG1 );
    pGrad.add( lG2 );
    pGrad.add( tfG2 );

    pEqn.add( "North", pFunc );
    pEqn.add( "South", pGrad );

    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", pEqn );
    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 );

        tfG1.setText( "-400*x1*(x2-x1*x1)-2*(1-x1)" );
        tfG1.setEditable( false );
        tfG2.setText( "200*(x2-x1*x1)" );
        tfG2.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 );

        tfG1.setText( "x1/50" );
        tfG1.setEditable( false );
        tfG2.setText( "2*x2" );
        tfG2.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 );
        tfG1.setEditable( true );
        tfG2.setEditable( true );
        tfX1.setEditable( true );
        tfX2.setEditable( true );
        xc = yc = 0.0;
        rad = 10;
    }
  }

  public void showResult( Vertex v )
  {
    double val;

    tfValue.setText(
      "f( " + v.coord[0] + ", " + v.coord[1]  + " ) = "  + v.val );
  }

  public void showState()
  {
    taMsg.appendText(
        "f" + gmz.dblArrayToString( gmz.getCurrentX() )
            + "=" + gmz.getCurrentFnVal() + "\n" );
    taMsg.appendText(
        "Gradient g:" + gmz.dblArrayToString( gmz.getCurrentG() ) + "\n" );
    taMsg.appendText(
        "Direction h:" + gmz.dblArrayToString( gmz.getCurrentH() ) + "\n" );
  }

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

    taMsg.appendText( "\nIteration " + gmz.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");
          gmz = new GradientMinimizer( 2 );
          int oper = chMethod.getSelectedIndex();
          gmz.setAlgorithm( oper );
          gmz.setFunction( tfFunc.getText() );
          grExp[0] = tfG1.getText();
          grExp[1] = tfG2.getText();
          gmz.setGradient( grExp );
          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();
          gmz.initCGSD( x );
          pCanv.setLimits( xc, yc, rad );
          pCanv.clear();
          pCanv.addPoint( gmz.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();
        vMouse.val = gmz.evalF( vMouse.coord );
        showResult( vMouse );
      }
    }
    if( evt.id == Event.MOUSE_MOVE ) {
    }
    return super.handleEvent( evt );
  }

  public void init()
  {
  }
}
