/* Viewing Sources */


/*
Nhan Le
<applet code="SpinningSquaresApplet" width="400" height="400"></applet>
*/

import java.applet.*;
import java.awt.*;
import java.util.*;

class RectangularBounds{
	private int x0, y0, x1, y1;
	public RectangularBounds(int x0, int y0, int x1, int y1){
		this.x0 = x0;
		this.y0 = y0;
		this.x1 = x1;
		this.y1 = y1;
	}
	public int getLeftBound(){return x0;}
	public int getRightBound(){return x1;}
	public int getTopBound(){return y0;}
	public int getBottomBound(){return y1;}
}
class Vector2D{
	private int xcomp;
	private int ycomp;
	private int mag;
	public Vector2D(double radiandirection, int mag){
		this.xcomp = (int)(mag*Math.cos(radiandirection));
		this.ycomp = (int)(-mag*Math.sin(radiandirection));
		this.mag = mag;		
	}
	public int getXcomp(){return xcomp;}
	public int getYcomp(){return ycomp;}
	public int getMag(){return mag;}
	public void setXcomp(int xcomp){this.xcomp=xcomp;}
	public void setYcomp(int ycomp){this.ycomp=ycomp;}
}

class BouncingObject{
	private int x,y;
	private Vector2D v;
	RectangularBounds b;
	public BouncingObject(int x, int y, Vector2D v, RectangularBounds b){
		this.x = x;
		this.y = y;
		this.v = v;
		this.b = b;
	}
	public int getX(){return x;}
	public int getY(){return y;}
	public void translate(){
		if(x+v.getXcomp()<b.getLeftBound())
			v.setXcomp(v.getXcomp()*-1);
		else if(x+v.getXcomp()>b.getRightBound())
			v.setXcomp(v.getXcomp()*-1);
		x+=v.getXcomp();


		if(y+v.getXcomp()<b.getTopBound())
			v.setYcomp(v.getYcomp()*-1);
		else if(y+v.getXcomp()>b.getBottomBound())
			v.setYcomp(v.getYcomp()*-1);
		y+=v.getYcomp();
	}
	public void setXY(int x,int y){this.x=x;this.y=y;}
}

class SpinningSquare extends BouncingObject{
	private double radianposition;
	private int radius;//technically the 1/2 the hypotenuse of a square
	private double rotationaldelta;
	public SpinningSquare(int x, int y, Vector2D v, RectangularBounds b, double radianposition, int radius){
		super(x,y,v,b);
		this.radianposition = radianposition;
		this.radius = radius;
		rotationaldelta = Math.abs(((double)((((new Random()).nextInt())%15))/10.0))+0.1;
	}
	public double getRadianPosition(){return radianposition;}
	public double getRadius(){return radius;}
	public void update(){
		radianposition += rotationaldelta;
		translate();
		if(radianposition>6.28)
			radianposition = 0.00;
	}
}

public class SpinningSquaresApplet extends Applet implements Runnable{
	private Graphics gbuffer;
	private Image ibuffer;
	private Thread t;
	private SpinningSquare[] squares;
	private Random random;
	static final int numberofsquares = 15;
	static final int appletwidth = 400;
	static final int appletheight = 400;
	static final int maxspeed = 12;
	static final int minspeed = 4;
	static final int squareradius = 30;//technically 1/2 the hypotenuse
	
	private float colorcounter=1.00f;
	private int colorshift = 0;
	private float red,gre,blu;
	public void init(){
		ibuffer = createImage(appletwidth,appletheight);
		random = new Random();
		red = colorcounter;
		gre = 0.0f;
		blu = 0.0f;
		squares = new SpinningSquare[numberofsquares];
		for(int i=0; i<squares.length; i++)
			squares[i] = new SpinningSquare(
				appletwidth/2,
				appletheight/2,
				new Vector2D(
					(double)(i*.5),
					Math.abs(random.nextInt()%(maxspeed-minspeed))+minspeed
				),
				new RectangularBounds(
					0+squareradius,
					0+squareradius,
					appletwidth-squareradius,
					appletheight-squareradius
				),
				(double)(((int)(random.nextInt()))%628),
				squareradius
			);
		t = new Thread(this);
		t.start();
	}
	public void run(){
		while(true){
			try{
				repaint();
				Thread.sleep(35);
				for(int i=0; i<squares.length; i++)
					squares[i].update();
				colorcounter-=0.005f;
				if(colorcounter<=0.40f){
					colorcounter = 1.00f;
					colorshift++;
					colorshift=(colorshift==3?0:colorshift);
					for(int i=0; i<squares.length; i++)
						squares[i].setXY(appletwidth/2,appletheight/2);
				}
				switch(colorshift){
				case 0: red = colorcounter; break;
				case 1: gre = colorcounter; break;
				case 2: blu = colorcounter; break;
				}				
			}
			catch(Exception e){
				//e.printStackTrace();
			}
		}
	}
	public void paint(Graphics g){
		if(gbuffer==null)
			gbuffer = ibuffer.getGraphics();
		clearScreen(gbuffer);
		drawSquares(gbuffer);
		g.drawImage(ibuffer, 0,0, this);
	}
	public void clearScreen(Graphics g){
		g.setColor(Color.black);
		g.fillRect(0,0,appletwidth,appletheight);
	}
	public void drawSquares(Graphics g){
		for(int i=0; i<squares.length; i++){
			g.setColor(new Color(red,gre,blu));
			g.drawLine(
				squares[i].getX()+(int)(squares[i].getRadius()*Math.cos(squares[i].getRadianPosition())),
				squares[i].getY()+(int)(-squares[i].getRadius()*Math.sin(squares[i].getRadianPosition())),
				squares[i].getX()+(int)(squares[i].getRadius()*Math.cos(squares[i].getRadianPosition()+1.57)),
				squares[i].getY()+(int)(-squares[i].getRadius()*Math.sin(squares[i].getRadianPosition()+1.57))
			);
			g.drawLine(
				squares[i].getX()+(int)(squares[i].getRadius()*Math.cos(squares[i].getRadianPosition()+1.57)),
				squares[i].getY()+(int)(-squares[i].getRadius()*Math.sin(squares[i].getRadianPosition()+1.57)),
				squares[i].getX()+(int)(squares[i].getRadius()*Math.cos(squares[i].getRadianPosition()+3.14)),
				squares[i].getY()+(int)(-squares[i].getRadius()*Math.sin(squares[i].getRadianPosition()+3.14))
			);
			g.drawLine(
				squares[i].getX()+(int)(squares[i].getRadius()*Math.cos(squares[i].getRadianPosition()+3.14)),
				squares[i].getY()+(int)(-squares[i].getRadius()*Math.sin(squares[i].getRadianPosition()+3.14)),
				squares[i].getX()+(int)(squares[i].getRadius()*Math.cos(squares[i].getRadianPosition()+4.71)),
				squares[i].getY()+(int)(-squares[i].getRadius()*Math.sin(squares[i].getRadianPosition()+4.71))

			);
			g.drawLine(
				squares[i].getX()+(int)(squares[i].getRadius()*Math.cos(squares[i].getRadianPosition()+4.71)),
				squares[i].getY()+(int)(-squares[i].getRadius()*Math.sin(squares[i].getRadianPosition()+4.71)),
				squares[i].getX()+(int)(squares[i].getRadius()*Math.cos(squares[i].getRadianPosition())),
				squares[i].getY()+(int)(-squares[i].getRadius()*Math.sin(squares[i].getRadianPosition()))
			);
		}
	}
	public void update(Graphics g){
		paint(g);
	}
}
/* sources by Nhan Le */
/* [email protected] */
/* [email protected] */
/* [email protected] */
/* if you find the sources useful or if you want to make any modifications, just email me */
/* html generated using GNU source-highlight 1.8 =-) */