var score, level;
var scoreDiv, levelDiv, prevDiv, arenaDiv;
var currentBlock, currentState, currentType, nextBlock, nextType, blockCount;
var blockTimer;
var blocks, blockDimensions, blockPivots;
var arena;
var x, y, dt;
var previews;
var arenaHeight = 16;
var arenaWidth = 12;
var paused, lost;
var submitScore, playerName, score

function init() {	
	//these divs must be in the page that called init().
	arenaDiv = document.getElementById('arena');
	infoDiv = document.getElementById('info');
	scoreDiv = document.getElementById('score');
	levelDiv = document.getElementById('level');
	prevDiv = document.getElementById('preview');
	messageDiv = document.getElementById('message');
	messageBackDiv = document.getElementById('messageBack');
	
	blocks = Array(7);
	//the format for a block is:	
	//		block[num][state][square][relX, relY]  --each unit of each state has a position relative to the pivot [.]
	blocks[0] = Array( Array( Array(-1, 0),  //  [ ][.][ ][ ]
									  Array(0, 0),   
									  Array(1, 0),   
									  Array(2, 0) ),
							 Array( Array(0, -1),  //     [ ] 
									  Array(0, 0),   //     [.]
									  Array(0, 1),   //     [ ]
									  Array(0, 2) ));//     [ ]
									  
	blocks[1] = Array( Array( Array(-1, 0),  //     [ ]
									  Array(0, 0),   //  [ ][.][ ]
									  Array(1, 0),   
									  Array(0, -1) ),
							 Array( Array(0, -1),  //     [ ] 
									  Array(0, 0),   //     [.][ ]
									  Array(0, 1),   //     [ ]
									  Array(1, 0) ),// 
							 Array( Array(-1, 0),  //      
									  Array(0, 0),   //  [ ][.][ ]
									  Array(1, 0),   //     [ ]
									  Array(0, 1) ),// 
							 Array( Array(0, -1),  //     [ ] 
									  Array(0, 0),   //  [ ][.]
									  Array(0, 1),   //     [ ]
									  Array(-1, 0) ));// 
									  
	blocks[2] = Array( Array( Array(-1, 0),  //     [ ][ ]
									  Array(0, 0),   //  [ ][.]
									  Array(0, -1),   
									  Array(1, -1) ),
							 Array( Array(0, -1),  //     [ ] 
									  Array(0, 0),   //     [.][ ]
									  Array(1, 0),   //        [ ]
									  Array(1, 1) ));//    
									  
	blocks[3] = Array( Array( Array(-1, -1), //  [ ][ ]
									  Array(0, 0),   //     [.][ ]
									  Array(0, -1),   
									  Array(1, 0) ),
							 Array( Array(0, -1),  //     [ ] 
									  Array(0, 0),   //  [ ][.]
									  Array(-1, 0),  //  [ ]
									  Array(-1, 1) ));//  

	blocks[4] = Array( Array( Array(0, -1),  //     [ ][ ]
									  Array(0, 0),   //     [.][ ]
									  Array(1, -1),   
									  Array(1, 0) ));
									  
	blocks[5] = Array( Array( Array(-1, 0),  //        [ ]
									  Array(0, 0),   //  [ ][.][ ]
									  Array(1, 0),   //     
									  Array(1, -1)), // 
							 Array( Array(0, -1),  //     [ ] 
									  Array(0, 0),   //     [.]
									  Array(0, 1),   //     [ ][ ]
									  Array(1, 1)),//
							 Array( Array(-1, 0),  //  [ ][.][ ]
									  Array(0, 0),   //  [ ]
									  Array(1, 0),   
									  Array(-1, 1) ),
							 Array( Array(-1, -1), //  [ ][ ] 
									  Array(0, -1),  //     [.]
									  Array(0, 0),   //     [ ]
									  Array(0, 1) ));//  
									  
	blocks[6] = Array( Array( Array(-1, 0),  //  [ ]
									  Array(0, 0),   //  [ ][.][ ]
									  Array(1, 0),   //     
									  Array(-1, -1)), // 
							 Array( Array(0, -1),  //     [ ][ ]
									  Array(0, 0),   //     [.]
									  Array(0, 1),   //     [ ]
									  Array(1, -1)),//
							 Array( Array(-1, 0),  //  [ ][.][ ]
									  Array(0, 0),   //        [ ]
									  Array(1, 0),   
									  Array(1, 1) ),
							 Array( Array(-1, 1),  //     [ ] 
									  Array(0, -1),  //     [.]
									  Array(0, 0),   //  [ ][ ]
									  Array(0, 1) ));//  
									  
	//dimensions of the first state of each block (x, y)
	blockDimensions = Array(Array(4, 1),
									Array(3, 2),
									Array(3, 2),
									Array(3, 2),
									Array(2, 2),
									Array(3, 2),
									Array(3, 2));
	
	//where are the 'pivots' relative to x, y?
	blockPivots = Array(Array(1, 0), 
							  Array(1, 1), 
							  Array(1, 1),
							  Array(1, 1),
							  Array(0, 1), 
							  Array(1, 1),
							  Array(1, 1));
							  
	//prep the preview arrays previews[block][row1, row2][brick?] = value
	previews = Array(Array(Array(1, 1, 1, 1)),
						  Array(Array(0, 1, 0), Array(1, 1, 1)),
						  Array(Array(0, 1, 1), Array(1, 1, 0)), 
						  Array(Array(1, 1, 0), Array(0, 1, 1)), 
						  Array(Array(1, 1), Array(1, 1)),
						  Array(Array(0, 0, 1), Array(1, 1, 1)),
						  Array(Array(1, 0, 0), Array(1, 1, 1)));
	
	//the arena contains information on the current state of the playing field.
	arena = new Array(arenaWidth);
	for (i = 0; i < arenaWidth; i++) {
		arena[i] = new Array(arenaHeight);
		for (j = 0; j < arenaHeight; j++) {
			arena[i][j] = 0;
			
		}
	}
		
	score = 0;
	level = 0;
	blockCount = 0;
	lost = false;
	paused = true;
	submitScores = false;
	
	document.onkeydown = keyDownListener;
	
	level++;
	levelDiv.innerHTML = 'Level: '+level;
	
	//clear the board!
	for (i = 0; i < 8; i++) {
		for (j = 0; j < arenaHeight; j++) {
			arena[i][j] = 0;
		}
	}
	chooseNext();
	block();
	
}

function keyDownListener(e) {
	if (!e) { //a fix for IE
		e = window.event;
	}
	
	
	if (e.keyCode == 37 && !lost && !paused) { //left key moves the block left, if possible
		collisions(-1, 0, currentState);
		if (!collide) {
			move(-1, 0, currentState);
			render();
		}
	}
	
	
	if (e.keyCode == 39 && !lost && !paused) { //right key moves the block right, if possible
		collisions(1, 0, currentState);
		if (!collide) {
			move(1, 0, currentState);
			render();
		}
	}	
	
	
	if (e.keyCode == 40 && !lost && !paused) { //down accellerates the timeout loop.	
      clearTimeout(blockTimer);
		dt = 5;
		blockTimer = setTimeout('go()', dt);
	}	
	
	
	if (e.keyCode == 38 && !lost && !paused) { //up switches the state of the block.
		rotate();
	}
	
	if (e.keyCode == 32 && !lost) { //pause/unpause
		pause(0);
	}
	
	if (e.keyCode == 13) { //submit score
		validate();
	}

}

function pause(how) {
	if (paused && how == 0) {
		clearMessage();
		paused = false;
		go();
	} else {
		paused = true;
		displayMessage(how);
	}
};

function displayMessage(which) {
	messageDiv.style.visibility = 'visible';
	messageBackDiv.style.visibility = 'visible';
	clearTimeout(blockTimer);
	var message = '<font style="font-size: 18px; text-align: center;">';
	var messageHeight;
	switch(which) {
		case 0:
			message += '<center>PAUSED</font><br />press space to resume.</center>';
			messageHeight = 40;
			break;
		case 1:
			message += '<center>HELP</center></font>UP will rotate your block<br />LEFT/RIGHT will move your block<br />'
			message += 'DOWN will speed up your block\'s downward motion<br />SPACE will pause the game<br />'
			message += 'CLEARING BRICKS: fill up a row with bricks to clear that row.  You lose when a brick gets stuck in the top two rows.<br /><br />'
			message += '<img src="bricks.gif" style="float: left;" />BLUE bricks are worth a few points<br />YELLOWISH get you bonus points!<br />RED get you even more<br />'
			message += 'STEEL will get you fantastic points.<br />FUNKY bricks will get you copious amounts of points.<br />';
			if (lost) {
				message += '<center><button onClick="refresh();" style="border: 1px solid black; font-family: verdana; font-size: 10px; background-color: #9CF;">New Game</button></center>';
				submitScores = false;
				submitted = true;
			}
			else
				message += 'Press SPACE to resume.</center>';
			messageHeight= 256;
			break;
		case 2:
			message += '<center>WHAT IS THIS?</center></font><br />BLOCK4DE (formerly 4Block) was a project undertaken by me to distract me from the myriads of exams and assignments that I should have been working on.';
			message += ' I scripted BLOCK4DE almost entirely with Javascript, and it is my first completed game.<br /><br />';
			message += 'If you have problems or praises for me to hear about, email me at <a href="mailto:zapwow@gmail.com" target="_new">zapwow@gmail.com</a>.<br /><br />I hope you enjoy playing BLOCK4DE as much as I enjoyed writing it!<br /><br />';
			
			if (lost) {
				message += '<center><button onClick="refresh();" style="border: 1px solid black; font-family: verdana; font-size: 10px; background-color: #9CF;">New Game</button></center>';
				submitScores = false;
				submitted = true;
			}
			else
				message += 'Press SPACE to resume.</center>';
			messageHeight = 256;
			break;
		case 3: 
			var URL = 'http://cse.yorku.ca/~cs243058/block4de/scores.php';
			if (submitScores)
				URL += '?score='+score+'&name='+playerName;
			message += '<center>TOP SCORES</font><br /><iframe src="'+URL+'" height=218 width=190 frameborder=0 allowtransparency="true" background-color="transparent"></iframe>';
			
			if (submitScores || lost) {
				message += '<button onClick="refresh();" style="border: 1px solid black; font-family: verdana; font-size: 10px; background-color: #9CF;">New Game</button></center>';
				submitScores = false;
			}
			else
				message += 'Press SPACE to resume.</center>';
			messageHeight = 256;
			break;
		case 4:
			message += '<center>GAME OVER</center></font>You won three bytes of webspace!<br /><br />Enter your initials to submit your score, or start a new game.<br />';
			message += '<br /><center><input type="text" maxlength=3 id="initials" style="border: 1px solid black; width: 36px; font-family: verdana; font-size: 10px;"/> ';
			message += ' <button onClick="validate()" style="border: 1px solid black; font-family: verdana; font-size: 10px; background-color: #9CF;">Submit Score</button><br />-or-<br />';
			message += '<button onClick="refresh();" style="border: 1px solid black; font-family: verdana; font-size: 10px; background-color: #9CF;">New Game</button>';
			messageHeight = 145;
			break;

	}
	
	messageDiv.innerHTML = message;
	messageBackDiv.style.height = messageHeight+'px';
	if (messageHeight < 220) {
		messageDiv.style.top = Math.round(40 + 118*(1-messageHeight/256))+'px';
		messageBackDiv.style.top = Math.round(40 + 118*(1-messageHeight/256))+'px';

	} else {
		messageDiv.style.top = '40px';
		messageBackDiv.style.top = '40px';
	}
	if (which == 4) {
		document.getElementById("initials").focus();
	}

}

function refresh() {
	window.location.reload(false);
}

function validate() {
	playerName = document.getElementById("initials").value;
	if (playerName != 'undefined' && playerName != '' && playerName.indexOf(' ') == -1) {
		submitScores = true;
		displayMessage(3);
	}
}


function clearMessage() {
	messageDiv.style.visibility = 'hidden';
	messageBackDiv.style.visibility = 'hidden';
}
function chooseNext() {
	nextBlock = Math.round(Math.random()*6);
	nextType = Math.random()*10;
	if (nextType < 6.5)
		nextType = 1;
	else if (nextType < 8)
		nextType = 2;
	else if (nextType < 9)
		nextType = 3;
	else if (nextType < 9.8)
		nextType = 4;
	else
		nextType = 5;
}
function block() {
	blockCount++;
	
	if (blockCount % 10 == 0)
		levelUp();
		
	currentBlock = nextBlock;
	currentType = nextType;
	currentState = 0;
	
	//preview the next block
	chooseNext();
	prevHeight = previews[nextBlock].length;
	prevWidth = previews[nextBlock][0].length;
	
	newPrev = '';
	for (i=0; i < prevHeight; i++) {
		for (j=0; j < prevWidth; j++) {
			newPrev += '<div class="smallBrick" style="top: '+(48+((2-prevHeight)*8)+16*i)+'; left: '+(16*(3-prevWidth/2)+16*j)
			if (previews[nextBlock][i][j] == 1) {
				newPrev += '; visibility: visible';//;"></div>';
			}
			newPrev += '; background-position: 0px '+((nextType-1)*(-16))+'px;"></div>';
			
		}
	}
	prevDiv.innerHTML = newPrev;
	
	
	//place the block
	x = 6 - Math.round(blockDimensions[currentBlock][currentState] / 2);
	y = 1 - blockDimensions[currentBlock][1];
	dt = 500;
	if (!paused)
		go();
	
}

function go() {
	score += 1
	
		
	collisions(0, 1, currentState);
	if (!collide) {
		move(0, 1, currentState);
		render();
		blockTimer = setTimeout('go()', dt-(5*level*level));
	} else if (y > 1) {
		dissolve();
		render();
		block();
	} else { 
		gameOver();
	}
}

function levelUp() {
	level++;
	if (level < 10)
		dt = 500 - 5*level*level;
	else
		dt = 0;
	render();
}

function collisions(dx, dy, state) {
	collide = false;	
	for (i = 0; i < 4; i++) {
		thisBrick = getBrick(currentBlock, state, i, x+dx, y+dy);
		if (thisBrick != 0 && thisBrick != 'a') {
			collide = true;
		}
	}
}

function move(dx, dy, state) {
	
	for (i = 0; i < 4; i++) {
		setBrick(currentBlock, currentState, i, x, y, 0);
	}

	y += dy;
	x += dx;
	currentState = state;
	
	for (i = 0; i < 4; i++) {
		setBrick(currentBlock, currentState, i, x, y, 'a');
	}
	
	//enable the debug() command to get a printout of the arena array and the position of the block.
	//debug();
}
function dissolve() {	
	for (i = 0; i < 4; i++) {
		setBrick(currentBlock, currentState, i, x, y, currentType);
	}
	for (j = 0; j < arenaHeight; j++) {
		rowSum = arenaWidth;
		scoreModifier = 0;
		for (i = 0; i < arenaWidth; i++) {
			if (arena[i][j] == 0) {
				rowSum--;
			}
			scoreModifier += (arena[i][j]+arena[i][j])*arena[i][j];
		}
		if (rowSum == arenaWidth) {
			score += 100 + 5*scoreModifier;
			for (k = j; k > 2; k--) {
				for (i = 0; i < arenaWidth; i++) {
					arena[i][k] = arena[i][k-1];
				}
			}
		}
	}
}


function render() {
	for (i = 0; i < arenaWidth; i++) {
		for (j = 0; j < arenaHeight; j++) {
			if (arena[i][j] != 0) {
				thisBrick = document.getElementById('brick'+i+'_'+j)
				thisBrick.style.visibility = 'visible';
				thisType = arena[i][j];
				if (arena[i][j] == 'a') {
					thisType = currentType;
				}
				thisBrick.style.backgroundPosition = '0px '+((thisType-1)*(-16))+'px';
			} else {
				document.getElementById('brick'+i+'_'+j).style.visibility = 'hidden';
			}
		}
	}
	scoreDiv.innerHTML = score+'pts';
	levelDiv.innerHTML = 'Level: '+level;
}
function gameOver() {
	lost = true;
	displayMessage(4);
}

function debug() {
	str = 'y='+y+' x='+x+'<br />';
	for (j = 0; j < arenaHeight; j++) {
		for (i = 0; i < arenaWidth; i++) {
			num = arena[i][j];
			if (num == 'a') {
				str += ' <b>a</b>';
			} else {
				str += ' '+num;
			}
		}
		str += '<br />';
	}
	document.getElementById("debug").innerHTML = str;
}


function getBrick(shape, state, brickNum, brickX, brickY) {
	var pivot;
	var bricks;
	pivot = blockPivots[shape];
	bricks = blocks[shape][state];
	
	xVal = brickX + pivot[0] + bricks[brickNum][0];
	yVal = brickY + pivot[1] + bricks[brickNum][1];
	if (xVal >= arenaWidth || yVal >= arenaHeight || xVal < 0 || yVal < 0) 
		 return -1;
	else
		return arena[xVal][yVal];
}

function setBrick(shape, state, brickNum, brickX, brickY, newValue) {
	var pivot;
	var bricks;
	pivot = blockPivots[shape];
	bricks = blocks[shape][state];
	arena[brickX + pivot[0] + bricks[brickNum][0]][brickY + pivot[1] + bricks[brickNum][1]] = newValue;
}

function rotate() {
	numStates = blocks[currentBlock].length-1;
	if (currentState == numStates) {
		nextState = 0;
	} else {
		nextState = currentState+1;
	}
	collisions(0, 0, nextState);
	if (!collide) {
		move(0, 0, nextState);
		render();
	}
}