// Michael Tartaglia
// 18 July 2002
// Nested Boxes: program creates circles moving in circles and so on recursively

import java.awt.Graphics;
import java.awt.*;
import java.applet.Applet;

public class NestedCircles extends Applet {
	public Image backBuffer, nameBuffer;		// IMAGE BUFFER
	public Graphics bufferPaint, namePaint;	// IMAGE PKGS
	public int width = 150,					// WIDTH OF PRIMARY CIRCLE
				  boxes = 4,					// NUMBER OF CIRCLES (DEPTH OF RECURSION)
	           theta,							// PLACEMENT OF CIRCLES (RADIANS)
				  maxBoxes = boxes;			// MAXIMUM DEPTH OF RECURSION
	public double deltaRadius = 2.4;		// RADIUS RATIO OF PARENT TO CHILD (2.4 : 1)
	public boolean go;			// LOOP CHECK BOOLEAN
	public Color[] colors = {new Color(0,0,180),new Color(120,120,220),
	                         new Color(220,220,255),new Color(220,220,220)};	// CIRCLE COLORS

	// CONSTRUCTOR
	public NestedCircles() {}

	public void init() {
		backBuffer = this.createImage(width,width);	// IMAGE BUFFER
		bufferPaint = backBuffer.getGraphics();

		// CREATING NAME PLATE
		nameBuffer = this.createImage(width,24);
		namePaint = nameBuffer.getGraphics();
		namePaint.setColor(Color.white);
		namePaint.fillRect(0,0,width-1,23);
		namePaint.setColor(Color.gray);
		namePaint.setFont(new Font("Arial",Font.BOLD,11));
		namePaint.drawString("Nested Circles",3,11);
		namePaint.setColor(Color.black);
		namePaint.setFont(new Font("Arial",Font.PLAIN,10));
		namePaint.drawString("by M Tartaglia",75,21);
		namePaint.drawRect(0,0,width-1,23);

		setBackground(Color.white);	// SET BG COLOR
		go = true;
	}
	public void stop() {go = false;}
	public void destroy() {stop();}

	public void update(Graphics g) {paint(g);}
	public void paint(Graphics g) {
		if (theta == 0) theta = 360;		// I.E., NO ZERO DEGREES
		else --theta;							// DECREASE ANGLE
		
		// DRAW CIRCLES TO THEIR BUFFER
		drawCircles(bufferPaint, width, boxes, 1,1, theta);

		g.drawImage(backBuffer,1,1,this);			// DRAW CIRCLE BUFFER IMAGE
		g.drawImage(nameBuffer,1,width+1,this);	// DRAW NAMEPLATE BUFFER IMAGE

		if (go) {	// LOOP
			try {Thread.sleep(500);repaint();}
			catch (InterruptedException ie) {}
		}
	}

	public void drawCircles(Graphics g,
									int curWidth,		// CURRENT WIDTH OF CIRCLE
									int curCircle,		// CURRENT CIRCLE # (LEVEL OF RECURSION #)
									int lastNX,			// LAST NESTED X POSITION
									int lastNY,			// LAST NESTED Y POSITION
									int curTheta) {	// RADIAN OF CIRCLE'S ORIGIN
		int x = lastNX, y = lastNY;		// POINTS OF CIRCLE PARENT'S IMAGE ORGIN
		if (curCircle == boxes) {
			// SET CIRCLE COLORS
			g.setColor(Color.white);
			g.fillRect(0,0,width+1,width+1);
			g.setColor(colors[curCircle%colors.length]);
			g.fillOval(0,0,curWidth-1,curWidth-1);
			g.setColor(Color.black);
			g.drawOval(0,0,curWidth-1,curWidth-1);
			
			// DRAW THE THREE NESTED CIRCLES
			drawCircles(g, (int)(curWidth/deltaRadius), curCircle-1, x,y, curTheta);
			drawCircles(g, (int)(curWidth/deltaRadius), curCircle-1, x,y, curTheta+45);
			drawCircles(g, (int)(curWidth/deltaRadius), curCircle-1, x,y, curTheta+90);

		} else if (curCircle > 0) {
			int n = 0;
			n = (int)((curWidth*deltaRadius) - curWidth)/2;
			x = lastNX + (int)(Math.cos(curTheta*180/Math.PI)*n) + n;
			y = lastNY + (int)(Math.sin(curTheta*180/Math.PI)*n) + n;
			g.setColor(colors[curCircle%colors.length]);
			g.fillOval(x,y,curWidth-1,curWidth-1);
			g.setColor(Color.black);
			g.drawOval(x,y,curWidth-1,curWidth-1);
			drawCircles(g, (int)(curWidth/deltaRadius), curCircle-1, x,y, -curTheta);
			drawCircles(g, (int)(curWidth/deltaRadius), curCircle-1, x,y, -(curTheta+45));
			drawCircles(g, (int)(curWidth/deltaRadius), curCircle-1, x,y, -(curTheta+90));
		}
		g.drawRect(0,0,width-1,width);
	}

}
