<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Interactor for Chain Reaction</title>
<script src="/socket.io/socket.io.js"></script>
<script src="/common.js"></script>
<script>
var CVSH=500;

var COLOURS=["#00F","#F00","#0CC"];

var socket=io();
var CELLSZ=~~(CVSH/(H+1));
var CVSW=CELLSZ*(W+1);
var CELL0X=~~(CVSW/2-W/2*CELLSZ)+.5,CELL0Y=~~(CVSH/2-H/2*CELLSZ)+.5;
var bd;

var cvs,ctx;

var onturn;

var usercanmove;

function init(){
	cvs=document.getElementById("cvs");
	cvs.width=CVSW;
	cvs.height=CVSH;
	ctx=cvs.getContext("2d");
	cvs.addEventListener("click",function(ev){
		if(!usercanmove)return;
		var bbox=ev.target.getBoundingClientRect();
		var cx=ev.clientX-bbox.left,cy=ev.clientY-bbox.top;
		var x=~~((cx-CELL0X)/CELLSZ),y=~~((cy-CELL0Y)/CELLSZ);
		if(x<0||y<0||x>=W||y>=H)return;
		if(bd[y][x].n&&bd[y][x].c!=onturn)return;
		applymove(W*y+x,onturn);
		socket.emit("usermove",W*y+x);
		usercanmove=false;
		setstatustext("<i>Waiting for other move...</i>");
	});
	onturn=0;
	usercanmove=false;
	bd=emptyboard();
	drawboard(bd,onturn);
	setstatustext("<i>Initialised.</i>");
}

function drawboard(bd,clr){
	var x,y,i,angle,radius;
	ctx.clearRect(0,0,CVSW,CVSH);
	ctx.strokeStyle=COLOURS[+clr];
	ctx.beginPath();
	for(y=0;y<H;y++){
		for(x=0;x<W;x++){
			ctx.moveTo(CELL0X+x*CELLSZ,CELL0Y+y*CELLSZ);
			ctx.lineTo(CELL0X+(x+1)*CELLSZ,CELL0Y+y*CELLSZ);
			ctx.lineTo(CELL0X+(x+1)*CELLSZ,CELL0Y+(y+1)*CELLSZ);
			ctx.lineTo(CELL0X+x*CELLSZ,CELL0Y+(y+1)*CELLSZ);
			ctx.lineTo(CELL0X+x*CELLSZ,CELL0Y+y*CELLSZ);
		}
	}
	ctx.stroke();
	for(y=0;y<H;y++){
		for(x=0;x<W;x++){
			ctx.fillStyle=COLOURS[bd[y][x].c];
			angle=1/bd[y][x].n*2*Math.PI;
			radius=bd[y][x].n==1?0:.15;
			for(i=0;i<bd[y][x].n;i++){
				ctx.beginPath();
				ctx.arc(
					CELL0X+(x+.5+radius*Math.cos(angle*i))*CELLSZ,
					CELL0Y+(y+.5+radius*Math.sin(angle*i))*CELLSZ,
					CELLSZ*.2,0,2*Math.PI,1);
				ctx.fill();
			}
		}
	}
}

function stabiliseanims(bd){
	var anims=[],stage;
	var newbd;
	var x,y,nnei,quo;
	do {
		stage=[];
		newbd=bdcopy(bd);
		for(y=0;y<H;y++){
			for(x=0;x<W;x++){
				nnei=(y>0)+(x>0)+(y<H-1)+(x<W-1);
				if(bd[y][x].n>=nnei){
					quo=~~(bd[y][x].n/nnei);
					newbd[y][x].n-=quo*nnei;
					if(y>0)  {
						newbd[y-1][x].n+=quo; newbd[y-1][x].c=bd[y][x].c;
						stage.push([W*y+x,W*(y-1)+x]);
					}
					if(x>0)  {
						newbd[y][x-1].n+=quo; newbd[y][x-1].c=bd[y][x].c;
						stage.push([W*y+x,W*y+x-1]);
					}
					if(y<H-1){
						newbd[y+1][x].n+=quo; newbd[y+1][x].c=bd[y][x].c;
						stage.push([W*y+x,W*(y+1)+x]);
					}
					if(x<W-1){
						newbd[y][x+1].n+=quo; newbd[y][x+1].c=bd[y][x].c;
						stage.push([W*y+x,W*y+x+1]);
					}
				}
			}
		}
		bd=newbd;
		anims.push([stage,bdcopy(bd)]);
		if(checkwin(bd)!=-1)break;
	} while(stage.length);
	return anims;
}

var applymove_queue=[];
var applymove_busy=false;

function applymove(idx,c){
	assert(idx>=0&&idx<W*H);
	applymove_busy=true;
	bd[~~(idx/W)][idx%W].n++;
	bd[~~(idx/W)][idx%W].c=c;
	drawboard(bd,onturn);
	var anims=stabiliseanims(bd);
	anims.forEach(function(pair,i){
		var stage=pair[0],newbd=pair[1];
		var finalstage=i==anims.length-1;
		setTimeout(function(){
			var time=0;
			var interval=setInterval(function(){
				var i,fx,fy,tx,ty;
				for(i=0;i<stage.length;i++){
					fx=stage[i][0]%W; fy=~~(stage[i][0]/W);
					bd[fy][fx].n--;
				}
				drawboard(bd,onturn);
				for(i=0;i<stage.length;i++){
					fx=stage[i][0]%W; fy=~~(stage[i][0]/W);
					tx=stage[i][1]%W; ty=~~(stage[i][1]/W);
					ctx.fillStyle=COLOURS[bd[fy][fx].c];
					ctx.beginPath();
					ctx.arc(
						CELL0X+(fx*(1-time/10)+tx*time/10+.5)*CELLSZ,
						CELL0Y+(fy*(1-time/10)+ty*time/10+.5)*CELLSZ,
						CELLSZ*.2,0,2*Math.PI,1);
					ctx.fill();
				}
				if(time==10){
					clearInterval(interval);
					bd=newbd;
					drawboard(bd,onturn);
					if(finalstage){
						applymove_busy=false;
						while(applymove_queue.length&&typeof applymove_queue[0]=="function"){
							applymove_queue[0]();
							applymove_queue.shift();
						}
						if(applymove_queue.length){
							setTimeout(function(){
								applymove(applymove_queue[0][0],applymove_queue[0][1]);
								applymove_queue.shift();
							},50);
						}
					}
				}
				time++;
			},20);
		},350*i+1);
	});
}

function queueapplymove(idx,c){
	if(applymove_busy)applymove_queue.push([idx,c]);
	else applymove(idx,c);
}

function getusermove(){
	usercanmove=true;
	setstatustext("<b>Your turn!</b>");
}

function setstatustext(text){
	var elem=document.getElementById("statustext");
	elem.innerHTML=text;
}

function assert(cond){if(!cond)throw new Error("Assertion failed");}


socket.on("emptyboard",function(){
	bd=emptyboard();
});
socket.on("applymove",function(obj){
	queueapplymove(obj.index,obj.player);
});
socket.on("alert",function(text){
	alert(text);
});
socket.on("setonturn",function(player){
	if(applymove_busy)applymove_queue.push(function(){
		onturn=player;
		drawboard(bd,onturn);
	});
	else {
		onturn=player;
		drawboard(bd,onturn);
	}
});
socket.on("getusermove",function(){
	if(applymove_busy)applymove_queue.push(getusermove);
	else getusermove();
});
socket.on("win",function(player){
	setstatustext("<b><i>Player "+(player+1)+" won!</i></b>");
});
</script>
</head>
<body onload="init()">
<h3>Interactor for Chain Reaction</h3>
<canvas id="cvs"></canvas><br>
<span id="statustext"></span>
</body>
</html>