/*
Client-side Canvas tag based Identicon rendering code

@author  Don Park
@version 0.2
@date    January 21th, 2007
*/

var patch0 = new Array( 0, 4, 24, 20 );
var patch1 = new Array( 0, 4, 20 );
var patch2 = new Array( 2, 24, 20 );
var patch3 = new Array( 0, 2, 22, 20 );
var patch4 = new Array( 2, 14, 22, 10 );
var patch5 = new Array( 0, 14, 24, 22 );
var patch6 = new Array( 2, 24, 22, 13, 11, 22, 20 );
var patch7 = new Array( 0, 14, 22 );
var patch8 = new Array( 6, 8, 18, 16 );
var patch9 = new Array( 4, 20, 10, 12, 2 );
var patch10 = new Array( 0, 2, 12, 10 );
var patch11 = new Array( 10, 14, 22 );
var patch12 = new Array( 20, 12, 24 );
var patch13 = new Array( 10, 2, 12 );
var patch14 = new Array( 0, 2, 10 );
var patchTypes = new Array( patch0, patch1, patch2, patch3, patch4,
		patch5, patch6, patch7, patch8, patch9, patch10, patch11,
		patch12, patch13, patch14 );
var centerPatchTypes = new Array(0, 4, 8, 15);

function vertices2points(vertices, x, y, scale, offset) {
	var s = "";
	for (var i = 0; i < vertices.length; i++) {
		if (s.length > 0) s += ", ";
		s += "(" + (x + (vertices[i] % 5 * scale) - offset) + "," + (y + (Math.floor(vertices[i] / 5) * scale) - offset) + ")";
	}
	return s;
}

function draw_grid(ctx, x, y, size, parts) {
	ctx.save();
	ctx.fillStyle = "rgb(0,0,0)";
	ctx.fillRect(x, y, size, size);
	ctx.strokeStyle = "rgb(128,128,128)";
	var partsize = size / parts;
	for (var i = 0; i < parts; i++) {
		for (var j = 0; j < parts; j++) {
			ctx.strokeRect(x + i * partsize, y + j * partsize, partsize, partsize);
		}
	}
	ctx.restore();
}
function render_identicon_patch(ctx, x, y, size, patch, turn, invert, foreColor, backColor) {
	patch %= patchTypes.length;
	turn %= 4;
	if (patch == 15) invert = !invert;

	var vertices = patchTypes[patch];
	var offset = size / 2;
	var scale = size / 4;

	ctx.save();

	// paint background
	ctx.fillStyle = invert ? foreColor : backColor;
	ctx.fillRect(x, y, size, size);

	// build patch path
	ctx.translate(x + offset, y + offset);
	ctx.rotate(turn * Math.PI / 2);
	ctx.beginPath();
	ctx.moveTo((vertices[0] % 5 * scale - offset), (Math.floor(vertices[0] / 5) * scale - offset));
	for (var i = 1; i < vertices.length; i++)
		ctx.lineTo((vertices[i] % 5 * scale - offset), (Math.floor(vertices[i] / 5) * scale - offset));
	ctx.closePath();
	
	// offset and rotate coordinate space by patch position (x, y) and
	// 'turn' before rendering patch shape

	// render rotated patch using fore color (back color if inverted)
	ctx.fillStyle = invert ? backColor : foreColor;
	ctx.fill();

	// restore rotation
	ctx.restore();
}

function render_identicon(node, code, size) {
	if (!node || !code || !size) return;
	
	var patchSize = size / 3;
	var middleType = centerPatchTypes[code & 3];
	var middleInvert = ((code >> 2) & 1) != 0;
	var cornerType = (code >> 3) & 15;
	var cornerInvert = ((code >> 7) & 1) != 0;
	var cornerTurn = (code >> 8) & 3;
	var sideType = (code >> 10) & 15;
	var sideInvert = ((code >> 14) & 1) != 0;
	var sideTurn = (code >> 15) & 3;
	var blue = (code >> 16) & 31;
	var green = (code >> 21) & 31;
	var red = (code >> 27) & 31;
	var foreColor = "rgb(" + (red << 3) + "," + (green << 3) + "," + (blue << 3) + ")";
	var backColor = "rgb(255,255,255)";
	
	var ctx = node.getContext("2d");

	// middle patch
	render_identicon_patch(ctx, patchSize, patchSize, patchSize, middleType, 0, middleInvert, foreColor, backColor);
	// side patchs, starting from top and moving clock-wise
	render_identicon_patch(ctx, patchSize, 0, patchSize, sideType, sideTurn++, sideInvert, foreColor, backColor);
	render_identicon_patch(ctx, patchSize * 2, patchSize, patchSize, sideType, sideTurn++, sideInvert, foreColor, backColor);
	render_identicon_patch(ctx, patchSize, patchSize * 2, patchSize, sideType, sideTurn++, sideInvert, foreColor, backColor);
	render_identicon_patch(ctx, 0, patchSize, patchSize, sideType, sideTurn++, sideInvert, foreColor, backColor);
	// corner patchs, starting from top left and moving clock-wise
	render_identicon_patch(ctx, 0, 0, patchSize, cornerType, cornerTurn++, cornerInvert, foreColor, backColor);
	render_identicon_patch(ctx, patchSize * 2, 0, patchSize, cornerType, cornerTurn++, cornerInvert, foreColor, backColor);
	render_identicon_patch(ctx, patchSize * 2, patchSize * 2, patchSize, cornerType, cornerTurn++, cornerInvert, foreColor, backColor);
	render_identicon_patch(ctx, 0, patchSize * 2, patchSize, cornerType, cornerTurn++, cornerInvert, foreColor, backColor);
}

function render_identicon_canvases(prefix) {
	var canvases = document.getElementsByTagName("canvas");
	var n = canvases.length;
	for (var i = 0; i < n; i++) {
		var node = canvases[i];
		if (node.title && node.title.indexOf(prefix) == 0) {
			var code = node.title.substring(prefix.length) * 1;
			var size = node.width;
			render_identicon(node, code, size);
		}
	}
}