var Board, Cell, Color;
function buildBoard() {
	var board = document.createElement("table");
	document.body.appendChild(board);
	//board.className = "c1i1 c2i2 c3i3 c4i4 c5i5 c6i6";
	Board = new Array(9);
	Cell  = new Array(9);
	Color = new Array(9);
	for (var a = 0; a < 9; a++) {
		Board[a] = new Array(9);
		Cell[a]  = new Array(9);
		var otr = document.createElement("tr");
		if (a==2||a==5) otr.className = "b";
		board.appendChild(otr);
		for (var b = 0; b < 9; b++) {
			var otd = document.createElement("td");
			if (b==2||b==5) otd.className = "b";
			var itb = document.createElement("table");
			itb.id = "i"+a+"i"+b;
			Cell[a][b] = itb;
			reset(a,b);
			var newScope = function(a,b,d) { return function() {Board['in']=[a,b];} };
			otd.onmouseover = newScope(a,b,d);
			otd.onmouseout  = function(){Board['in'] = [];};
			otd.appendChild(itb);
			otr.appendChild(otd);
			for (var c = 7; c > 0; c-=3) {
				var itr = document.createElement("tr");
				itb.appendChild(itr);
				for (var d = c; d < c+3; d++) {
					var itd = document.createElement("td");
					itd.appendChild( document.createTextNode(d) );
					itr.appendChild(itd);
					itd.className = "i"+d;
					itd.onclick = click;
					itd.ondblclick = dblclick;
				}
			}
		}
	}
	var colors = document.createElement("ol");
	colors.id = "colors";
	for (var i = 0; i < 7; i++) {
		var patch = document.createElement("li");
		//patch.appendChild( document.createTextNode("") );
		patch.className = "c"+i;
		var newScope = function(i) { return function() {Board['in']=[i,'c'];} };
		patch.onmouseover = newScope(i);
		patch.onmouseout  = function(){Board['in'] = [];};
		colors.appendChild(patch);
	}
	var build = document.createElement("label");
	build.appendChild(  document.createElement("input") );
	build.appendChild( document.createTextNode("Create") );
	build.firstChild.type = "checkbox";
	build.firstChild.id   = "build";
	build.firstChild.checked = 1;
	var solveit = document.createElement("button");
	solveit.type = "button";
	solveit.appendChild( document.createTextNode("Solve It") );
	solveit.onclick = function(){solve(); build.firstChild.checked=0;};
	var resetit = document.createElement("button");
	resetit.type = "button";
	resetit.appendChild( document.createTextNode("Restart") );
	resetit.onclick = function(){clear(0);};
	var clearit = document.createElement("button");
	clearit.type = "button";
	clearit.appendChild( document.createTextNode("Clear All") );
	clearit.onclick = function(){clear(1); build.firstChild.checked=1;};
	document.body.appendChild(colors);
	document.body.appendChild(build);
	document.body.appendChild(solveit);
	document.body.appendChild(resetit);
	document.body.appendChild(clearit);
	document.onkeypress = keyHandler;
}

function keyHandler(e) {
	var x = Board['in'][0], y = Board['in'][1], k = e.charCode || e.keyCode;
	if (x==undefined || y==undefined) return;
	//alert(k);
	if (48 < k && k <=57) {
		if (y == 'c') toggleColor(k-48,x);
		else if (document.getElementById("build").checked) fixVal(x,y,k-48);
		else setVal(x,y,k-48,2);
	}
	else if (y == 'c') { return; }
	else if (k == 8 || k == 46) {
		reset(x,y);
	}
}

function toggleColor(num, c) {
	var s = [];
	Color[num-1] = Color[num-1] == c ? null : c;
	for (var i=1; i<10; i++)
		if (Color[i-1])
			s.push("c"+Color[i-1]+"i"+i);
	//alert(num + " => color " + c + "\n" + s.join(" "));
	document.body.firstChild.className = s.join(" ");
}

function dblclick(e) {
	var q = (this.parentNode.parentNode.id + this.className).split("i");
	var x=q[1],y=q[2],v=q[3];
	if (e.ctrlKey && !Board[x][y].f && candidates(x,y,[]).length == 1)
		reset(x,y);
}
function click(e) {
	if (document.getElementById("build").checked) return;
	var q = (this.parentNode.parentNode.id + this.className).split("i");
	var x=q[1],y=q[2],v=q[3];
	if (e.shiftKey) {
		if (Board[x][y].f) unfix(x,y);
		else fixVal(x,y,v);
	}
	else if (Board[x][y].f) {
		elim(x,y,Board[x][y].f);
	}
	else {
		var c = candidates(x,y,[]);
		if (c.length == 1) elim(x,y,c[0]);
		//else setVal(x,y,v,2);
	}
}

function reset(x,y) {
	Board[x][y] = {
		f: 0, c: 0,
		v: [,1,1,1 ,1,1,1 ,1,1,1 ]
	};
	computeClass(x,y);
}
function setVal(x,y,v,op) {
	var c = candidates(x,y,[]);
	switch(op) {
		case 3:
			for (var q=9; q>0; q--)
				Board[x][y].v[q] = (q==v);
			break;
		case 2:
			if (c[0] == v && c.length == 1) break;
			Board[x][y].v[v] ^= 1; break;
		case 0:
			if (c.length == 1) break;
		default:
			Board[x][y].v[v] = op;
			c = candidates(x,y,[]);
	}
	if (document.getElementById("build").checked) return;
	computeClass(x,y);
	if (c.length == 1 && !Board[x][y].c)
		elim(x,y,c[0]);
}

function fixVal(x,y,v) {
	Board[x][y].f = v;
	setVal(x,y,v,3);
	computeClass(x,y);
}
function unfix(x,y) {
	Board[x][y].f = 0;
	computeClass(x,y);
}

function candidates(x,y,rv) {
	for (q=1;q<=9;q++)
		if (Board[x][y].v[q]) {
			if (rv.push) rv.push(q);
			else rv[q] = q;
		}
	return rv;
}
function computeClass(x,y) {
	var s = [];
	for (q=1;q<=9;q++)
		if (Board[x][y].v[q])
			s.push("o"+q);
	if (Board[x][y].f)
		s = [ "g" + Board[x][y].f ];
	Cell[x][y].className = s.join(" ");
	if (Cell[x][y].parentNode)
		Cell[x][y].parentNode.className = Board[x][y].c ?	"cleared" : "";
}
function elim(a,b,v) {
	var q = [
		[0,0,0,0,0,0,0,0,0,0],
		[0,0,0,0,0,0,0,0,0,0],
		[0,0,0,0,0,0,0,0,0,0],
		new Array(10),
		new Array(10),
		new Array(10)
	];
	Board[a][b].c = v;
	for (var x=0;x<9;x++) {
		if (x!=a) setVal(x,b,v,0);

		var c = candidates(x,b,[]);
		for (var i = 0; i < c.length; i++) {
			q[0][c[i]]++;
			q[3][c[i]] = [x,b];
		}
	}
	for (var y=0;y<9;y++) {
		if (y!=b) setVal(a,y,v,0);

		var c = candidates(a,y,[]);
		for (var i = 0; i < c.length; i++) {
			q[1][c[i]]++;
			q[4][c[i]] = [a,y];
		}
	}
	for   (var j = x = Math.floor(a/3)*3; x<j+3; x++)
		for (var k = y = Math.floor(b/3)*3; y<k+3; y++) {
			if (x!=a || y!=b) setVal(x,y,v,0);

			var c = candidates(x,y,[]);
			for (var i = 0; i < c.length; i++) {
				q[2][c[i]]++;
				q[5][c[i]] = [x,y];
			}
		}
	//alert(["at (",a,b,") group count for 5 is", q[2][5], "found at", q[5][5][0], q[5][5][1]].join(" "));
	for (var m = 0; m<3; m++)
		for (var n = 9; n>0; n--)
			if (q[m][n] == 1)
				setVal(q[m+3][n][0], q[m+3][n][1], n, 3);
}
function solve() {
	var f = [];
	for (var x=0;x<9;x++)
	for (var y=0;y<9;y++)
		if (Board[x][y].f) f.push(x,y);
	while (f.length) {
		y = f.pop(); x = f.pop();
		elim(x,y,Board[x][y].f);
	}
}
function clear(q) {
	for (var x=0;x<9;x++)
	for (var y=0;y<9;y++)
		if (!q && Board[x][y].f) {
			var f = Board[x][y].f;
			reset(x,y);
			fixVal(x,y,f);
		}
		else {
			reset(x,y);
		}
}
