/*----------------------------------------------------------------------+
|   Title:  MandelbrotApplet.java                                       |
|                                                                       |
|   Author: David E. Joyce                                              |
|           Department of Mathematics and Computer Science              |
|           Clark University                                            |
|           Worcester, MA 01610-1477                                    |
|           U.S.A.                                                      |                                                                       |
|           http://aleph0.clarku.edu/~djoyce/                           |
|                                                                       |
|   Dates:  April, 1985. Pascal version for textronix terminal          |
|           April, 1987. Added escape, pattern, alternate planes        |
|           August, 1994. C version for CGI web image server            |
|           January, 2003. Java applet version                          |
|                                                                       |
|   Reference: Benoit B. Mandelbrot, "The Fractal Geometry of           |
|           Nature", WH Freeman, 1982.  Chapter 19, pages 180-          |
|           192, especially page 183.			                        |
|                                                                       |
|   Copyright: 1987,1994,2003 by David E. Joyce and Clark University    |
|           Permission to use, copy, and distribute for non-commercial  |
|           purposes is hereby granted without fee, providing that      |
|           the above copyright notice appear in all copies and that    |
|           both the copyright notice and this permission notice        |
|           appear in supporting documentation.                         |
|                                                                       |
|           The software may be modified for your own purposes, but     |
|           modified versions may not be distributed.                   |
|           This software is provided "as is" without any expressed     |
|           or implied warranty.                                        |
+----------------------------------------------------------------------*/

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

public class MandelbrotApplet
       extends Applet
       implements ActionListener, AdjustmentListener, ItemListener,
          WindowListener, MouseListener, MouseMotionListener  {

  MandelbrotColorPlane m;
  ColorPlaneWindow w;

  // parameters
  int parPlane;
  int resolution;
  int wrap;
  int escape;
  int pattern;

  public void init() {
    initializePanels();
    initializeParameters();
    updateStatus();
  } // init

  Panel wholePanel = new Panel();
  Panel controlPanel = new Panel();
  Button resetButton = new Button("Reset");
  Button redrawButton = new Button("Redraw");
  Choice planeChoice = new Choice();
  Label wrapLabel = new Label("",Label.CENTER);
  Scrollbar wrapScrollbar;
  Choice escapeChoice = new Choice();
  Choice patternChoice = new Choice();
  Label statusLabel = new Label();
  Button locationButton = new Button("Lift");
  Frame remoteFrame;

  Label scaleLabel = new Label("",Label.CENTER);
  Scrollbar scaleScrollbar;
  private static final double[] scaleValue =
    {0.02, 0.05, 0.1, 0.25, 0.5, 0.75, 0.9, 1.0,
     1.1, 1.25, 1.5, 2.0, 2.5, 3.0, 4.0, 5.0,
     6.0, 10.0, 20.0, 50.0};
  private static final int 	SCALEDEFAULT = 11;

  Label resLabel = new Label("",Label.CENTER);
  Scrollbar resScrollbar;
  private static final int[] resValue =
    {10, 20, 50, 75, 100, 150, 200, 300, 500, 750,
     1000, 1500, 2000, 3000, 4000, 5000};
  private static final int RESDEFAULT = 1;

  void initializePanels() {
    wholePanel.setLayout(new BorderLayout(5,5));

    controlPanel.setLayout(new GridLayout(15,1,5,5));

    controlPanel.add(resetButton);
    resetButton.addActionListener(this);

    controlPanel.add(redrawButton);
    redrawButton.addActionListener(this);

    controlPanel.add(scaleLabel);
    scaleScrollbar = new Scrollbar(Scrollbar.HORIZONTAL,9,2,0,scaleValue.length+1);
    scaleScrollbar.addAdjustmentListener(this);
    controlPanel.add(scaleScrollbar);

    controlPanel.add(resLabel);
    resScrollbar = new Scrollbar(Scrollbar.HORIZONTAL,0,2,0,resValue.length+1);
    resScrollbar.addAdjustmentListener(this);
    controlPanel.add(resScrollbar);

    controlPanel.add(new Label("Plane:",Label.CENTER));
    planeChoice.addItem("mu");
    planeChoice.addItem("lambda");
    planeChoice.addItem("1/mu");
    planeChoice.addItem("1/(mu+.25)");
    planeChoice.addItem("1/lambda");
    planeChoice.addItem("1/(lambda-1)");
    planeChoice.addItem("1/(mu-1.401)");
    planeChoice.addItemListener(this);
    controlPanel.add(planeChoice);

    controlPanel.add(new Label("Escape:",Label.CENTER));
    escapeChoice.addItem("circle");
    escapeChoice.addItem("square");
    escapeChoice.addItem("strip");
    escapeChoice.addItem("half-plane");
    escapeChoice.addItemListener(this);
    controlPanel.add(escapeChoice);

    controlPanel.add(new Label("Pattern:",Label.CENTER));
    patternChoice.addItem("plain");
    patternChoice.addItem("feathered");
    patternChoice.addItem("binary");
    patternChoice.addItem("grayscale");
    patternChoice.addItem("zebra");
    patternChoice.addItemListener(this);
    controlPanel.add(patternChoice);

    controlPanel.add(wrapLabel);
    wrapScrollbar = new Scrollbar(Scrollbar.HORIZONTAL,0,2,1,12);
    wrapScrollbar.addAdjustmentListener(this);
    controlPanel.add(wrapScrollbar);

    controlPanel.add(locationButton);
    locationButton.addActionListener(this);

    wholePanel.add("West",controlPanel);

    wholePanel.add("South",statusLabel);

    m = new MandelbrotColorPlane(resolution,parPlane,wrap,escape,pattern);
    w = new ColorPlaneWindow(m,0.0,0.0,2.0,2.0);
    w.addMouseMotionListener(this);
    w.addMouseListener(this);

    wholePanel.add(w);
    this.add(wholePanel);
    int width = this.getSize().width - controlPanel.getPreferredSize().width - 10;
    w.setSize(width,0);

    // set up the remote frame for future use
    remoteFrame = new Frame("Mandelbrot");
    remoteFrame.setSize(this.getSize());
    remoteFrame.addWindowListener(this);
  } // initializePanels

  void initializeParameters() {
    w.setScale(scaleValue[SCALEDEFAULT]);
    scaleLabel.setText("scale="+w.getScale());
    scaleScrollbar.setValue(SCALEDEFAULT);
    parPlane = 0;
    planeChoice.select(0);
    m.setParPlane(parPlane);
    resolution = resValue[RESDEFAULT];
    resLabel.setText("resolution="+resolution);
    m.setResolution(resolution);
    resScrollbar.setValue(RESDEFAULT);
    wrap = 1;
    wrapLabel.setText("color wrap="+wrap);
    m.setWrap(wrap);
    wrapScrollbar.setValue(0);
    escape = 0;
    escapeChoice.select(0);
    m.setEscape(escape);
    pattern = 0;
    patternChoice.select(0);
    m.setPattern(pattern);
    w.setCenter(0.0,0.0);
    w.setRadius(2.0);
  }// reset Parameters;

  void updateStatus() {
    statusLabel.setText("r="+w.getRadius()+"  center="+w.getCenter());
  } // updateStatus

  public void actionPerformed(ActionEvent evt) {
    String command = evt.getActionCommand();
    if (command.equals("Reset")) {
      initializeParameters();
      w.repaint();
    } else if (command.equals("Redraw"))
      w.repaint();
    else if (command.equals("Lift")) {
      remoteFrame.add(wholePanel);
      int width = remoteFrame.getSize().width -
         controlPanel.getPreferredSize().width - 10;
      w.setSize(width,0);
      remoteFrame.setVisible(true);
      locationButton.setLabel("Return");
    } else if (command.equals("Return"))
      returnFrame();
    updateStatus();
  } // actionPerformed

  void returnFrame() {
      this.add(wholePanel);
      int width = this.getSize().width - controlPanel.getPreferredSize().width - 10;
      w.setSize(width,0);
      wholePanel.setSize(this.getSize());
      this.validate();
      remoteFrame.setVisible(false);
      locationButton.setLabel("Lift");
  } // returnFrame

  public void itemStateChanged(ItemEvent evt) {
    if (evt.getSource() == planeChoice) {
      int newParPlane = planeChoice.getSelectedIndex();
      // change the center of the window
      Complex z = MandelbrotColorPlane.convert(w.getCenter(),parPlane,newParPlane);
      w.setCenter(z);
      parPlane = newParPlane;
      m.setParPlane(parPlane);
    } else if (evt.getSource() == escapeChoice) {
      escape = escapeChoice.getSelectedIndex();
      m.setEscape(escape);
      w.setChanged();
    } else if (evt.getSource() == patternChoice) {
      pattern = patternChoice.getSelectedIndex();
      m.setPattern(pattern);
      w.setChanged();
    }
    updateStatus();
  } // itemStateChanged


  public void adjustmentValueChanged(AdjustmentEvent e) {
    if (e.getSource() == scaleScrollbar) {
      w.setScale(scaleValue[e.getValue()]);
      scaleLabel.setText("scale="+w.getScale());
    } else if (e.getSource() == resScrollbar) {
      resolution = resValue[e.getValue()];
      resLabel.setText("resolution="+resolution);
      m.setResolution(resolution);
      w.setChanged();
    } else if (e.getSource() == wrapScrollbar) {
      wrap = e.getValue();
      wrapLabel.setText("color wrap="+wrap);
      m.setWrap(wrap);
      w.setChanged();
    }
    updateStatus();
  } // adjustmentValueChanged

  // windowListener methods
  public void windowActivated(WindowEvent e) {}
  public void windowClosed(WindowEvent e) {}
  public void windowClosing(WindowEvent e) { returnFrame();}
  public void windowDeactivated(WindowEvent e) {}
  public void windowDeiconified(WindowEvent e) {}
  public void windowIconified(WindowEvent e) {}
  public void windowOpened(WindowEvent e) {}

  // mouse methods
  public void mouseEntered(MouseEvent e) {
    statusLabel.setText("r="+w.getRadius()+
    "  cursor="+w.convert(e.getX(),e.getY()));
  }

  public void mouseExited(MouseEvent e) {
    updateStatus();
  }

  public void mouseReleased(MouseEvent e) {}

  public void mousePressed(MouseEvent e) {
    updateStatus();
  }

  public void mouseClicked(MouseEvent e) {}

  public void mouseMoved(MouseEvent e) {
    statusLabel.setText("r="+w.getRadius()+
    "  cursor="+w.convert(e.getX(),e.getY()));
  }

  public void mouseDragged(MouseEvent e) {}

} // MandelbrotApplet
