// Java (Applet) Fractal Explorer
// (c) 1997 by Nils Pipenbrinck
// fixed in 2005 by doj after decompilation of .class files with jad

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

public class FractalExplorer
    extends Applet
    implements MouseListener, MouseMotionListener, ActionListener
{
    int height;
    int width;
    int x1;
    int y1;
    int x2;
    int y2;
    Image image;
    private MandelState M;
    private Stack History;
    private Button RedrawButton;
    private Button BackButton;
    private Button ChangeButton;
    private Panel ButtonPanel;
    private ImagePanel Viewer;

    public FractalExplorer()
    {
        M = new MandelState(-2D, 2D, -1.5D, 1.5D, 0.0D, 0.0D, true);
        History = new Stack();
        RedrawButton = new Button("Redraw");
        BackButton = new Button("Back");
        ChangeButton = new Button("Change");
        ButtonPanel = new Panel(new GridLayout(8, 1));
        Viewer = new ImagePanel();
    }

    public void init()
    {
        addMouseListener(this);
        addMouseMotionListener(this);
        setLayout(new BorderLayout());
        add("East", ButtonPanel);
        add("Center", Viewer);
        Viewer.addNotify();
        BackButton.addActionListener(this);
        BackButton.setEnabled(false);
        ButtonPanel.add(BackButton);
        RedrawButton.addActionListener(this);
        ButtonPanel.add(RedrawButton);
        ChangeButton.addActionListener(this);
        ChangeButton.setActionCommand("Change");
        ChangeButton.setLabel("Julia");
        ButtonPanel.add(ChangeButton);
    }

    public void startNewImage(MandelState mandelstate)
    {
        Rectangle rectangle = Viewer.getBounds();
        if(rectangle == null)
            return;
        height = rectangle.height;
        width = rectangle.width;
        if(image != null)
        {
            if((image.getHeight(this) != height) | (image.getWidth(this) != width))
                image = createImage(width, height);
        }
	else
        {
            image = createImage(width, height);
        }
        Viewer.theImage = image;
        MandelRenderer Calc = new MandelRenderer(image.getGraphics(), width, height, mandelstate);
	showStatus("Calculation time: " + (double)Calc.milliseconds / 1000D + "ms");
	Viewer.paint(Viewer.getGraphics());
    }

    public void start()
    {
        startNewImage(M);
    }

    /*
    public void destroy()
    {
    }
    */

    public void drawImage(Graphics g)
    {
        if(image == null)
        {
            startNewImage(M);
        }
	else
        {
            Viewer.paint(Viewer.getGraphics());
        }
    }

    public void actionPerformed(ActionEvent actionevent)
    {
        if(actionevent.getActionCommand() == "Redraw")
            startNewImage(M);
        if(actionevent.getActionCommand() == "Back")
        {
            M = (MandelState)History.pop();
            BackButton.setEnabled(!History.isEmpty());
            startNewImage(M);
        }
        if(actionevent.getActionCommand() == "Change")
        {
            History.push(M);
            BackButton.setEnabled(!History.isEmpty());
            M = (MandelState)M.clone();
            M.switchMode();
            ChangeButton.setLabel(M.isMandel ? "Julia" : "Mandel");
            startNewImage(M);
        }
    }

    public void mousePressed(MouseEvent mouseevent)
    {
        mouseevent.consume();
        x1 = mouseevent.getX();
        y1 = mouseevent.getY();
        y2 = y1;
        x2 = x1;
        Viewer.R = new Rectangle(x1, y1, 0, 0);
        Viewer.drawDrag = true;
    }

    public void mouseReleased(MouseEvent mouseevent)
    {
        mouseevent.consume();
        Viewer.drawDrag = false;
        if((x1 != x2) & (y1 != y2))
        {
            History.push(M);
            BackButton.setEnabled(!History.isEmpty());
            Rectangle rectangle = Viewer.getBounds();
            double d = (M.right - M.left) / (double)rectangle.width;
            double d1 = (M.bottom - M.top) / (double)rectangle.height;
            M = new MandelState(M.left + d * (double)x1, M.left + d * (double)x2, M.top + d1 * (double)y1, M.top + d1 * (double)y2, M.other_r, M.other_i, M.isMandel);
        }
        startNewImage(M);
    }

    public void mouseDragged(MouseEvent mouseevent)
    {
        mouseevent.consume();
        Rectangle rectangle = Viewer.getBounds();
        Viewer.R.width = mouseevent.getX() - x1;
        Viewer.R.height = (Viewer.R.width * rectangle.height) / rectangle.width;
        x2 = x1 + Viewer.R.width;
        y2 = y1 + Viewer.R.height;
        Graphics g = getGraphics();
        if(g != null)
            drawImage(g);
    }

    public void mouseMoved(MouseEvent mouseevent)
    {
    }

    public void mouseClicked(MouseEvent mouseevent)
    {
    }

    public void mouseEntered(MouseEvent mouseevent)
    {
    }

    public void mouseExited(MouseEvent mouseevent)
    {
    }
}
