import java.awt.Graphics;
import java.awt.Image;
import java.awt.Dimension;
import java.awt.image.MemoryImageSource;
import java.awt.event.MouseEvent;
import java.awt.AWTEvent;
import java.applet.Applet;

public class ExLattice extends Applet implements Runnable {
	private Image image = null;
	private MemoryImageSource source = null;
	private volatile Thread thread = null;
	private volatile boolean initialise = true;
        private volatile double probability = 0.75;
	private int a = 2, b = 2;
        private int[] colors = { 0xFF000000, 0xFFFFFFFF, 0xFFCC6600 };
	
	public void start() {
		(thread = new Thread( this )).start();
	}

	protected void processMouseEvent( MouseEvent me ) {
		if ( me.getID() == MouseEvent.MOUSE_RELEASED ) {
			synchronized( this ) {
				initialise = true;
				probability = (me.getY()/(double)getSize().height);
			}
		}
	}
	
	public void run() {
		enableEvents( AWTEvent.MOUSE_EVENT_MASK );
		Dimension size = getSize();
		int width = size.width;
		int height = size.height;
		int[] pixels = new int[ width*height ];
		int[] stateNow  = new int[ width*height ];
		int[] stateNext = new int[ width*height ];
		synchronized( this ) {
			source = new MemoryImageSource( width, height, pixels, 0, width );
			source.setFullBufferUpdates( true );
			source.setAnimated( true );
			image = createImage( source );
		}
		
		while( thread == Thread.currentThread() ) {
		
			synchronized( this ) {
				if ( initialise ) {
					initialise = false;
					for ( int i = 0; i < stateNow.length; i++ ) 
						stateNow[ i ] = (Math.random() < probability)? 0 : (Math.random() < 0.5? 1 : 2 );
					//System.out.println( "Initialised" );
				}
				else {
					for ( int j = 0; j < height; j++ ) {
						for ( int i = 0; i < width; i++ ) {
							int state = stateNow[ j*width + i ];
							int sumNeighbours = 0;
							for ( int x = i-1; x <= (i+1); x++ ) {
								int nx = (x+width)%width;
								for ( int y = j-1; y <= (j+1); y++ ) {
									if ( x == i && y == j )
										continue;
									int ny = (y+height)%height;
                                                                        int statexy = stateNow[ ny*width + nx ];
                                                                        if ( statexy == 1 )
                                                                            sumNeighbours += statexy;
								}
							}
							
							int nextState = 0;
							if ( state == 1 )
								nextState = 2;
							else if ( state == 0 && a <= sumNeighbours && sumNeighbours <= b )
								nextState = 1;
							stateNext[ j*width + i ] = nextState;
						}
					}
					int[] tmp = stateNow;
					stateNow = stateNext;
					stateNext = tmp;
					//System.out.println( "Updated" );
				}
				for ( int i = 0; i < stateNow.length; i++ ) {
					pixels[ i ] = colors[ stateNow[ i ] ];
				}
				source.newPixels();
				repaint();
			}
			
			try {
				Thread.sleep( 40 );
			}
			catch( Exception e ) {
			}
		}
		
	}
	
	public void stop() {
		thread = null;
	}
	
	public void update( Graphics g ) {
		paint( g );
	}
	
	public synchronized void paint( Graphics g ) {
		if ( image != null ) {
			g.drawImage( image, 0, 0, this );
		}
	}
}