/* 
 * Mandelbrot/Juliaset Viewer - Java Applet
 * 
 * (C) 2007 by Bernhard Pollak
 * made for the fractals lecture 186.186
 * hold by Dr. Traxler at the TU Vienna
 * 
 */

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

public class appletMandelbrotJulia extends Applet implements MouseListener,MouseMotionListener {
  
  private CanvasMJ canvasMJ;  
  
  public void init(){
    setBackground(Color.white); 
    createGUI();    
  }
  
  public void destroy() {
    
  }
  
  public void paint(Graphics g)     { 
    
  } 
  
  private Label createLabel(String text, int fontStyle, int fontSize) {
    Label l=new Label(text);
    l.setFont(new Font("Arial",fontStyle,fontSize));
    return l;
  }
  
  private void createGUI() {
    System.out.println("createGUI");
    
    setLayout(new BorderLayout(10,10));
    
    Panel p1 = new Panel();  
    p1.add(createLabel("Mandelbrot & Juliaset",Font.BOLD,18));
    add("North",p1);    
    
    canvasMJ = new CanvasMJ(); 
    add("Center",canvasMJ);
    canvasMJ.addMouseListener(this);
    canvasMJ.addMouseMotionListener(this);
    
  } 
  
  public void mouseClicked(MouseEvent e)  {
    System.out.println("mouseClicked");
    canvasMJ.mouseClicked(e);
  }
  
  
  public void mousePressed(MouseEvent e)  {
    
  }
  
  public void mouseReleased(MouseEvent e) {
    
  }
  
  public void mouseEntered(MouseEvent e) {    
    
  }
  
  public void mouseExited(MouseEvent e) {   
    
  }
  
  public void mouseMoved(MouseEvent e) {
    System.out.println("mouseMoved");
    canvasMJ.mouseMoved(e);
  }
  
  public void mouseDragged(MouseEvent e) {

  }
    

}



class CanvasMJ extends Canvas {
  
  //private boolean running=true;
  Graphics graphics;  
  Image mBuffer;
  
  int MAXITERATION=30;
  
  double constRe,constIm;
  double centerx,centery;
  double mx,my;

  double virtualPixelSize=0.005;
  double bufferPixelSize=0.0;
  boolean drawMandelbrot=true;  // draw mandelbrot or julia set
  
  int colorstyle=0;
  
  CanvasMJ() {    
    
    update(graphics);
  }
  
  public void mouseClicked(MouseEvent e)  {
    System.out.println("mouseClicked e.getButton():"+e.getButton());
    if (e.getButton()==1) {
      Dimension d=getSize();
      drawMandelbrot=!drawMandelbrot;
      // convert mouse coordinates to real and imag part...
      constRe = (e.getX()-d.width/2)*virtualPixelSize;
      constIm = -(e.getY()-d.height/2)*virtualPixelSize;    
      System.out.println("mouseClicked constRe:"+constRe+"("+e.getX()+") constIm:"+constIm+"("+e.getY()+")");
      repaint();
    }
    if (e.getButton()==3) {     
      colorstyle=(colorstyle+1)%6;
      bufferPixelSize=0.0;
      System.out.println("mouseClicked colorstyle:"+colorstyle);
      repaint();
    }
  }
  
  public void mouseMoved(MouseEvent e) {    
    Dimension d=getSize();    
    // convert mouse coordinates to real and imag part...
    mx = (e.getX()-d.width/2)*virtualPixelSize;
    my = -(e.getY()-d.height/2)*virtualPixelSize;
    
    graphics.setColor(Color.black);
    graphics.fillRect(0,d.height-35,170,35);
    graphics.setColor(Color.red);
    
    Font f = new Font("Arial",0,12);
    graphics.setFont(f);    
    graphics.drawString("Re:"+mx,8,d.height-22);
    graphics.drawString("Im:"+my,8,d.height-7);
  } 
  
  // check if inside julia set
  public int checkJulia(double real, double imag) {
    int i;
    double treal2 =0;   
    for (i = 0; i<MAXITERATION; i++){
      treal2 = real;
      real = real*real - imag*imag + constRe;           
      imag = treal2 * imag * 2 + constIm;         
      if (real*real + imag*imag > 4) return i;            
    }
    return i;
  }
  
  // check if inside mandelbrot set
  public int checkMandelbrot(double real, double imag) {
    int i;
    double treal = 0;
    double timag = 0;
    double treal2 =0;
    for (i = 0; i<MAXITERATION; i++){
      treal = treal2*treal2 - timag*timag + real;
      timag = treal2 * timag * 2 + imag;          
      treal2 = treal;
      if (treal*treal + timag*timag > 4) return i;            
    }
    return i;
  }
  
  public void paint(Graphics g) {
    update(g);
  }
  
  public void drawFractal(Graphics g, Dimension d) {
    int res;
        
    if (g!=null) {
      System.out.println("drawFractal w:"+d.width+" h:"+d.height);
      g.setColor(Color.white);
      for (int x=0;x<d.width;x++) {
        for (int y=0;y<d.height;y++){
          //res = checkC(cx+x*virtualPixelSize,cy-y*virtualPixelSize);
          if (drawMandelbrot) {
            res = checkMandelbrot(centerx+x*virtualPixelSize,centery-y*virtualPixelSize);
          } else {
            res = checkJulia(centerx+x*virtualPixelSize,centery-y*virtualPixelSize);
          }
          switch (colorstyle) {
          case 0: g.setColor(new Color(res%32*8,res%16*16,res%8*32)); break;  // blue
          case 1: g.setColor(new Color(res%16*16,res%32*8,res%8*32)); break;  // violett
          case 2: g.setColor(new Color(res%16*16,res%8*32,res%32*8)); break;  // green
          case 3: g.setColor(new Color(res%32*8,res%8*32,res%16*16)); break;  // mint         
          case 4: g.setColor(new Color(res%8*32,res%16*16,res%32*8)); break;  // brown
          case 5: g.setColor(new Color(res%8*32,res%32*8,res%16*16)); break;  // magenta
          } 
          if (res==MAXITERATION) g.setColor(new Color(0,0,0));
          g.drawLine(x,y,x,y);
        }
      }
    }
  }
  
  public void drawInfo() {
    int i=1;
    int step=15;
    int left=8;
    int top=3;
    
    graphics.setColor(Color.red);
    Font f = new Font("Arial",0,12);
    graphics.setFont(f);
    if (drawMandelbrot) {     
      graphics.drawString("Mandelbrot Set",left,top+i++*step);
      graphics.drawString("Iterations: "+MAXITERATION,left,top+i++*step);
    } else {
      graphics.drawString("Julia Set",left,top+i++*step);
      graphics.drawString("Iterations:"+MAXITERATION,left,top+i++*step);
      graphics.drawString("Re: "+constRe,left,top+i++*step);
      graphics.drawString("Im: "+constIm,left,top+i++*step);
    }
  }
  
  public void update(Graphics g) {  
    setBackground(Color.black);
      
    Dimension d=getSize();
    double screenDim = d.height;
    if (d.width<d.height) screenDim = d.width;
    // calculate the pixelsize of the fractal depending on the panel dimension (so we have a max. sized fractal)
    if (screenDim!=0) virtualPixelSize=(1.0/(screenDim/4.3));
    System.out.println("update d.width:"+d.width+" - virtualPixelSize:"+virtualPixelSize);    
    centerx=-virtualPixelSize*d.width/2;
    centery=virtualPixelSize*d.height/2;

    graphics = getGraphics();
    if (graphics!=null) {   
      if (drawMandelbrot) {
        // has the size changed?
        if ((bufferPixelSize!=0) && (bufferPixelSize==virtualPixelSize) && (mBuffer!=null)) {
          // no: copy from buffer
          System.out.println("update from image buffer...");
          // maybe the fractal size didnĀ“t changed, but the panel size - so we center it new...
          graphics.drawImage(mBuffer, (d.width-mBuffer.getWidth(this))/2, (d.height-mBuffer.getHeight(this))/2, this);          
        } else {
          // yes: draw to buffer and copy from buffer
          mBuffer = createImage(d.width, d.height);
          drawFractal(mBuffer.getGraphics(),d);
          graphics.drawImage(mBuffer, 0, 0, this);
          bufferPixelSize=virtualPixelSize;
        }       
      } else {
        // draw the julia set
        drawFractal(graphics,d);        
      }     
      drawInfo();
    }
  }
  
}