import java.awt.*;
import java.awt.Graphics;
import java.applet.*;

public class MovingLines
extends      Applet
implements   Runnable
{
    // This implementation demonstrates using double-buffering
    // and a separate animation thread to achieve smooth
    // flicker-free animation on the screen.  That's not the
    // fastest way to write thie particular demo:  Using XORPaint
    // directly to the screen (no offscreen buffer) would be
    // -much- faster in this particular case:
    Thread  animator   = null;
    boolean keepMoving = false;

    // Our offscreen buffer:
    Image   screenbuffer;
    int     height;
    int     width;

    // Location for endpoints of line.
    static final int  X1 = 0;
    static final int  Y1 = 1;
    static final int  X2 = 2;
    static final int  Y2 = 3;
    int[] endpoint = new int[4];

    // Speed and direction for endpoints of line.
    int[] speed = new int[4];

    // Set of lines currently visible:
    static final int VISIBLE_LINES = 128;
    int[][] line = new int[4][ VISIBLE_LINES ];
    int thisline = 0;

    public void init() {

	// Using relatively prime numbers maximizes
	// time until display repeats:
	speed[X1]    =  2;   speed[Y1]    =  3;
	speed[X2]    =  5;   speed[Y2]    =  7;

        endpoint[X1] =  1;   endpoint[Y1] =  1;
        endpoint[X2] =  1;   endpoint[Y2] =  1;

	for     (int e = 4;               e --> 0;  ) {
            for (int i = VISIBLE_LINES;   i --> 0;  ) {
                line[e][i] = -1;
	    }
        }
	keepMoving = true;
    }

    public void start() {
	animator = new Thread(this);
	animator.start();
	keepMoving = true;
    }

    public void stop() {
	keepMoving = false;
	if (animator != null)   animator.stop();
	animator = null;
    }

    public void run() {
        while (keepMoving) {
	    checkBuffer();
	    updateLineEndpoints();
	    noteNewLine();
	    redrawBuffer();
	    paint(getGraphics());
        }
    }

    void checkBuffer() {
	// Re/create our offscreen buffer if
	// we haven't made one yet or it is
	// the wrong size, presumably due to
	// user resizing us while we run:
	Dimension d  = this.size();
	if (screenbuffer == null
	||  d.width      != width
	||  d.height     != height
	){
	   screenbuffer = createImage( d.width, d.height );
	   width        = d.width;
	   height       = d.height;
	}
    }

    void updateCoord( int coord, int limit ) {

        int nextloc = endpoint[coord] + speed[coord];
        if (nextloc < 0
        ||  nextloc >= limit
        ){
	    // Bounce off wall:
	    speed[coord] = -speed[coord];

	    if (nextloc < 0)    nextloc = -nextloc;
	    else                nextloc = limit - (nextloc-limit);
	}
	endpoint[coord] = nextloc;
    }

    void updateLineEndpoints() {
	// Update line endpoints: 
	updateCoord( X1, width );	updateCoord( Y1, height );
	updateCoord( X2, width );	updateCoord( Y2, height );
    }

    void noteNewLine() {
	// Save new lineseg in point[] buffer:
	if (++thisline == VISIBLE_LINES)   thisline = 0;
        line[X1][thisline] = endpoint[X1];  line[Y1][thisline] = endpoint[Y1];
        line[X2][thisline] = endpoint[X2];  line[Y2][thisline] = endpoint[Y2];
    }

    void redrawBuffer() {
	Graphics g = screenbuffer.getGraphics();
	g.clearRect( 0,0, width,height );
	for (int i = VISIBLE_LINES;   i --> 0;   ) {
	    if (line[X1][i] != -1) {
                g.drawLine(
		    line[X1][i], line[Y1][i],
		    line[X2][i], line[Y2][i]
		);
    }   }   }

    public void paint(Graphics g) {
        if (screenbuffer != null) {
	    g.drawImage( screenbuffer, 0, 0, this );
	}
    }
}
