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

public class marbles extends Applet
{
	int width,height;
	Graphics bg;
	Image buf;
	Font font=new Font("TimesRoman",Font.BOLD,56);
	FontMetrics fm;
	Color[] clr={new Color(255,0,0),new Color(255,164,164),new Color(164,0,0),new Color(255,80,0),
		   new Color(0,255,0),new Color(164,255,164),new Color(0,164,0),
		   new Color(0,0,255),new Color(0,0,164),new Color(128,128,255),
		   new Color(65,105,225),new Color(164,0,164),new Color(196,196,255),
		   new Color(255,255,0),new Color(255,255,164),new Color(164,164,0),
		   new Color(255,0,255),new Color(255,128,255),new Color(0,255,255),
		   new Color(164,255,255),new Color(0,164,164),new Color(255,128,64),
		   new Color(196,92,50),new Color(255,255,255)};
	Color bgclr=new Color(255,224,200),hlclr=new Color(240,240,240);
	int[] xi,yi,ci,t;
	int n=0,nn=0,nmax=124,ii,xold,yold,xoff,yoff,cx=100,cy=10,cw,ch,nc;
	int r=20,xleft=60,ytop=60,nnm,np=24;
	int[] px,py,ax,ay;


	public marbles()
	{
	}

	public String getAppletInfo()
	{
		return "Name: marbles\r\n" +
		       "Author: Bob Roesser\r\n";
	}


	public void init()
	{
		width=Integer.parseInt(getParameter("width"));
		height=Integer.parseInt(getParameter("height"));
		xi=new int[nmax];
		yi=new int[nmax];
		ci=new int[nmax];
		ax=new int[np];
		ay=new int[np];
		px=new int[np];
		py=new int[np];
		int r2=4*r/5;
		int x2=71*(r2-r)/100;
		double aa=Math.PI/2.;
		for(int i=0;i<np/2;i++){
			double a=(double)i*Math.PI/(double)(2*np);
			ax[i]=(int)((double)r*Math.cos(a+aa))+r/4;
			ay[i]=-(int)((double)r*Math.sin(a+aa))+r/4;
			ax[np-1-i]=(int)((double)(r)*Math.cos(a+aa))+r/2;
			ay[np-1-i]=-(int)((double)(r)*Math.sin(a+aa))+r/2;
		}
for(int i=0;i<np;i++)System.out.println("i="+i+" ax="+ax[i]+" ay="+ay[i]);
		t=new int[nmax];
		buf=createImage(width,height);
		bg=buf.getGraphics();
		bg.setFont(font);
		fm=bg.getFontMetrics();
		nc=clr.length;
		cw=(width-2*cx)/nc;
		ch=cw;
		nnm=1+2*(width-2*xleft)/(5*r);
		resize(width,height);
	}

	public void destroy()
	{
	}

	
	public void update(Graphics g){paint(g);}
	public void paint(Graphics g){
		int i;
		// sort marbles bottom-left to top-right along diagonals
		for(i=0;i<n;i++)t[i]=i;
		boolean mark=true;
		while(mark){
			mark=false;
			for(i=1;i<n;i++){
				if(xi[t[i-1]]-yi[t[i-1]]>xi[t[i]]-yi[t[i]]){
					int j=t[i];
					t[i]=t[i-1];
					t[i-1]=j;
					mark=true;}}}
		bg.setColor(bgclr);
		bg.fillRect(0,0,width,height/3);
		bg.setColor(bgclr);
		bg.fillRect(0,height/3,width,2*height/3);
// paint color patches
		patches();
// paint marbles
		for(i=0;i<n;i++){paintmarble(bg,xi[t[i]],yi[t[i]],clr[ci[t[i]]]);}
		g.drawImage(buf,0,0,this);
	}

	public void patches(){
		// paint color patches
		for(int i=0;i<nc;i++){
			bg.setColor(clr[i]);
			bg.fillRect(cx+i*cw,cy,cw,ch);}
	}


	public void paintmarble(Graphics g, int x, int y,Color c){
		g.setColor(new Color(128,128,128));
		g.fillOval(x-r+3,y-r+3,2*r,2*r);
		g.setColor(c);
		g.fillOval(x-r,y-r,2*r,2*r);
		for(int i=0;i<np;i++){
			px[i]=ax[i]+x;
			py[i]=ay[i]+y;}
		g.setColor(hlclr);
		g.fillPolygon(px,py,np);
	}

	public void start()
	{
	}
	
	public void stop()
	{
	}


	public boolean mouseDown(Event evt, int x, int y){
		int i;
		ii=-1;
		boolean mark=false;
		if(x>=cx&&x<cx+nc*cw&&y>=cy&&y<=cy+ch){
			if(n<nmax){
				ci[n]=(x-cx)/cw;
				xi[n]=xleft+nn%nnm*5*r/2;
				yi[n++]=ytop+nn/nnm*5*r/2;
				nn++;}
			repaint();
			return true;}
		for(i=0;i<n;i++){
			if(x>xi[i]-r&&x<xi[i]+r&&y>yi[i]-r&&y<yi[i]+r){
				ii=i;
				break;}}
		if(ii>=0){
			xoff=x-xi[ii];
			yoff=y-yi[ii];
			xold=x;
			yold=y;}
		return true;
	}

	public boolean mouseUp(Event evt, int x, int y){
		mousecommon(evt,x,y);
/*		if(ii>=0){
			xi[ii]=x-xoff;
			yi[ii]=y-yoff;
			repaint();
			xold=x;
			yold=y;}*/
		return true;
	}

	public void mousecommon(Event evt, int x, int y){
		if(ii>=0){
			int xx=x-xoff,yy=y-yoff,i,iii=ii,dx=0,dy=0,drr=0;
			boolean mark=true;
				mark=false;
				for(i=0;i<n;i++){
					if(i==iii)continue;
					dx=xx-xi[i];
					dy=yy-yi[i];
					drr=dx*dx+dy*dy;
					if(drr<=4*r*r){
						mark=true;
						break;}}
				if(mark){
					ii=-1;
					double dr=Math.sqrt((double)drr);
					dx=(int)((double)(dx*2*r)/dr);
					dy=(int)((double)(dy*2*r)/dr);
					xx=xi[i]+dx;
					yy=yi[i]+dy;}
				xi[iii]=xx;
				yi[iii]=yy;
				repaint();
				xold=x;
				yold=y;}
	}

	public boolean mouseDrag(Event evt, int x, int y){
		mousecommon(evt,x,y);
		if(ii<0&&y>cy+ch+5)mouseDown(evt,x,y);
		return true;
	}

	public boolean mouseMove(Event evt, int x, int y){
		return true;
	}

	public boolean keyDown(Event evt,int key){
			return true;
	}

}
