import java.awt.image.*;
import java.awt.Graphics;
import java.awt.Color;
import java.awt.Event;
import java.awt.Image;
import java.awt.Font;



public class Mandel extends java.applet.Applet implements Runnable
{
  int mouse_oldx = 0, mouse_oldy = 0;
  int mouse_x = 0, mouse_y = 0;
  boolean mouse_drag = false;

  Thread runThread;
  int im_w = 480, im_h = 480;
  Graphics img;
  Image im;

  double drawx1 = -2, drawy1 = -2;
  double drawx2 =  2, drawy2 =  2;

  int drawx = 0, drawy = 0;
  Color[] drawcol;

  public void init()
  {
    System.out.println("LKS Mandelbrot Zoom v0.1");

    drawcol = new Color[64];

    int s = 1;
    double rr=0, gg=0, bb=0;
    for(int i=0; i<64; i++)
    {
      s--;
      if(s <= 0) {
        rr = 0.5 + 4.0*(((i*i*i-5)&15)/15.0);
        gg = 0.5 + 4.0*(((3*i*i+9)&15)/15.0);
        bb = 0.5 + 4.0*(((i*i-i+1)&15)/15.0);
        s = 4 + ((3*i*i-8*i*i*i)&15);
      }
      double r = 128+127*Math.sin(rr*i*3.14159/32.0);
      double g = 128+127*Math.sin(gg*i*3.14159/32.0);
      double b = 128+127*Math.sin(bb*i*3.14159/32.0);
      drawcol[i] = new Color((byte)(r), (byte)(g), (byte)(b));
    }

    im = createImage(im_w, im_h);
    img = im.getGraphics();
  }



  public void start()
  {
    if(runThread == null)
    {
      runThread = new Thread(this);
      runThread.start();
    }
  }



  public void stop()
  {
    if(runThread != null)
    {
      runThread.stop();
      runThread = null;
    }
  }



  public int mandel(double a, double b)
  {
    double x = 0, y = 0;
    double newx = 0;
    int i = 0;

    while(x*x + y*y < 4 && i < 256)
    {
      newx = x*x - y*y + a;
      y = 2*x*y + b;
      x = newx;
      i++;
    }

    return i & 63;
  }

  public void run()
  {
    while(true) {
      try { runThread.sleep(20); } catch (InterruptedException e) { return; }

      if(drawy < im_w)
      {
        int c, cc = -1;

        for(drawx = 0; drawx < im_w; drawx++)
        {
          c = mandel(
            drawx1 + ((drawx2-drawx1)*(drawx+0.0))/im_w,
            drawy1 + ((drawy2-drawy1)*(drawy+0.0))/im_h
          );
          if(cc != c) { 
            img.setColor(drawcol[c]);
            cc = c;
          }
          img.fillRect(drawx, drawy, 1, 1);
        }
        drawy ++;
      }
      repaint();
    }
  }



  public boolean mouseDown(Event evt, int x, int y)
  {
    mouse_oldx = x;
    mouse_oldy = y;
    mouse_x = x;
    mouse_y = y;
    mouse_drag = true;
    return true;
  }


  
  public boolean mouseUp(Event evt, int x, int y)
  {
    mouse_drag = false;

    double x1 = drawx1 + ((drawx2-drawx1)*(mouse_oldx+0.0))/im_w;
    double y1 = drawy1 + ((drawy2-drawy1)*(mouse_oldy+0.0))/im_h;
    double x2 = drawx1 + ((drawx2-drawx1)*(mouse_x   +0.0))/im_w;
    double y2 = drawy1 + ((drawy2-drawy1)*(mouse_y   +0.0))/im_h;

    drawx1 = x1; drawy1 = y1; drawx2 = x2; drawy2 = y2;

    drawx = 0;
    drawy = 0;

    return true;
  }
  


  public boolean mouseDrag(Event e, int x, int y)
  {
    mouse_x = x;
    mouse_y = y;
    repaint();
    return true;
  }



  public void update(Graphics g)
  {
    paint(g);
  }



  public void paint(Graphics g)
  {
    g.drawImage(im, 0, 0, this);
    if(mouse_drag) {
      g.setColor(Color.white);
      g.fillRect(mouse_oldx, mouse_oldy, mouse_x-mouse_oldx, mouse_y-mouse_oldy);
    }
  }

}

