var HTMLNS = "http://www.w3.org/1999/xhtml";
var boardid, cols, rows, body, docwidth, docheight, cellwidth, current, order;
var status, statusdiv, animationdiv, currentcell, whathowdiv, chk_autosave;
var animationState = 0;
var animationChars = ".|/-\\";
var data;
var windows = new Array();
var savechr;
var currCol = 0, currRow = 0;
var updateInterval = 3000;
var httpobj = new Array();
var commentsok = 0;
var boardData;
var users;

/* Wait until the page & all associated files load fully before we get going. */
addEvent(window, "load", startup);

// startup {{{
function startup()
{
	/* Initialise a bunch of stuff. */
	body = document.getElementsByTagName("body")[0]; 
   chk_autosave = getElement("chk_autosave");
	
	getSize();
	boardid = getBoardID();
	cols = getCols();
	rows = getRows();
	order = new Array(cols * rows);

	/* Set positions for the draggable boxes, because we can't read them out of the CSS, for some weird reason... */
	getElement("editbox").style.left = "250px";
	getElement("editbox").style.top = "110px";
	getElement("whathow").style.left = "100px";
	getElement("whathow").style.top = "100px";
	getElement("charsuggest").style.left = "70px";
	getElement("charsuggest").style.top = "90px";
	getElement("contact").style.left = "400px";
	getElement("contact").style.top = "90px";
	getElement("extras").style.left = "200px";
	getElement("extras").style.top = "90px";
	getElement("recent").style.left = "110px";
	getElement("recent").style.top = "100px";

	/* Register our key handler */
	document.onkeyup = keyHandler;
	getElement("newchar").onkeyup = keyHandler;

	HTTPRequest('board', "board?type=table&board=" + boardid, boardResponse);
}
// }}}

// boardResponse {{{
function boardResponse()
{
	if(httpobj['board'].readyState == 4)
		if(httpobj['board'].status == 200)
		{
			if(httpobj['board'].responseText.indexOf("OK") != -1)
			{
				eval(httpobj['board'].responseText);
            var boardhtml = '<table id="board" cellpadding="1" cellspacing="0">';

            for(var row = 0; row < boardData.length; row++)
            {
               boardhtml += "<tr>";

               for(var col = 0; col < boardData[row].length; col++)
               {
                  if(boardData[row][col] == 32)
                     code = "&nbsp;";
                  else
                     code = "&#" + boardData[row][col] + ";";

                  boardhtml += '<td class="c" id="' + col + '_' + row + '" onclick="eb(' + col + ',' + row + ')" onmouseover="u(' + col + ',' + row + ')">' + code + "</td>";
                 //boardhtml += '<td class="c" id="' + col + '_' + row + '" onclick="eb(' + col + ',' + row + ')" onmouseover="u(' + col + ',' + row + ')">&#' + boardData[row][col] + ";</td>";
               }
               
               boardhtml += "</tr>";
            }

            boardhtml += "</table>";

            getElement("board").innerHTML = boardhtml;

				/* Set the font size for the board */
				cellwidth = (docwidth - 40 - (cols * 3)) / cols;
				getElement("board").style.fontSize = (cellwidth * 1.3) + "px";

				//getElement("board").style.width = (docwidth - 40) + "px";
				//getElement("board").style.height = ((width * 1.5 * rows) + rows) + "px";

				/* Kick off the various things that draw the board. */
				actions(0);
			}
			else
			{
				alert("Uh-oh, unable to load the initial board!");
				getElement('whathow').innerHTML = httpobj['board'].responseText;
				toggleWindow('whathow');
			}
			stat();
		}
		else
			alert("Error: Response code: " + httpobj['board'].status);

}
// }}}

// actions {{{
function actions(action)
{
	switch(action)
	{
		case 0:
			stat("Calculating order...");
		break;

		case 1:
			generateOrder();
			randomiseOrder(50);
		break;

		case 2:
			/* If the user is using a gecko-based browser, (FireFox, Netscape 6, Camino, etc) we need to disable the fancy drawing effect. :( */
			if(navigator.userAgent.toLowerCase().indexOf('gecko') != -1 && navigator.userAgent.toLowerCase().indexOf('like gecko') == -1)
			{
				getElement("board").style.color = "#FFFFFF";
				stat();
				
				/* Start the updating timer */
				setTimeout("update()", updateInterval);
			}
			else
			{
				stat("Drawing board...");
				setTimeout("showCell(20)", 1);
			}
		break;

		default:
			action = -1;
		break;
	}
	
	if(action != -1)
		setTimeout("actions(" + (action + 1) +")", 1);
}
// }}}

// addEvent {{{
// Add an eventListener to browsers that can do it somehow.
// Originally by the amazing Scott Andrew.
function addEvent(obj, evType, fn)
{
	if(obj.addEventListener)
	{
		obj.addEventListener(evType, fn, true);
		return true;
	}
	else if(obj.attachEvent)
	{
		var r = obj.attachEvent("on"+evType, fn);
		return r;
	} 
	else 
		return false;
}
// }}}

// getSize {{{
function getSize()
{
	if( typeof( window.innerWidth ) == 'number' )
	{
		//Non-IE
		docwidth = window.innerWidth;
		docheight = window.innerHeight;
	}
	else if( document.documentElement && ( document.documentElement.clientWidth || document.documentElement.clientHeight ) )
	{
		//IE 6+ in 'standards compliant mode'
		myWidth = document.documentElement.clientWidth;
		myHeight = document.documentElement.clientHeight;
	}
	else if( document.body && ( document.body.clientWidth || document.body.clientHeight ) )
	{
		//IE 4 compatible
		myWidth = document.body.clientWidth;
		myHeight = document.body.clientHeight;
	}
}
// }}}

// generateOrder {{{
function generateOrder()
{
	var cols = getCols();
	var rows = getRows();
	var row = 0;
	var col = 0;

	current = 0;
	
	order[current++] = (col++ + "_" + row);
	
	var direction = true;
	do
	{
		if(col >= 0 && col < cols && row >= 0 && row < rows)
			order[current++] = (col + "_" + row);
		
		if(direction)
		{
			col--
			row++;
			
			if(col == -1 || row == rows)
			{
				direction = !direction;
				col++;
			}

		}
		else
		{
			col++;
			row--;
			
			if(col == cols || row == -1)
			{
				direction = !direction;
				row++;
			}
		}

	}
	while(current < order.length);
	current = 0;
}
// }}}

// randomiseOrder {{{
function randomiseOrder(blocksize)
{
	for(var i = order.length - blocksize; i >= 0; i--)
	{
		var pos = i + (Math.round(Math.random() * blocksize));
		var tmp = order[i];
		order[i] = order[pos];
		order[pos] = tmp;
	}
}
// }}}

// showCell {{{
function showCell(num)
{
	if(current == order.length)
	{	
		stat();

		/* Start the updating timer */
		setTimeout("update()", updateInterval);

		return;
	}

	if(num == 0)
		setTimeout("showCell(50)", 1);
	else
	{
		var cell = getElement(order[current++])
		cell.style.color = "#FFFFFF";
      cell.style.width = cellwidth + "px";
      
		showCell(--num);
	}
}
// }}}

// HTTPRequest {{{
function HTTPRequest(type, url, callback)
{
	if(window.XMLHttpRequest)
	{ // code for Mozilla, Safari, etc
		httpobj[type] = new XMLHttpRequest();
		httpobj[type].onreadystatechange = callback;
		httpobj[type].open("GET", url, true);
		httpobj[type].send(null);
	}
	else
		if(window.ActiveXObject)
		{ //IE
			httpobj[type] = new ActiveXObject("Microsoft.XMLHTTP");
			if(httpobj[type])
			{
				httpobj[type].onreadystatechange = callback;
				httpobj[type].open("GET", url, true);
				httpobj[type].send();
			}
		}
}
// }}}§

// clickedCell {{{
function clickedCell(e)
{
	var thisObj;
	if(window.event && window.event.srcElement)
		thisObj = window.event.srcElement;
	else
		if(e && e.target)
			thisObj = e.target;
	
	if(!thisObj)
		return;
	
	if(thisObj.nodeType == 3)
		thisObj = getParent(thisObj, "DIV");
	
	if(!thisObj)
		return;

	var id = thisObj.id;
	var bits = id.split("_");
	var col = bits[0];
	var row = bits[1];
	
	editBox(col, row, thisObj);
}
// }}}

// editBox {{{
function eb(col, row)
{
	return editBox(col, row);
}

function editBox(col, row)
{
	if(currentcell)
		highlight(currentcell, false);

	currentcell = getElement(col + "_" + row);
   if(currentcell)
   {
	   getElement("editcol").innerHTML = col;
	   getElement("editrow").innerHTML = row;
	
	   if(currentcell.innerHTML == "&nbsp;")
	   	getElement("newchar").value = " ";
	   else
	   	getElement("newchar").value = currentcell.innerHTML;
	
	   /* currently selected cell stuff */
	   currCol = col;
	   currRow = row;
	   
	   /* override the visibility value for this box, so the box doesn't close when clicking a different cell. */
	   windows['editbox'] = false;

	   toggleWindow('editbox');
	   
	   /* Set the focus on the textbox, and select everything in it. */
	   getElement("newchar").focus();
	   getElement("newchar").select();


	   highlight(currentcell, true);
   }
}
// }}}

// highlight {{{
function highlight(element, state)
{
	if(element)
		if(state)
			element.style.border = "1px solid #02BAE4";
		else
			element.style.border = "1px solid #000000";
}
// }}}

// toggleWindow {{{
function toggleWindow(windowname, filename)
{
	windows[windowname] = !windows[windowname];
	var element = getElement(windowname);	

	if(!element)
	{
		alert("Erk, couldn't locate object '" + windowname + "'. Please let the developer know!");
		return;
	}

	/* See if we need to load this box from the server. */
	if(element.innerHTML.length == 0)
	{
		element.innerHTML = "<div class=\"padding\">Hold on a sec, loading page...</p>";
		HTTPRequest('pageload', (filename ? filename : "page?page=" + windowname), pageLoad);
	}
	
	/* Special actions */
	if(windowname == "editbox" && !windows[windowname])
	{
		currentcell = null;

		getElement("focuslink").focus();
	}	

	if(windows[windowname])
		element.style.display = "block";
	else
		element.style.display = "none";
		

}
// }}}

// toggleCharmap {{{
function toggleCharmap()
{
	windows['charmap'] = !windows['charmap'];
	
	var editboxdiv = getElement('editbox');
	var charmapdiv = getElement('charmap');
	
	if(windows['charmap'])
	{
		editboxdiv.style.height = "400px";
		charmapdiv.style.display = "block";
	}
	else
	{
		editboxdiv.style.height = "110px";
		charmapdiv.style.display = "none";
	}
}
// }}}

// saveCell {{{
function saveCell()
{
	var textbox = getElement("newchar")
	if(textbox.value.length == 1)
		savechr = textbox.value.charCodeAt(0);
	else
		savechr = 32; // space
   
   if(!currentcell || textbox.value == currentcell.innerHTML)
   {
      return;
   }

	var bits = currentcell.id.split("_");
	var col = bits[0];
	var row = bits[1];

	stat("Saving cell..." + boardid);
	
	HTTPRequest('save', "save?board=" + boardid + "&col=" + col + "&row=" + row + "&chr=" + escape(savechr), saveResponse);

	if(textbox.value == '<')
		currentcell.innerHTML = "&lt;"
	else
      if(textbox.value == ' ')
         currentcell.innerHTML = "&nbsp;";
      else
		   currentcell.innerHTML = textbox.value;
}
// }}}

// saveResponse {{{
function saveResponse()
{
	if(httpobj['save'].readyState == 4)
		if(httpobj['save'].status == 200)
		{
			if(httpobj['save'].responseText.indexOf("OK") == -1)
				alert("Uh-oh, I was unable to save the last edit you made!");
				//getElement('boarddiv').innerHTML = httpobj['save'].responseText;
				stat();
		}
		else
			alert("Error: Response code: " + httpobj['save'].status);

}
// }}}

// keyHandler {{{
function keyHandler(e)
{
	var keycode = (window.event) ? event.keyCode : e.keyCode;

	/* Ignore if the contact window is open :) */
	if(windows['contact'])
		return false;

	if(keycode >= 37 && keycode <= 40)
   {
		highlight(getElement(currCol + "_" + currRow), false);
      
  		e.cancelBubble = true;
		if (e.stopPropagation)
			e.stopPropagation();

	    if(chk_autosave.checked == true)
         saveCell();
   }
   
	switch(keycode)
	{
		case 37: // left
			if(currCol > 0)
				currCol--;
		break;

		case 38: // up
			if(currRow > 0)
				currRow--;
		break;

		case 39: // right
			if(currCol < cols - 1)
				currCol++;
		break;

		case 40: // down
			if(currRow < rows - 1)
				currRow++;
		break;

		case 13:
			if(currentcell)
				saveCell();
			else
				editBox(currCol, currRow);

			e.cancelBubble = true;
			if (e.stopPropagation)
				e.stopPropagation();
		break;

		case 27:
			windows["editbox"] = true;
			toggleWindow("editbox");
		break;
	}

	if(keycode >= 37 && keycode <= 40)
	{
		highlight(getElement(currCol + "_" + currRow), true);
		if(windows["editbox"])
			editBox(currCol, currRow);
	}
   
   return false;
}	
// }}}

// u {{{
function u(col, row)
{
	if(!windows["editbox"])
	{
		highlight(getElement(currCol + "_" + currRow), false);
		currCol = col;
		currRow = row;
		highlight(getElement(col + "_" + row), true);
	}
}
// }}}

// update {{{
function update()
{
	stat("Checking for updates...");

	HTTPRequest('update', "update?board=" + boardid + "&time=" + lastUpdate, updateResponse);
}
// }}}

// updateResponse {{{
function updateResponse()
{
	if(httpobj['update'].readyState == 4)
		if(httpobj['update'].status == 200)
		{
			if(httpobj['update'].responseText.indexOf("OK") == -1)
			{
				getElement('whathow').innerHTML = httpobj['update'].responseText;
				toggleWindow('whathow');
			}
			else
			{
				var updates;
				eval(httpobj['update'].responseText);
				
            var users_text;

            if(users == 0)
               users_text = "(You're the only one right now... tell your friends about this!)";
            else if(users == 1)
               users_text = "(One other user right now)";
            else
               users_text = "(Roughly " + users + " other users right now)"

            getElement('users').innerHTML = users_text;

				if(updates)
				{
					for(var i = 0; i < updates.length; i++)
					{
						//stat("sched update " + (updateInterval - 50) * updates[i][3] + "doUpdate(" + updates[i][0] + ", " + updates[i][1] + ", '" + updates[i][2] + "')");
						setTimeout("doUpdate(" + updates[i][0] + ", " + updates[i][1] + ", '" + updates[i][2] + "')", (updateInterval - 50) * updates[i][3]);
					}
					updates = null;
				}
			}

			setTimeout("update()", updateInterval);
			stat();
		}
		else
			stat("Error: Response code: " + httpobj['update'].status);
}
// }}}

// doUpdate {{{
function doUpdate(col, row, chr)
{
	stat("Updating (" + col + ", " + row + ") with '" + "&#" + chr + ";'");
	var cell = getElement(col + "_" + row)
	cell.style.background = "#FFFFFF";
	cell.innerHTML = '&#' + chr + ';';

	setTimeout("resetBG(" + col + ", " + row + ")", 100);
}
// }}}

// resetBG {{{
function resetBG(col, row)
{
	getElement(col + "_" + row).style.background = "#000000";
}
// }}}

// pageLoad {{{
function pageLoad()
{
	var http = httpobj["pageload"];

	if(http.readyState == 4)
		if(http.status == 200)
			getElement(http.getResponseHeader("pagename")).innerHTML = http.responseText;
		else
			stat("Error: Response code: " + http.status);
}
// }}}

// sendComments {{{
function sendComments()
{
	getElement("sendcommentlink").style.display = "none";
   getElement('retrysend').style.display = "none";
	getElement("sendingcomment").style.display = "block";
   
   // After a few seconds, show the retry link
   setTimeout('showRetryLink()', 4000);

	var c_name = escape(getElement("comment_name").value);
	var c_email = escape(getElement("comment_email").value);
	var c_msg = escape(getElement("comment_message").value);

	HTTPRequest('comment', "comments?name=" + c_name + "&email=" + c_email + "&msg=" + c_msg, commentResponse);
}
// }}}

// commentResponse {{{
function commentResponse()
{
	var http = httpobj["comment"];

	if(http.readyState == 4)
		if(http.status == 200)
			if(http.responseText.indexOf("OK") != -1)
			{
				getElement("sendingcomment").style.display = "none";
				getElement("sentcomment").style.display = "block";
				getElement("sendingerror").style.display = "none";
            commentsok = 1;
            getElement("retrysend").style.display = "none";

			}
			else
			{
				getElement("sendcommentlink").style.display = "block";
				getElement("sendingcomment").style.display = "none";
				getElement("sendingerror").style.display = "block";
			}
}
// }}}

// showRetryLink {{{
function showRetryLink()
{
   if(commentsok == 0)
   {
      getElement('sendingcomment').style.display = "none";
      getElement('retrysend').style.display = "block";
   }
}
// }}}


