import java.applet.Applet;
import java.awt.event.*;
import java.awt.*;

public class fract extends    Applet          // this fractal applet extends the Applet prototype
		               implements MouseListener   // and implements the mouse listener to allow event
                                              // handling.
{

	// Definition of constants
  // -----------------------
  
	final double default_real_min = -2; // The Mandelbrot fractal is defined for
	final double default_real_max = 2;  // complex numbers with 
	final double default_imag_min = -2; // -2 < real(z) < 2 and -2 < imag(z) < 2.
	final double default_imag_max = 2;  // In the picture, the x-axis represents
                                      // the real part of the number, whereas 
                                      // the y-axis represents the imaginary part.
                                      
  final int max_iter = 255;           // maximum number of iterations
                                      // (limited by the max. number of colors)

  final int zoom_factor = 4;          // the zooming window will be 1/4th = 25% of
                                      // the actual picture size

	// Definition of variables
  // -----------------------

	double real_min = default_real_min; // actual min. real part 
	double real_max = default_real_max; // actual max. real part 
	double imag_min = default_imag_min; // actual min. imaginary part 
	double imag_max = default_imag_max; // actual max. imaginary part 
  
  Dimension applet_size;              // size of the applet
  int xmax, ymax;                     // width and height of the picture in pixels
  
  int clipping_pixels_x,              // current mouse position +/- clipping pixels x/y
      clipping_pixels_y;              // determines the width/height of our zooming window

  int zoom_window_start_x,            // xy boundaries of the zooming window
      zoom_window_start_y,
      zoom_window_stop_x, 
      zoom_window_stop_y;
 
  // Functions
  // ---------
  
	public int iterate( double complex_real,  
			                double complex_imag  )
	{
    // ----------------------------------------------------------------
    // This function returns the number of iterations we need to reach
    //
    //          2            2
    // real( p )  + imag( p )  ~= 4, or we exceed the number of maximum
    //                               iterations allowed
    //
    //
    // with the recursive formulas
    //
    //                          2            2
    // real( new_p ) = real( p )  - imag( p )  + real( z )
    // 
    // and
    //
    // imag( new_p ) = 2 * ( real( p ) * imag( p ) ) + imag( z )
    //
    //
    // when p starts at 0 + 0i.
    //
    // ----------------------------------------------------------------

    // local variables
		double real = 0, 
		       imag = 0;
		double new_real,
		       new_imag;
		int    iteration_count = 0;

		while (( real * real + imag * imag < 4 )
		      && ( iteration_count != max_iter ))
		{
			new_real = real * real - imag * imag + complex_real;
			new_imag = real * imag + real * imag + complex_imag;
		
			real = new_real;
			imag = new_imag;

			iteration_count++; 
		}

		return iteration_count;
	}

	public void paint( Graphics g )
	{
    // ----------------------------------------------------------------
    // This function is mandatory for each applet. It actually draws
    // the picture.
    // In this applet, the whole xy space available for the applet is
    // first mapped into the real and imaginary boundaries of the 
    // fractal number space. Then we calculate the number of iterations
    // for each pixel and draw it in the color represents this number.
    // If the maximum number of iterations has been reached for a
    // specific pixel, we will draw it in black color.
    // ----------------------------------------------------------------

    // local variables
		double real, imag;
		double step_real, step_imag;
		int    x, y;
		int    iterations;
		int    color;

		imag = imag_max;  // we will start at x = 0, y = 0 (left upper corner), which
                      // is the minimum of real( z ) and maximum of imag( z )
		
    // mapping the pixel steps into steps for z
		step_real = ( real_max - real_min ) / xmax;  
		step_imag = ( imag_max - imag_min ) / ymax;

    // loop through the whole picture
		for( y = 0; y < ymax; y++ )
		{
			real = real_min;
			for( x = 0; x < xmax; x++ )
			{
      
        // calculate number of iterations for the current pixel
				iterations = iterate( real, imag );
        
				if ( iterations > max_iter ) 
          // draw pixel in black color, if allowed
          // number of iterations has been reached
					color = 0;
				else
          // let the color value (0 to 255) represent the number
          // of iterations for this pixel
					color = iterations;
        
        // set color and draw pixel
				g.setColor( new Color( color, 0, 0 ));
				g.drawLine( x, y, x, y );
        
				real += step_real;	
			}
			imag -= step_imag;
		}
	}

	public void init()
	{
    // ----------------------------------------------------------------
    // The init() function of an applet is always executed when the
    // applet gets initialized (loaded into the browser).
    // Hence we will do some initialization stuff in here...
    // ----------------------------------------------------------------
 
    // setting initial background to white
		this.setBackground( new Color( 255, 255, 255 ));

    // adding event listener to this applet
		addMouseListener( this );

    // get applet size and set the pixel limits of
    // the fractal image
    applet_size = this.getSize();
    ymax = applet_size.height;
    xmax = applet_size.width;

    // calculating the clipping size
    // Note: (int) performs a type cast
    clipping_pixels_x = (int) ( xmax / zoom_factor );
    clipping_pixels_y = (int) ( ymax / zoom_factor ); 
  }

  // Event Handling
  // --------------

	public void mousePressed( MouseEvent e )
	{
    // ----------------------------------------------------------------
    // This function gets executed whenever somebody presses the mouse
    // button down inside the applet (fractal picture).
    // ----------------------------------------------------------------
 
    // So let's determine our position and define our zooming window
		zoom_window_start_x = e.getX() - clipping_pixels_x;
		zoom_window_start_y = e.getY() - clipping_pixels_y;

    zoom_window_stop_x  = e.getX() + clipping_pixels_x;
    zoom_window_stop_y  = e.getY() + clipping_pixels_y;
	}
  

	public void mouseReleased( MouseEvent e )
	{
    // ----------------------------------------------------------------
    // Sooner or later, the user will release a pressed mouse button  
    // (unless either the mouse or the user dies ;-)
    // We will now use the zooming window as new boundaries of the
    // complex number space z.
    // ----------------------------------------------------------------
 
    // local variables
		double real1, imag1;
    double real2, imag2;

    // mapping xy pixels for each corner of the zoom window into real
    // and imaginary part of z
    real1 = real_min + zoom_window_start_x * ( real_max - real_min ) / xmax;
    imag1 = imag_max - zoom_window_start_y * ( imag_max - imag_min ) / ymax;

    real2 = real_min + zoom_window_stop_x * ( real_max - real_min ) / xmax;
    imag2 = imag_max - zoom_window_stop_y * ( imag_max - imag_min ) / ymax;

    // no matter in which direction the zoom window was opened
    // (I left this in from the version where the user could define the
    // clipping window by dragging the mouse.)
    if ( real1 < real2 )
      {
        real_min = real1;
        real_max = real2;
      }
    else
      {
        real_min = real2;
        real_max = real1;
      }
    
    if ( imag1 < imag2 )
      {
        imag_min = imag1;
        imag_max = imag2;
      }
    else
      {
        imag_min = imag2;
        imag_max = imag1;
      }
      
    // re-draw the picture using the new z space just calculated
    repaint();  
	}
  
	public void mouseEntered( MouseEvent e )
	{
    // ----------------------------------------------------------------
    // This gets executed when the mouse pointer enters the applet.
    // We will give zooming instruction by writing some text into the
    // status line of the browser that runs the applet.
    // ----------------------------------------------------------------
    getAppletContext().showStatus( "Click on the picture to zoom in ..." );
	}

	public void mouseExited( MouseEvent e )
	{
    // ----------------------------------------------------------------
    // This gets executed when the mouse pointer leaves the applet.
    // ----------------------------------------------------------------
    
    // Let's clean up the status line ...
    getAppletContext().showStatus( "                                   " );
	}

	public void mouseClicked( MouseEvent e )
	{
    // ----------------------------------------------------------------
    // Actually, we don't do anything when the user clicks the mouse.
    // (click -> there is a certain delay between pressing and
    // releasing the mouse button). All we need for zooming we have
    // already handled in mousePressed and mouseReleased (see above).
    // However, the definition of this function is required by the
    // mouse listener that we have added to this applet. So we just
    // leave this function empty.
    // ----------------------------------------------------------------
	}

}
