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

public class Sand extends Applet implements Runnable {
	private Image image = null;
	private MemoryImageSource source = null;
	private volatile Thread thread = null;
	private int dropx = -1, dropy = -1;
	private int HEIGHT = 64;
        //private int r = 0xFF, g = 0xCC, b = 0x00;
	
	public void start() {
		(thread = new Thread( this )).start();
	}

	protected void processMouseMotionEvent( MouseEvent me ) {
		if ( me.getID() == MouseEvent.MOUSE_MOVED ) {
			synchronized( this ) {
				dropx = me.getX();
				dropy = me.getY();
			}
		}
	}
        
        protected void processMotionEvent( MouseEvent me ) {
		if ( me.getID() == MouseEvent.MOUSE_EXITED ) {
			synchronized( this ) {
				dropx = -1;
				dropy = -1;
			}
		}
	}
	
	public void run() {
                //setCursor( Cursor.getPredefinedCursor( Cursor.CROSSHAIR_CURSOR ) );
                enableEvents( AWTEvent.MOUSE_EVENT_MASK );
                enableEvents( AWTEvent.MOUSE_MOTION_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 ( dropx >= 0 && dropx < width && dropy >= 0 && dropy < height && Math.random() < 0.5 )
                                    stateNow[ dropy*width + dropx ] += HEIGHT;
					
                                for ( int i = 0; i < stateNext.length; i++ ) stateNext[ i ] = 0;
                                for ( int j = 0; j < height; j++ ) {
                                        for ( int i = 0; i < width; i++ ) {
                                                int state = stateNow[ j*width + i ];
                                                int numNeighbours = 8;
                                                if ( numNeighbours <= state  ) {
                                                        //state -= 8;
                                                        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;
                                                                        stateNext[ ny*width + nx ]++;
                                                                        state--;
                                                                }
                                                        }
                                                }
                                                stateNext[ j*width + i ] += state;
                                        }
                                }
                                
                                int[] tmp = stateNow;
                                stateNow = stateNext;
                                stateNext = tmp;
                                
                                for ( int i = 0; i < stateNow.length; i++ ) {
					int state = stateNow[ i ];
                                        //if ( state > 255 ) System.out.println( "Too beacoup " + state + " " + stateNow[ i ] );
                                        //if ( state < 0 ) System.out.println( "Too small " + state + " " + stateNow[ i ] );
                                        //sum += stateNow[ i ];
					state = Math.min( Math.max( state, 0 ), 255 );
                                        int r = (state+20)*(state), g = (state+5)*(state), b = 2*state;
                                        r = Math.min( 255, r );
                                        b = Math.min( 255, b );
                                        g = Math.min( 255, g );
					pixels[ i ] = 0xFF000000 | (r << 16) | (g << 8) | (b);
				}
                                //System.out.println( sum );
				source.newPixels();
				repaint();
			}
			
			try {
				Thread.sleep( 20 );
			}
			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 );
		}
	}
}