// decompiled from the old .class file I had
// with a few tiny mods

import java.applet.Applet;
import java.applet.AppletContext;
import java.awt.*;
import java.io.PrintStream;

public class mandelbrot extends Applet
{

    public boolean handleEvent(Event event)
    {
        switch(event.id)
        {
        case 401: // Event.KEY_PRESS
        case 403: // Event.KEY_ACTION
            switch(event.key)
            {
            default:
                break;
            case ']':
              max_i+=max_i/10;
              rendered=0; 
              repaint(); 
              break;
            case '[':
              max_i-=max_i/10;
              if (max_i < 1) max_i=1;
              rendered=0; 
              repaint(); 
              break;

            case 43: // '+'
            case 61: // '='
                max_i++;
                rendered = 0;
                repaint();
                break;

            case 45: // '-'
                max_i--;
                if(max_i == 0)
                    max_i = 1;
                rendered = 0;
                repaint();
                break;

            case 114: // 'r'
                rendered = 0;
                max_i = 16;
                xmin = -2.25D;
                ymin = -1.3125D;
                step = 3.5D / (double)screen_width;
                repaint(); 
                return true;
            }
            return true;

        case 501: // Event.MOUSE_DOWN
            mouseDown(event, event.x, event.y);
            return true;

        case 502: // Event.MOUSE_UP
            mouseUp(event, event.x, event.y);
            return true;

        case 506: // Event.MOUSE_DRAG
            mouseDrag(event, event.x, event.y);
            return true;
        }
        return false;
    }

    public void init()
    {
        screen_width = 512;
        screen_height = (screen_width * 3) / 4;
        xmin = -2.25D;
        ymin = -1.3125D;
        step = 3.5D / (double)screen_width;
        busy = 0;
        max_i = 16;
        rendered = 0;
        start_x = start_y = end_x = end_y = -1;
        myColors = new Color[256];
        frame_buffer = new short[screen_width * screen_height];
        for(int i = 0; i < 255; i++)
            myColors[i] = new Color(i, i/2, i/2);

    }

    public void mandel(double d, double d1, double d2)
    {
        int l = 0;
        busy = 1;
        int j = 0;
        for(double d4 = d1; j < screen_height; d4 += d2)
        {
            int i = 0;
            for(double d3 = d; i < screen_width; d3 += d2)
            {
                int k = (iterate(d3, d4, d3, d4) * 255) / max_i;
                graph.setColor(myColors[k]);
                frame_buffer[l++] = (short)k;
                graph.fillRect(i, j, 1, 1);
                i++;
            }

            j++;
        }

        busy = 0;
        rendered = 1;
    }

    public int iterate(double d, double d1, double d2, double d3)
    {
        for(int i = 0; i < max_i; i++)
        {
            double d4 = d;
            double d5 = d1;
            d = (d4 * d4 - d5 * d5) + d2;
            d1 = 2D * d4 * d5 + d3;
            if(d * d + d1 * d1 > 4D)
                return i;
        }

        return 0;
    }

    void update_fb()
    {
        int i = 0;
        for(int j = 0; j < screen_height; j++)
        {
            for(int k = 0; k < screen_width; k++)
            {
                graph.setColor(myColors[frame_buffer[i++]]);
                graph.fillRect(k, j, 1, 1);
            }

        }

    }

    public boolean mouseDown(Event event, int i, int j)
    {
        if(busy != 0)
        {
            return true;
        } else
        {
            start_x = Math.min(Math.max(i, 0), screen_width - 1);
            start_y = Math.min(Math.max(j, 0), screen_height - 1);
            return true;
        }
    }

    public boolean mouseDrag(Event event, int i, int j)
    {
        if(busy != 0)
            return true;
        if(start_x != -1 && start_y != -1)
        {
            if(end_x != -1 && end_y != -1)
            {
                int k = Math.min(start_x, end_x);
                int l = start_y * screen_width;
                for(; k < Math.max(start_x, end_x); k++)
                {
                    graph.setColor(myColors[frame_buffer[k + l]]);
                    graph.fillRect(k, start_y, 1, 1);
                }

                k = Math.min(start_x, end_x);
                l = end_y * screen_width;
                for(; k < Math.max(start_x, end_x); k++)
                {
                    graph.setColor(myColors[frame_buffer[k + l]]);
                    graph.fillRect(k, end_y, 1, 1);
                }

                k = Math.max(start_y + 1, end_y + 1) * screen_width;
                for(int i1 = Math.min(start_y, end_y) * screen_width; i1 < k; i1 += screen_width)
                {
                    graph.setColor(myColors[frame_buffer[i1 + start_x]]);
                    graph.fillRect(start_x, i1 / screen_width, 1, 1);
                }

                for(int j1 = Math.min(start_y, end_y) * screen_width; j1 < k; j1 += screen_width)
                {
                    graph.setColor(myColors[frame_buffer[j1 + end_x]]);
                    graph.fillRect(end_x, j1 / screen_width, 1, 1);
                }

            }
            if(end_x < start_x)
                end_x = start_x;
            end_x = Math.min(Math.max(i, 0), screen_width - 1);
            end_y = start_y + ((end_x - start_x) * 3) / 4;
            end_y = Math.min(Math.max(end_y, 0), screen_height - 1);
            graph.setColor(Color.white);
            graph.drawRect(start_x, start_y, end_x - start_x, end_y - start_y);
        }
        return true;
    }

    public boolean mouseUp(Event event, int i, int j)
    {
        if(busy != 0)
            return true;
        if(i != start_x && j != start_y)
        {
            ymin += step * (double)start_y;
            xmin += step * (double)start_x;
            step *= i - start_x;
            step /= screen_width;
            start_x = -1;
            start_y = -1;
            end_x = end_y = -1;
            rendered = 0;
            repaint();
        }
        return true;
    }

    public void paint(Graphics g)
    {
        if(paint_xx == 0)
            graph = g.create();
        paint_xx = 1;
        if(rendered == 0)
        {
            System.out.print("Rendering...");
            getAppletContext().showStatus("min x: " + xmin + ", min y: " + ymin + ", max i: " + max_i + ", step: " + step);
            mandel(xmin, ymin, step);
            getAppletContext().showStatus("min x: " + xmin + ", min y: " + ymin + ", max i: " + max_i + ", step: " + step);
            System.out.println("Done");
            System.out.println("Quick Help: use '-' and '+' to set the maximum iterations.");
            System.out.println("Quick Help: use 'r' to reset to program defaults");
            System.out.println("Quick Help: use the mouse to select zoom area");
            System.out.println("Image Specs: min x: " + xmin + ", min y: " + ymin + ", max i: " + max_i + ", step: " + step);
            return;
        } else
        {
            getAppletContext().showStatus("min x: " + xmin + ", min y: " + ymin + ", max i: " + max_i + ", step: " + step);
            update_fb();
            getAppletContext().showStatus("min x: " + xmin + ", min y: " + ymin + ", max i: " + max_i + ", step: " + step);
            System.out.println("Restored image from framebuffer\n");
            return;
        }
    }

    public mandelbrot()
    {
    }

    int screen_width;
    int screen_height;
    int start_x;
    int start_y;
    int end_x;
    int end_y;
    int busy;
    Color myColors[];
    int rendered;
    short frame_buffer[];
    int max_i;
    Graphics graph;
    double xmin;
    double ymin;
    double step;
    int paint_xx;
}
