/*
	Changes:
	- eliminate the excessive 'h:' messages.
	- eliminate "joined" and "left" messages.
	- read initial user list from online.txt.
	- eliminate pruning logic from client side.

	Publish these changes ASAP. Add CSS to game.cgi
*/
var latestMessagePos = -1;
var latestUlogPos = -1;
var lst = -1;
var llt = -1;
var room = 'main';
var username;
var name, uid;
var initialPeriod = 4;
var period = initialPeriod;
var countdown = 0;
var chatDiv;
var waitingForResponse = false;
var scheduledPosts = new Array();
var messageCount = 0;
var users = new Array();
var usersLastSeen = new Array();

var req, done;
function sendRequest(url, postData, callback) {
	// branch for native XMLHttpRequest object
	if (window.XMLHttpRequest) {
		try {
			req = new XMLHttpRequest();
		} catch(e) {
			req = false;
		}
	// branch for IE/Windows ActiveX version
	} else if (window.ActiveXObject) {
		try {
			req = new ActiveXObject("Msxml2.XMLHTTP");
		} catch(e) {
			try {
				req = new ActiveXObject("Microsoft.XMLHTTP");
			} catch(e) {
				req = false;
			}
		}
	}

	if (req) {
		done = false;
		req.onreadystatechange = function() {
			if (req.readyState == 4 && req.status == 200 && !done) {
				done = true;
				callback();
			}
		}
		if (postData) {
			req.open("POST", url, true);
		}
		else {
			req.open("GET", url, true);
		}
		req.send(postData);
	}
}

function splitLines(text) {
	var outLines = new Array();
	var lines = text.split('\n');
	for (var i = 0; i < lines.length; i++) {
		var line = lines[i];
		if (!(line.length == 0 && i == lines.length-1))
			outLines.push(line);
	}
	return outLines;
}

function el(type, attributes, content) {
	var element = document.createElement(type);
	if (attributes) {
		var attrs = attributes.split(',');
		for (var i = 0; i < attrs.length; i++)
		{
			var eqIdx = attrs[i].indexOf('=');
			var atName = attrs[i].substring(0, eqIdx);
			var atValue = attrs[i].substring(eqIdx+1);
			if (atName == 'class')
				element.className = atValue;
			else if (atName == 'onclick')
			{
				element.onclick = function(e) { eval(atValue); };
				if (element.captureEvents) element.captureEvents(Event.CLICK);
			}
			else
				element.setAttribute(atName, atValue);
		}
	}
	if (content) {
		element.appendChild(content);
	}
	return element;
}

function tx(text)
{
	return document.createTextNode(text);
}

function eResponse()
{
	try {
		var messages = splitLines(req.responseText);
		var st;
		var lt = new Date().valueOf();
		for (var i = 0; i < messages.length; i++) {
			var fields = messages[i].split('\^');
			var pos = fields[0];
			var uname = fields[1];
			var textf = fields[2];
			var textf = textf.replace(/\\\\/g, "\\").replace(/\\c/g, '^');
			if (fields.length > 3)
				st = fields[3];

			var colonIdx = textf.indexOf(':');
			var msgType;
			var msg;
			if (colonIdx >= 0) {
				msgType = textf.substring(0, colonIdx);
				msg = textf.substring(colonIdx+1);
			}
			else {
				msgType = 't';
				msg = textf;
			}


			if (latestMessagePos < 0) {
				// We use the first message to get the latest message pos

				//postMessage(username+" has joined the game");
				scheduledPosts.push("h:");
				var initialUsers = msg.split(',');
				for (var i = 0; i < initialUsers.length; i++)
					addUser(initialUsers[i]);
				latestMessagePos = pos;
				latestUlogPos = uname;
			}
			else {
				if (msgType == 't')
				{
					displayTextMessage(pos,uname,msg);
					latestMessagePos = pos;
				}
				else if (msgType == 'h') // someone introduces themselves to you.
				{
					addUser(uname);
					latestUlogPos = pos;
				}
				else if (msgType == 'b') // someone says bye
				{
					removeUser(uname);
					latestUlogPos = pos;
				}
			}
		}
		st *= 1000;
		/*
		if (lst >= 0)
		{
			var sd = st - lst;
			var ld = lt - llt;
			if (Math.abs(sd-ld) > 1000)
			{
				//scheduledPosts.push('d:'+(sd-ld));
				if (username.match(/Ryan Heise/))
				{
					//alert('d:'+(sd-ld));
				}
			}
			else if (username.match(/Ryan Heise/))
			{
				//scheduledPosts.push('e:'+(sd-ld));
			}
		}
		lst = st;
		llt = lt;
		*/
		waitingForResponse = false;
	} catch (e) {
		alert(e);
	}
}

function displayTextMessage(pos, uname, text)
{
	var unameParts = uname.split('/');
	var namePart = unameParts[0];
	var uidPart = unameParts[1];

	var chatDiv = document.getElementById('chatDiv');
	var messageDiv = document.getElementById('message_'+pos);
	if (messageDiv) chatDiv.removeChild(messageDiv);
	var titleBit = uidPart != '0' ? ('title=user id: '+uidPart+',') : '';
	if (uidPart == '2') // system
	{
		messageDiv = el('div', 'class='+(messageCount%2==0?'even':'odd'), el('span', 'class=sysmsg', tx(text)));
	}
	else
	{
		messageDiv = el('div', titleBit + 'id=message_'+pos+',class='+(messageCount%2==0?'even':'odd'), el('img', 'src=/gravatar.cgi?u='+uidPart+',width=15,height=15'));
		messageDiv.appendChild(el('span', 'class=chatname', tx(namePart)));
		messageDiv.appendChild(tx(': '+text));
	}
	messageCount++; // do not count posts that contain cube moves -- well, this code isn't needed anymore
	chatDiv.appendChild(messageDiv);
	chatDiv.scrollTop = chatDiv.scrollHeight;
}

function pruneUsers()
{
	for (var i = 0; i < users.length; i++)
	{
		// hasn't been seen for 1 minute (each cycle is 500 ms)
		if (currentCycle - usersLastSeen[i] > 120)
		{
			removeUser(users[i]);
			break; // delete 1 user at a time
		}
			
	}
}

function removeUser(uname)
{
	for (var i = 0; i < users.length; i++)
		if (uname == users[i])
		{
			users.splice(i, 1);
			usersLastSeen.splice(i, 1);
			//updateUsersDiv();
			document.getElementById('usersDiv').removeChild(document.getElementById(uname));
			return;
		}
}

function addUser(uname)
{
	for (var i = 0; i < users.length; i++)
		if (uname == users[i])
		{
			usersLastSeen[i] = currentCycle;
			return;
		}
	users.push(uname);
	usersLastSeen.push(currentCycle);
	//updateUsersDiv();
	document.getElementById('usersDiv').appendChild(createAvatar(uname));
}

function updateUsersDiv()
{
	var usersDiv = document.getElementById('usersDiv');
	var userLinks = '';
	var guestCount = 0;
	for (var i = 0; i < users.length; i++) {
		var username = users[i];
		var parts = username.split('/');
		name = parts[0];
		if (/^guest.*$/.test(name)) {
			guestCount++;
		}
		else {
			uid = parts[1];

			userLinks += '<a class="rplink" title="'+name+'" target="_top" href="/profile/' + uid + '"><img width="40" height="40" style="border: solid 1px #ddd; padding: 4px; margin: 4px;" src="/gravatar.cgi?u=' + uid + '"></a>';
		}
	}
	if (guestCount > 0)
		userLinks += '<div>' + guestCount + (guestCount == 1 ? ' guest' : ' guests') + '</div>';
	usersDiv.innerHTML = '<div>' + userLinks + '</div>';
}

function createAvatar(uname)
{
	var parts = uname.split('/');
	var name = parts[0];
	var uid;
	if (/^guest.*$/.test(name)) {
		uid = 0;
	}
	else {
		uid = parts[1];
	}

	var imgEl = el('img', 'class=avatarImg,src=/gravatar.cgi?u='+uid);
	var avatarEl = el('a', 'id='+uname+',class=rplink,title='+name+',target=_top,href='+(uid > 0 ? ('/profile/'+uid) : '/register.cgi'), imgEl);
	return avatarEl;
}

// public
function postMessage(text)
{
	if (text == null || text.length == 0)
		return;
	period = initialPeriod;
	countdown = 0;
	scheduledPosts.push('t:'+text);
}

function sendScheduledPosts()
{
	var posts = scheduledPosts;
	scheduledPosts = new Array();
	if (posts.length > 0)
	{
		var postData = '';
		for (var i = 0; i < posts.length; i++)
			postData += posts[i]+"\n";
		sendChatRequest(postData);
		return true;
	}
	else
	{
		return false;
	}
}

function setUser(nusername)
{
	/*
	if (! /^[a-zA-Z0-9 ]+$/.test(nusername))
	{
		alert('Name must contain only characters a-z,A-Z,0-9,_ and space');
		return;
	}
	if (! /^[0-9]+$/.test(nuserid))
	{
		alert('User id must be an unsigned int');
		return;
	}
	*/

	username = nusername;
	var parts = username.split('/');
	name = parts[0];
	uid = parts[1];
	/*
	var nameRow = document.getElementById('nameRow');
	nameRow.style.display = 'none';
	var messageRow = document.getElementById('messageRow');
	messageRow.style.display = 'block';
	*/

	doCycle();
}

function sendChatRequest(postData)
{
	waitingForResponse = true;
	sendRequest('http://hi-games.net/chat/e.cgi?r='+room+'&u='+escape(username)+'&s='+latestMessagePos+'&v='+latestUlogPos, postData, eResponse);
}

function checkMessages()
{
	sendChatRequest("\n");
}

var currentCycle = 0;
function doCycle()
{
	if (currentCycle % 100 == 0)
	{
		scheduledPosts.push('h:'); // keep alive
	}
	if (countdown <= 0 && !waitingForResponse)
	{
		if (sendScheduledPosts())
		{
			period = initialPeriod;
		}
		else
		{
			checkMessages();
			//period *= 2;
			//period = 2;
			if (period < 100)
				period++;
		}
		countdown = period;
		//pruneUsers();
	}
	else
	{
		countdown--;
	}
	currentCycle++;
	setTimeout("doCycle();", 500);
}

function initChat(lroom) {
	room = lroom;
	username = 'guest' + Math.floor(Math.random()*1000);
	window.onunload = goodbye;
}

function wakeUp() {
	period = initialPeriod*2;
	countdown = 0;
	//if (countdown > period)
	//	countdown = period;
}

function goodbye() {
	// should be called on page unload.
	if (latestMessagePos >= 0)
		sendChatRequest("b:"); // say bye
}

function reset() {
	scheduledPosts = new Array();
	latestMessagePos = -1;
	latestUlogPos = -1;
	period = initialPeriod;
	countdown = 0;
}
