import java.applet.*;
import java.util.*;
import java.io.*;
import java.net.*;
import java.awt.*;
import java.awt.image.ColorModel;
import java.awt.image.MemoryImageSource;

/* portions of this code were adapted from the DitherTest applet */
/* fractal faulting codes adapted from Usenet and published references
 *   - Basic faulting on a plane adapted from 'faultmap' by Aurel Balmosan
 *     (aurel@xylo.owl.de) -- some significant changes made
 */

public class FaultingApplet extends Applet implements Runnable
{
    /************************************************************
     * Boilerplate methods to handle painting and initialization
     ************************************************************/

    private int width = 256;
    private int height = 256;
    private double scalefactor = 1.0;
    private int[][] heightfield;
    private Random rgen;
    private Image img;
    private boolean started;

    public boolean handleEvent(Event evt)
    {
	if (evt.id == Event.WINDOW_DESTROY)  System.exit(0);
	return super.handleEvent(evt);
    }
    public boolean action( Event evt, Object arg)
    {
	return true;
    }
    String calcString = "Calculating...";
    public void paint(Graphics g)
    {
	int w = size().width;
	int h = size().height;
	if (img == null) {
	    super.paint(g);
	    g.setColor(Color.black);
	    FontMetrics fm = g.getFontMetrics();
	    int x = (w - fm.stringWidth(calcString))/2;
	    int y = h/2;
	    g.drawString(calcString, x, y);
	} else {
	    g.drawImage(img, 0, 0, w, h, this);
	}
    }
    public void init()
    {
	int w = Integer.parseInt(getParameter("width"));
	if (w<=0 || w>256) w=width;
	width=w;
	height=w;
	scalefactor = 256/width;
        rgen = new Random();
	started = false;
	start();
    }
    synchronized void BuildImage()
    {
        /* build the image for display -- greyscale */
	int pixels[];
	int i, j, a, index = 0, min, max;
	// calculate range of values in heightfield
	min = heightfield[0][0];
	max = heightfield[0][0];
	for (i=0;i max) max = heightfield[i][j];
	    }
	}
	scalefactor = 255.0 / (max-min);
	pixels = new int[width * height];
	for (i=0;i255) a=255;
		/*if (a>255) a=255;*/
		pixels[index++] = (255 << 24) | (a << 16) | (a << 8) | a;
	    }
	}

	img = createImage(new MemoryImageSource(width, height,
						ColorModel.getRGBdefault(),
						pixels, 0, width));
	repaint();
    }

    /************************************************************
     * Thread methods to handle processing in the background
     ************************************************************/

    Thread kicker;

    public /*synchronized*/ void start() {
	if (!started) {
	    started = true;
	    kicker = new Thread(this);
	    kicker.start();
	} else if ((kicker != null) && (kicker.isAlive()))
	    kicker.resume();
    }

    public /*synchronized*/ void stop() {
	try {
	    if ((kicker != null) && (kicker.isAlive())) {
		kicker.suspend();
	    }
	} catch (Exception e) {
	}
    }

    public void restart() {
	try {
	    if (kicker != null) {
		kicker.stop();
	    }
	} catch (Exception e) {
	}
	kicker = null;
	img = null;
	started = false;
	start();
    }

    public void run()
    {
	Thread me = Thread.currentThread();
	me.setPriority(4);
	DoFaulting(10000);
    }

    /************************************************************
     * Faulting implementations
     ************************************************************/

    private int Rand0(int range)
    {
	double d = rgen.nextDouble();
	int i = (int)(d*range);
	if (i<0) i = -i;
	return i;
    }
    
    synchronized void DoFaulting(int iterations)
    {
	double  pfi, cp, sp;
	int     i, h, j, x, y;
	int     px, py, tx, ty, wmod=width, hmod=width;
    
	/* Get the memory (widthxwidth bytes) */
	heightfield = new int[width][width];
	/* base value = 0 */
	for (i=0;i0)
	{
	    px=Rand0(wmod); py=Rand0(hmod);
	    pfi=rgen.nextDouble()*2.0*Math.PI;
	    cp=Math.cos(pfi); sp=Math.sin(pfi);
	    h=((pfi>Math.PI/2) && (pfi<=Math.PI+Math.PI/2)) ? -1 : 1;
	    // I'll ignore any horizontal or vertical cuts -- CDB
	    if (sp>-0.01 && sp<0.01)   // line essentially horizontal
	    {
		iterations++;
	    }
	    else if (cp>-0.01 && cp<0.01)   // line essentially vertical
	    {
		iterations++;
	    }
	    else   // walk from selected point, setting faultline
	    {
		double dx;
		double mx = cp/sp;  // dx for unit y
		for (y=py+1,dx=px+mx,x=(int)dx; 
			y=0 && x=0 && x>=0 && x=0))
		    for (;y>=0;y--)
		    {
			heightfield[0][y]+=h;
		    }
	    }
	}
	
	for (y=0; y