import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;

public class ExpressionApplet extends java.applet.Applet implements Variable{
        Image img;                              // image buffer used to draw plot
        Expression exp;                 // the Expression we wish to draw
        TextField input;                // the user input field for the Expression
        double x, y;                    // the currently evaluated variables
        double left = -Math.PI, right = Math.PI, top = Math.PI, bottom = - Math.PI;
                                                        // our bounds
        
        /*
        * Set up the interface, create an initial Expression,
        * and draw it.
        */
        public void init(){
                input = new TextField("x^2+y^2",20);
                Button b = new Button( "Draw" );
                final Variable v = this;
                input.addActionListener( new ActionListener(){
                                public void actionPerformed( ActionEvent e ){
                                        exp = new Expression( input.getText(), v );
                                        img = null;
                                        repaint();
                                }
                        } );
                b.addActionListener( new ActionListener(){
                                public void actionPerformed( ActionEvent e ){
                                        exp = new Expression( input.getText(), v );
                                        img = null;
                                        repaint();
                                }
                        } );
                add( input );
                add( b );
                exp = new Expression("x^2+y^2", this);
                repaint();
        }

        /*
        * Looks for variables we define, and returns them
        * appropriately. Otherwise, returns NaN.
        */
        public double variable( String s ){
                if( s.compareTo( "x" ) == 0 || s.compareTo( "X" ) == 0 )
                        return x;
                if( s.compareTo( "y" ) == 0 || s.compareTo( "Y" ) == 0 )
                        return y;
                return Math.log(-1);
        }

        /*
        * Evaluate and draw the Expression at every pixel.
        */
        public void paint( Graphics g ){
                double min = 0, max = 0;
                if( img != null ){
                        g.drawImage( img, 0, 0, this );
                        return;
                }
                for( int y = 0; y < getSize().height; y++ ){
                        for( int x = 0; x < getSize().width; x++ ){
                                mapToVirtual( x, y );
                                double a = exp.evaluate();
                                if( a > max )
                                        max = a;
                                else if( a < min )
                                        min = a;
                        }
                }
                int pix[] = new int[ getSize().width * getSize().height ];
                int index = 0;
                for( int y = 0; y < getSize().height; y++ ){
                        for( int x = 0; x < getSize().width; x++ ){
                                mapToVirtual( x, y );
                                pix[ index++ ] = Color.getHSBColor( (float)(exp.evaluate()/(max-min) - min/(max-min)), 1, 1 ).getRGB();
                        }
                }
                img  = createImage( new MemoryImageSource( getSize().width, getSize().height, pix, 0, getSize().width ) );
                g.drawImage( img, 0, 0, this );
        }

        /*
        * Map a pixel coordinate to a virtual coordinate.
        */
        public void mapToVirtual( int x, int y ){
                this.x = ( (right-left)/getSize().width )*x + left;
                this.y = ( (bottom-top)/getSize().height )*y + top;
        }
}
