
letters  = {
'a' : [0,0,0,224,240,496,496,440,920,1020,1020,2044,1550,3598,3590,0],
'b' : [0,0,0,2032,4080,3120,3120,3888,4080,8176,7216,6192,7216,8176,4080,0],
'c' : [0,0,0,4064,8176,7224,6200,24,24,24,24,6168,7224,8176,4064,0],
'd' : [0,0,0,2040,4088,3608,7192,7192,6168,7192,7192,7192,3608,4088,2040,0],
'e' : [0,0,0,8176,8176,48,48,48,4080,4080,48,48,48,8176,8176,0],
'f' : [0,0,0,4080,4080,48,48,48,2032,2032,48,48,48,48,48,0],
'g' : [0,0,0,4064,8176,14392,14392,24,24,15896,15896,12344,14392,16368,16352,0],
'h' : [0,0,0,6192,6192,6192,6192,6192,8176,8176,6192,6192,6192,6192,6192,0],
'i' : [0,0,0,384,384,384,384,384,384,384,384,384,384,384,384,0],
'j' : [0,0,0,3072,3072,3072,3072,3072,3072,3072,3072,3168,3680,4064,2016,0],
'k' : [0,0,0,3608,1816,920,984,504,248,504,952,1944,1816,3608,7704,0],
'l' : [0,0,0,48,48,48,48,48,48,48,48,48,48,4080,4080,0],
'm' : [0,0,0,14392,14392,15480,15480,15480,16120,14040,14040,14296,14296,13208,13208,0],
'n' : [0,0,0,6256,6256,6384,6384,6640,7088,7088,7984,7728,7728,7216,7216,0],
'o' : [0,0,0,4064,8176,14392,14392,12312,12312,12312,12312,14392,14392,8176,4064,0],
'p' : [0,0,0,4080,8176,7216,6192,7216,7728,4080,1008,48,48,48,48,0],
'q' : [0,0,0,2032,4088,7196,7196,6156,6156,6156,6156,7964,7964,8184,16368,6144],
'r' : [0,0,0,4088,4088,3096,3096,3864,4088,2040,3608,3608,3096,3096,7192,0],
's' : [0,0,0,1008,2040,3608,3608,248,1016,2016,3840,3612,3612,2040,2032,0],
't' : [0,0,0,8176,8176,768,768,768,768,768,768,768,768,768,768,0],
'u' : [0,0,0,6192,6192,6192,6192,6192,6192,6192,6192,6192,7280,8176,4064,0],
'v' : [0,0,0,7180,7196,3100,3608,1592,1840,1904,880,992,992,480,448,0],
'w' : [0,0,0,25027,29127,29671,29670,13158,13166,16254,7804,7740,7740,7740,3096,0],
'x' : [0,0,0,3612,3640,1904,1008,992,448,480,992,1904,1848,3644,7196,0],
'y' : [0,0,0,3598,3612,1852,952,1008,496,224,192,192,192,192,192,0],
'z' : [0,0,0,8160,8160,7168,3584,1792,1920,896,448,224,240,8176,8176,0],
'!' : [0,0,0,384,384,384,384,384,384,384,384,384,0,384,384,0],
'@' : [0,0,0,8160,16376,30780,28636,61422,60534,52790,58934,58934,30518,32766,16382,28],
'£' : [0,0,0,4032,4064,3168,96,96,496,496,96,96,112,4080,4080,0],
'$' : [0,128,992,2032,3760,3760,176,496,2016,3968,3712,3248,3760,2032,2016,128],
'%' : [0,0,0,3196,3836,1772,2028,1020,1020,16304,32704,30400,30432,32352,15920,0],
'^' : [0,0,0,448,960,992,1888,1648,0,0,0,0,0,0,0,0],
'&' : [0,0,0,992,1008,880,1008,992,496,3576,4024,3864,3864,8184,8176,0],
'*' : [0,0,0,192,1008,1008,480,480,320,0,0,0,0,0,0,0],
'(' : [0,0,0,768,896,384,448,192,192,192,192,192,192,192,448,384],
')' : [0,0,0,224,192,448,384,896,896,896,768,896,896,896,384,448],
'_' : [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
'+' : [0,0,0,0,0,384,384,384,4080,4080,384,384,384,0,0,0],
'}' : [0,0,0,480,480,448,384,384,896,896,896,384,384,384,384,448],
'{' : [0,0,0,896,896,384,384,448,448,224,224,448,448,384,384,384],
'|' : [0,0,0,384,384,384,384,384,384,384,384,384,384,384,384,384],
'"' : [0,0,0,1728,1728,1728,1728,0,0,0,0,0,0,0,0,0],
':' : [0,0,0,0,0,0,384,384,0,0,0,0,0,384,384,0],
'?' : [0,0,0,2016,4080,3632,3632,3584,1792,1920,896,384,384,384,384,0],
'>' : [0,0,0,0,0,112,496,2016,3840,3840,2016,496,112,0,0,0],
'<' : [0,0,0,0,0,3584,3968,992,240,240,1008,3968,3584,0,0,0],
'~' : [0,0,0,4080,4080,1552,0,0,0,0,0,0,0,0,0,0],
'1' : [0,0,0,3072,3840,3968,3456,3072,3072,3072,3072,3072,3072,3072,3072,0],
'2' : [0,0,0,2016,4080,3696,3120,3584,3840,1920,960,480,240,4080,4080,0],
'3' : [0,0,0,992,2032,1584,1552,1920,1984,3968,3584,3120,3632,2032,2016,0],
'4' : [0,0,0,1792,1792,1920,1984,1728,1760,1648,1584,4080,4080,1536,1536,0],
'5' : [0,0,0,2032,2032,48,48,2032,2032,3632,3584,3632,3632,2032,992,0],
'6' : [0,0,0,2016,2032,3696,48,2032,2032,3632,3632,3632,3696,2032,2016,0],
'7' : [0,0,0,4064,4064,3072,3584,1536,1792,1792,768,896,384,384,448,0],
'8' : [0,0,0,2016,2032,1648,1648,2032,992,2032,3696,3632,3632,4080,2016,0],
'9' : [0,0,0,992,2032,3632,3632,3632,4080,4064,4032,3632,1584,2032,992,0],
'0' : [0,0,0,992,2032,3696,3632,3632,3120,3120,3632,3632,3696,2032,992,0],
'-' : [0,0,0,0,0,0,0,0,0,0,960,960,0,0,0,0],
'=' : [0,0,0,0,0,0,4080,4080,0,0,4080,4080,0,0,0,0],
']' : [0,0,0,480,480,384,384,384,384,384,384,384,384,384,384,384],
'[' : [0,0,0,960,960,192,192,192,192,192,192,192,192,192,192,192],
'\\' : [0,0,0,96,96,96,224,192,192,192,384,384,384,896,768,0],
'\'' : [0,0,0,384,384,384,384,0,0,0,0,0,0,0,0,0],
';' : [0,0,0,0,0,0,384,384,0,0,0,0,0,384,384,384],
'/' : [0,0,0,768,896,384,384,384,192,192,192,224,96,96,96,0],
'.' : [0,0,0,0,0,0,0,0,0,0,0,0,0,384,384,0],
',' : [0,0,0,0,0,0,0,0,0,0,0,0,0,896,896,896],
'`' : [0,0,0,224,448,384,0,0,0,0,0,0,0,0,0,0]
};


$(document).ready(function(){

	pixelCanvas = $('#pixelCanvas');
	canvasContext = document.getElementById('pixelCanvas').getContext('2d');
	row = new Array;
	blocks = new Array;
	blocksSequence = new Array;
	targetColour = new Colour(255, 0, 0);
	colToUse = new Colour(222, 222, 222);
	baseColour = new Colour( 20, 20, 20 );
	spirals = Array();
	lastX = -1; // Last hit coords
	lastY = -1;
	colourMode = true;
	animators = Array();
	message = '';
	originX = 350;
	originY = 350;

	grid = new Grid;
	grid.init();

	pixelCanvas.mousemove( function(e) {

			var x = e.pageX - $(this).offset().left - 102;
			var y = e.pageY - $(this).offset().top - 102;

			x = Math.floor( x / grid.totalBlockWidth );
			y = Math.floor( y / grid.totalBlockWidth );

			// Check we're not out of bounds
			if (x > (grid.cols - 1) || y > (grid.rows -1)) return;
			if (x < 0 || y < 0) return;
			
			if ( lastX != x || lastY != y ){
				grid.blocks[y][x].hit();
				lastX = x;
				lastY = y;
			}	
	});

	pixelCanvas.click(function(e) {
			


			var x = e.pageX - $(this).offset().left - 102;
			var y = e.pageY - $(this).offset().top - 102;

			x = Math.floor( x / grid.totalBlockWidth );
			y = Math.floor( y / grid.totalBlockWidth );

			// Check we're not out of bounds
			if (x > (grid.cols - 1) || y > (grid.rows -1)) return;
			if (x < 0 || y < 0) return;

			if (x==0 && y==0) { // If you click the top left, it starts a spiral
			 spiral = new Spiral;
			}
			else if (x== (grid.cols - 1)  && y==(grid.rows - 1)) { // bottom right adds multiple
				autoAdd( 50 );
			}
			else if (x==0 && y==15) { // bottom left changes colour mode
				colourMode = (colourMode == true) ? false : true;
			}
			else if (x== (grid.cols - 1)  && y== 0) { // top right rotates grid
				gridRotate = 0.2;
			}
			else 	grid.blocks[y][x].hit();
	});
	
	
	$(document).keypress( function(e) {
	// press return to play the message
	if (e.which == 13 && message != '')  {
		messageAnimation = new StartMessage(message);
		animators.push(messageAnimation);
		message = '';
		return;
	}

	// Other letters go into the queue
	// Ensure any previous messages are stopped
	if (typeof messageAnimation != 'undefined') {
		messageAnimation.stop();
		delete messageAnimation;
	}

	renderLetter(String.fromCharCode(e.which));
	message += String.fromCharCode(e.which);
	
})


animators.push(new StartMessage('mesmerizer!'));
	t = setInterval('tick()', 30);

	
   
});

function autoAdd( num) {
	for (index = 0; index < num; index ++) {

		blockNum = rand( grid.blocksSequence.length );
		grid.blocksSequence[blockNum].hit();
	}
}


function tick() {

	if (typeof gridRotate == 'undefined') gridRotate = 0;
	canvasContext.clearRect(0, 0, 700, 700);
	canvasContext.save();
		canvasContext.translate( 350, 350  );
		if (gridRotate > 0) { 
			canvasContext.rotate( ( Math.PI / 180 ) * gridRotate );
			gridRotate += 0.2;
			if (gridRotate > 360) gridRotate = 0;
		}

	 for (block = 0; block < grid.blocksSequence.length; block ++) {
		 grid.blocksSequence[block].magic();
		 grid.blocksSequence[block].draw();
	 }
	 canvasContext.restore();
}

function averageColours(col1, col2) {
	//return {r: Math.round((col1.r + col2.r) / 2), g: Math.round((col1.g + col2.g) / 2), b: Math.round((col1.b + col2.b) / 2)};
	newCol = new Colour;
	if (col1.r < col2.r) newCol.r = col1.r + 1;
	else if (col1.r > col2.r) newCol.r = col1.r -1;
	else newCol.r = col1.r;

	if (col1.g < col2.g) newCol.g = col1.g + 1;
	else if (col1.g > col2.g) newCol.g = col1.g -1;
	else newCol.g = col1.g;

	if (col1.b < col2.b) newCol.b = col1.b + 1;
	else if (col1.b > col2.b) newCol.b = col1.b -1;
	else newCol.b = col1.b;

	return newCol;
}

function rand ( n )
{
  return ( Math.floor ( Math.random ( ) * n) );
}

function Block( context, x, y, grid ) {

	this.neighbours = Array();
	this.colour = getColour();
	this.nextColour = this.colour;
	this.ink = 0;
	this.lastSizeDiff = 0;
	this.x = x;
	this.y = y;
	this.ctx = context;
	this.rotate = 0;
	this.grid = grid;
	this.xPixels = x * grid.totalBlockWidth;
	this.yPixels = y * grid.totalBlockWidth;

	this.setNeighbours = function( neighbours ) {
		this.neighbours = neighbours;
	}
	
	this.setColour = function( newCol ) {
		this.colour.r = newCol.r;
		this.colour.g = newCol.g;
		this.colour.b = newCol.b;
	}


	this.magic = function() {

		this.setColour(this.nextColour);

		// Work out which neighbour has the most ink
		var bestNeighbour = this.neighbours[0];
		for (index = 1; index < this.neighbours.length; index ++) {
			if ( this.neighbours[index].ink > bestNeighbour.ink ) bestNeighbour = this.neighbours[index];
		}

		// Only do something if the best neighbour has more ink than me
		if (bestNeighbour.ink > this.ink && bestNeighbour.ink > 1) {
			this.setColour(averageColours( this.colour, bestNeighbour.colour )) ;
			this.ink = Math.round(bestNeighbour.ink * 0.7) ;
			bestNeighbour.ink = bestNeighbour.ink - Math.round(this.ink / 50);
			if (bestNeighbour.ink < 0) bestNeighbour.ink = 0;
		}	
		else if (this.ink > 0) this.ink --;

		// If the ink is 0, return to white
		if (this.ink == 0) this.setColour(averageColours( this.colour, baseColour));

		// Change the size of the el
		sizeDiff = Math.round( 15 * (this.ink / this.grid.maxInk) );
		this.lastSizeDiff = sizeDiff;
	}

	this.draw = function() {

		var ctx = this.ctx;

		borderColour = new Colour(this.colour.r, this.colour.g, this.colour.b);
		borderColour.add(20);
		
		ctx.fillStyle = this.colour.toRgba( 1 );
		ctx.strokeStyle = 'rgba(255,255,255, 0.2)';

		ctx.save();

		ctx.translate( (this.xPixels) + this.grid.halfBlockWidth -248, (this.yPixels) + this.grid.halfBlockWidth -248 );
		if (this.rotate > 0) ctx.rotate( ( Math.PI / 180 ) * this.rotate );
		ctx.fillRect ( -this.grid.halfBlockWidth, -this.grid.halfBlockWidth, this.grid.blockWidth , this.grid.blockWidth );
	//ctx.fillRect ( -15, -15, 30 , 30 );

		sizeDiff = Math.round( (Math.floor( this.grid.blockWidth / 2 )) * (this.ink / this.grid.maxInk) );

		ctx.lineWidth = sizeDiff;

		if (sizeDiff > 0) ctx.strokeRect ( -this.grid.halfBlockWidth + (sizeDiff / 2), -this.grid.halfBlockWidth + (sizeDiff / 2), this.grid.blockWidth - (sizeDiff), this.grid.blockWidth - (sizeDiff) );
		if (this.rotate > 0) 	this.rotate += 10;
		if (this.rotate > 90) this.rotate = 0;
		ctx.restore();

	}

	this.hit = function() {
		this.setColour(getColour());
		this.ink = 200;
		this.rotate = 1;
	}

}


function Colour( r, g, b ) {
	this.r = r;
	this.g = g;
	this.b = b;

	this.add = function( num ) {
		this.r += num;
		this.g += num;
		this.b += num;
		if (this.r > 255) r = 255;
		if (this.g > 255) g = 255;
		if (this.b > 255) b = 255;
	}

	this.toRgba = function( alpha ) {
		return 'rgba(' + this.r + ', ' + this.g + ', ' + this.b + ', ' + alpha + ')';
	}
}




function Spiral() {
	this.x = 0;
	this.y = 0;
	this.direction = 0;
	this.timer = null;
	this.upperLimitX = 15;
	this.upperLimitY = 15;
	this.lowerLimitX = 0;
	this.lowerLimitY = 1;

	this.tick = function() {
				if (this.x == 7 && this.y == 8) {
			this.x = 0;
			this.y = 0;
			this.upperLimitX = 15;
			this.upperLimitY = 15;
			this.lowerLimitX = 0;
			this.lowerLimitY = 1;
			this.direction = 0;
		}

		grid.blocks[this.y][this.x].hit();



		if (this.direction == 0) {
			this.x++;
			if (this.x > this.upperLimitX) {
				this.direction = 1;
				this.x = this.upperLimitX;
				this.upperLimitX --;
			}
		}

		if (this.direction == 1) {
			this.y++;
			if (this.y > this.upperLimitY) {
				this.direction = 2;
				this.y = this.upperLimitY;
				this.upperLimitY --;
			}
		}

		if (this.direction == 2) {
			this.x--;
			if (this.x < this.lowerLimitX) {
				this.direction = 3;
				this.x = this.lowerLimitX;
				this.lowerLimitX ++;
			}
		}

		if (this.direction == 3) {
			this.y--;
			if (this.y < this.lowerLimitY) {
				this.direction = 0;
				this.y = this.lowerLimitY;
				this.lowerLimitY ++;
			}
		}
	}

	this.stop = function() {
		clearInterval(this.timer);
	}

	var self= this;
	this.timer = setInterval( function() {self.tick();}, 50);

}


function getColour() {
	if (colourMode) {
			if (colToUse.r == targetColour.r && colToUse.g == targetColour.g && colToUse.b == targetColour.b) targetColour = new Colour(rand(255), rand(255),rand(255));
			colToUse = averageColours( colToUse, targetColour );
		}
		else colToUse = new Colour(rand(255), rand(255),rand(255));
		return colToUse;
}


function renderLetter(letter) {
	toRender = letters[letter];
	colour = getColour();
		for (rows = 0; rows < 16; rows ++) {
			rowTotal = 0;
			for (cols = 0; cols < 16; cols ++ ) {
				 if ((toRender[rows] & Math.pow(2, cols)) > 0) {
					 grid.blocks[rows][cols].hit();
				 }
			}
		}
}

function StartMessage(message) {
	this.msgIndex = 0;
	this.timer = null;
	
	if (typeof message == 'undefined') this.message = $('#message').val().toLowerCase();
	else this.message = message;

	var self = this;

	this.timer = setInterval(function() {self.tick();}, 300);

	this.tick = function() {
		
		if (this.message[this.msgIndex] != ' ') {
			renderLetter(this.message[this.msgIndex]);
		}
		this.msgIndex++;

		if (this.msgIndex >= this.message.length) clearInterval(this.timer);
	}

		this.stop = function() {
		clearInterval(this.timer);
	}
}

function Grid() {
	this.rows = 16;
	this.cols = 16;
	this.blockWidth = 30;
	this.blockSpacing = 1;
	this.maxInk = 200;
	this.blocks = Array();
	this.blocksSequence = Array();
	var canvasContext = document.getElementById('pixelCanvas').getContext('2d');

	// Do some maths to speed up the calculations later
	this.totalBlockWidth = this.blockWidth + this.blockSpacing;
	this.halfBlockWidth = Math.floor( this.totalBlockWidth / 2 );

	this.init = function() {
		// initialise the blocks
		for (rows = 0; rows < this.rows; rows ++) {
			row = new Array;
			for (cols = 0; cols < this.cols; cols ++ ) {
				row[cols] = new Block( canvasContext, cols, rows, this );
			}
			this.blocks[rows] = row;
		}

		// Loop through all the blocks and assign neighbours
		for (rows = 0; rows < this.rows; rows ++) {
			for (cols = 0; cols < this.cols; cols ++ ) {
				neighbours = Array();
				if (cols < (this.cols - 2)) {
					neighbours.push( this.blocks[rows][cols + 1] );
				}
				if (rows < (this.rows - 2)) {
					neighbours.push( this.blocks[rows + 1][cols]  );
				}
				if (cols > 0) {
					neighbours.push( this.blocks[rows][cols - 1]  );
				}
				if (rows > 0) {
					neighbours.push( this.blocks[rows - 1][cols] );
				}
				this.blocks[rows][cols].setNeighbours( neighbours );
				this.blocksSequence.push( this.blocks[rows][cols] );
			}
		}
	}

}


  function fadeText() {
  $('.fade').fadeTo('slow', 0);
  }

  var t = setTimeout('fadeText()', 10000);

