var autocompletors = new Array();
var theOnlineDestination = null;

var DETAILS_FIRSTNAME = 0;
var DETAILS_LASTNAME = 1;
var DETAILS_USERNAME = 2;
var DETAILS_EMAIL = 3;
var DETAILS_EXTRA = 4;
var DETAILS_PICCODE = 5;
var DETAILS_IDLE = 6;
var DETAILS_ID = 7;

addEvent(window, "load", findAutocompletors);

function test(str)
{
	str = str.toString();
	var testDiv = document.createElement('div');
	testDiv.innerHTML = str.replace('<', '&lt;');
	testDiv.style.borderBottom = "1px solid black";
	document.body.appendChild(testDiv);
}

function stopKeyAction(event)
{
	if (event.preventDefault) event.preventDefault();

	if (usingIE)
	{
		event.cancel = true;
		event.cancelBubble = true;
		event.keyCode = 0;
		event.returnValue = false;
	}
}

function findAutocompletors()
{
	theOnlineDestination = document.getElementById("onlineDestination");
	var inputArray = document.getElementsByTagName("input");
	var textAreaArray = document.getElementsByTagName("textarea");

	var i = null;


	var theInputArray = new Array();

	for (i = 0; i < inputArray.length; i++)
	{
		theInputArray[theInputArray.length] = inputArray[i];
	}
	for (i = 0; i < textAreaArray.length; i++)
	{
		theInputArray[theInputArray.length] = textAreaArray[i];
	}

	var theType = null;
	var autocomplete = null;
	var limit = null;
	var matchUsername = null;
	var matchEmail = null;

	preloadImages(["http://www.craterfish.org/email.png",
			"http://www.craterfish.org/smilies/smile.png",
			"http://www.craterfish.org/smilies/hmm.png"]);

	for (i = 0; i < theInputArray.length; i++)
	{
		theType = theInputArray[i].attributes.getNamedItem("type");
		if (theInputArray[i].nodeName.toLowerCase() == "textarea" || (theType && theType.value.toLowerCase() == "text"))
		{
			autocomplete = theInputArray[i].attributes.getNamedItem("autocomplete");
			if (autocomplete)
			{
				matchUsername = /username/i.test(autocomplete.value);
				matchEmail = /email/i.test(autocomplete.value);

				if (matchUsername || matchEmail)
				{
					limit = theInputArray[i].attributes.getNamedItem("autocompletelimit");
					limit = limit ? limit.value : "10";

					autocompletors[autocompletors.length] = new autocompletor(theInputArray[i], matchUsername, matchEmail, /list/i.test(autocomplete.value), limit, /online/i.test(autocomplete.value));
				}
			}
		}
	}
}

function highlightText(text, theRegExp)
{
	text = text.replace('<', '&lt;').replace('>', '&gt;');
	//gotta use tabs here instead of spaces because later spaces are replaced to &nbsp; with a / /g
	if (theRegExp) text = text.replace(theRegExp, '<b\tstyle\t=\t"background-color:\t#00FF00;">$1</b>');

	return text;
}

function autocompletor(theInput, matchUsername, matchEmail, listStyle, limit, online)
{
	var myself = this;

	this.theInput = theInput;
	this.matchUsername = matchUsername ? "1" : "",
	this.matchEmail = matchEmail ? "1" : "";
	this.limit = limit;
	this.listStyle = listStyle;
	this.online = online;
	this.focused = false;
	this.theTable = null;
	this.theDiv = null;
	this.lastSearch = "";
	this.xhreq = null;
	this.searching = false;
	this.theText = "";
	this.highlightedTR = null;
	this.visible = false;
	this.TRArray = new Array();
	this.replaceLength = null;
	this.waitingToSelect = false;
	this.mouseOverMe = false;
	this.contextMenu = null;
	this.cancelContextRemoval = false;
	this.lastMouseDownWasContextMenu = false; //on macs the context menu happens on the mouse DOWN, not up
	this.contextURL = null;

	this.theInput.setAttribute("autocomplete", "off");

	addEvent(this.theInput, "focus", function(){myself.gotFocus();});
	addEvent(this.theInput, "blur", function(){myself.lostFocus();});
	addEvent(this.theInput, "keydown", function(event){myself.keyDownEvent(event);});
	addEvent(this.theInput, "keyup", function(event){myself.keyUpEvent(event);});
	addEvent(this.theInput, "keypress", function(event){myself.keyPressEvent(event);});
	addEvent(document, "mouseup", function(event){myself.bodyMouseUp(event);});
	addEvent(document, "mousedown", function(event){myself.bodyMouseDown(event);});

	this.bodyMouseUp = function(event)
	{
		if (this.contextMenu && !this.lastMouseDownWasContextMenu) this.removeContextMenu();
	}

	this.bodyMouseDown = function(event)
	{
		this.lastMouseDownWasContextMenu = false;
	}

	this.removeContextMenu = function()
	{
		var myself = this;
		this.cancelContextRemoval = false;
		setTimeout(function()
		{
			if (myself.contextMenu && !myself.cancelContextRemoval)
			{
				myself.contextMenu.parentNode.removeChild(myself.contextMenu);
				myself.contextMenu = null;
			}
		}, 0);
	}

	this.gotFocus = function()
	{
		this.focused = true;
		if (this.theDiv && theInput.value === this.lastSearch && !this.searching && this.highlightedTR !== null && (theInput.value != "" || this.online))
		{
			if (theOnlineDestination && positionMenu) positionMenu(menuArray[4], menuHeaderArray[4]);
			this.theDiv.style.visibility = "visible";
			this.visible = true;
		}
	}

	this.lostFocus = function()
	{
		this.focused = false;

		if (!this.mouseOverMe && !this.online)
		{
			if (this.theDiv) this.theDiv.style.visibility = "hidden";
			this.visible = false;
		}
	}

	this.checkText = function()
	{
		var myself = this;

		if (this.focused)
		{
			this.search();
		}

		if (!this.searching && !this.theInput.value && this.online)
		{
			var thereIsData = false;

			try
			{
				if (autocompleteData)
				{
					thereIsData = true;
				}
			}
			catch(e){}

			if (thereIsData)
			{
				this.handleResults(autocompleteData);
				autocompleteData = "";
			}
		}

		setTimeout(function(){myself.checkText();}, 100);
	}

	this.positionTable = function(repeat)
	{
		if (!theOnlineDestination)
		{
			var myself = this;

			if (this.theDiv && this.theDiv.style.visibility == "visible" && trueTop(this.theInput) > 0)
			{
				this.theDiv.style.top = trueTop(this.theInput) + this.theInput.offsetHeight;

				var theLeft = trueLeft(this.theInput);
				if (theLeft + this.theDiv.offsetWidth > document.body.clientWidth + document.body.scrollLeft)
				{
					this.theDiv.style.left = theLeft + this.theInput.offsetWidth - this.theDiv.offsetWidth;
				}
				else this.theDiv.style.left = theLeft;
			}

			if (repeat) setTimeout(function(){myself.positionTable(true);}, 250);
		}
	}

	this.keyUpEvent = function(event)
	{
		if (event.keyCode == 38) //up arrow
		{
			//on macs the up arrow moves the caret to the beginning of the textbox
			stopKeyAction(event);
		}
	}

	this.keyPressEvent = function(event)
	{
		if (event.keyCode == 38) //up arrow
		{
			//on macs the up arrow moves the caret to the beginning of the textbox
			stopKeyAction(event);
		}
	}

	this.keyDownEvent = function(event)
	{
		if (event.keyCode == 13 || event.keyCode == 9 || event.keyCode == 39) //13 is enter and 9 is tab and 39 is right arrow
		{
			if (!this.online && (this.visible || this.searching))
			{
				if (listStyle) stopKeyAction(event);

				if (this.searching || this.theInput.value != this.lastSearch) this.waitingToSelect = true;
				else this.selectEntry();

				return false;
			}
		}
		else if (event.keyCode == 38) //up arrow
		{
			if (this.highlightedTR === null)
			{
				this.highlightTR(this.TRArray.length - 1);
			}
			else if (this.highlightedTR > 0)
			{
				this.highlightTR(this.highlightedTR - 1);
			}

			//on macs the up arrow moves the caret to the beginning of the textbox
			stopKeyAction(event);
		}
		else if (event.keyCode == 40) //down arrow
		{
			if (this.highlightedTR === null && this.TRArray.length)
			{
				this.highlightTR(0);
			}
			else if (this.highlightedTR + 1 < this.TRArray.length)
			{
				this.highlightTR(this.highlightedTR + 1);
			}
		}
		else
		{
			this.search();
		}
	}

	this.search = function()
	{
		var myself = this;

		if (trueTop(this.theInput) > 0 && (this.online || (theInput.value && this.caretPosition() == this.theInput.value.length && !/[,;]\s*$/.test(this.theInput.value))))
		{
			if (this.theDiv && this.highlightedTR !== null && theInput.value === this.lastSearch && !this.searching)
			{
				if (theOnlineDestination && positionMenu) positionMenu(menuArray[4], menuHeaderArray[4]);
				this.theDiv.style.visibility = "visible";
				this.visible = true;
			}

			if (!this.searching && this.theInput.value != this.lastSearch)
			{
				this.searching = true;
				this.lastSearch = theInput.value;

				var theURL = "matchemail=" + this.matchEmail + "&matchusername=" + this.matchUsername + "&limit=" + this.limit;
				if (this.theInput.value) theURL += "&text=" + theInput.value;
				else theURL += "&online=1";

				this.xhreq = createXMLHttpRequest();
				this.xhreq.open("post", "http://www.craterfish.org/autocomplete.php", true);
				this.xhreq.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
				this.xhreq.onreadystatechange = function(){myself.getResults();};
				this.xhreq.send(theURL);
			}
		}
		else if (!this.online)
		{
			if (this.theDiv) this.theDiv.style.visibility = "hidden";
			this.visible = false;
		}
	}

	this.getResults = function()
	{
		if (this.xhreq.readyState != 4) return;

		this.searching = false;

		var response = this.xhreq.responseText;

		this.handleResults(response);
	}

	this.handleResults = function(response)
	{
		var myself = this;

		var pieces = null;

		var detailArray = null;
		var i = null;
		var theTR = null;
		var theTD = null;
		var theImage = null;
		var str = null;
		var displayStr = null;
		var usefulStr = null;
		var noResults = false;
		var newSize = null;

		if (this.theDiv) this.theDiv.parentNode.removeChild(this.theDiv);
		this.highlightedTR = null;
		this.TRArray = new Array();

		this.theDiv = document.createElement("div");
		if (!theOnlineDestination)
		{
			this.theDiv.style.position = "absolute";
			this.theDiv.style.zIndex = 5;
		}
		this.theDiv.style.border = "2px outset #DDDDDD";
		this.theDiv.style.backgroundColor = "#FFFFFF";
		this.theDiv.style.overflowX = "hidden";
		this.theDiv.style.overflowY = "hidden";
		this.theDiv.style.visibility = "visible";//this is checked for with javascript
		//if (this.online) this.theDiv.onmousemove = function(){myself.theInput.focus();};

		this.theTable = document.createElement("table");
		this.theTable.cellSpacing = 0;
		this.theTable.cellPadding = 0;

		var theTBody = document.createElement("tbody");
		this.theTable.appendChild(theTBody);

		this.replaceLength = parseInt(response.match(/^(\d+)\./)[1]);
		response = response.substr(this.replaceLength.toString().length + 1);

		var detailNum = parseInt(response.match(/^(\d+)\./)[1]);
		response = response.substr(detailNum.toString().length + 1);

		var theRegExp = null;
		if (this.lastSearch)
		{
			var regExpStr = "";
			regExpStr += "(";
			regExpStr += this.lastSearch.substr(this.lastSearch.length - this.replaceLength).replace(/([\\()\[\]\.])/g, '\\$1');
			regExpStr += ")";

			theRegExp = new RegExp(regExpStr, "gi");
		}

		if (!response.length && this.online)
		{
			theTR = document.createElement("tr");
			theTBody.appendChild(theTR);

			theTD = document.createElement("td");
			theTD.style.color = "#FF0000";
			theTD.style.fontFamily = "arial";
			theTD.style.backgroundColor = "#FFD66E";
			theTD.style.borderTop = "1px solid #FF5D16";
			theTD.style.borderBottom = "1px solid #FF5D16";
			theTD.align = "center";
			theTD.style.width = "300px";

			theTD.innerHTML = "No Results Found";

			theTR.appendChild(theTD);

			noResults = true;
		}

		//yeah.. the CPU kept going to 100% and perhaps this might fix it???
		var lastLength = response.length + 1;
		while (response.length && response.length < lastLength)
		{
			lastLength = response.length;

			pieces = response.split(",", detailNum);

			detailArray = new Array();
			for (i = 0; i < detailNum; i++)
			{
				detailArray[i] = pieces[i];
				response = response.substr(detailArray[i].toString().length + 1);
			}

			for (i = 0; i < detailArray.length; i++)
			{
				detailArray[i] = response.substr(0, detailArray[i]);
				response = response.substr(detailArray[i].length);
			}

			usefulStr = "";
			if (detailArray[DETAILS_USERNAME])
			{
				usefulStr = detailArray[DETAILS_USERNAME];
			}
			else if (detailArray[DETAILS_EMAIL])
			{
				usefulStr = detailArray[DETAILS_EMAIL];
			}

			if (usefulStr)
			{
				theTR = document.createElement("tr");
				this.addTDFunctionality(theTR, usefulStr);
				theTR.style.cursor = "pointer";
				theTBody.appendChild(theTR);

				theTD = document.createElement("td");
				theTD.style.borderBottom = "1px solid #DDDDDD";
				theTR.appendChild(theTD);

				theImage = document.createElement("img");
				if (detailArray[DETAILS_EXTRA] == "email")
				{
					theImage.src = "http://www.craterfish.org/email.png";
				}
				else if (detailArray[DETAILS_EXTRA] == "buddy")
				{
					theImage.src = "http://www.craterfish.org/smilies/smile.png";
				}
				else if (detailArray[DETAILS_EXTRA] == "stranger")
				{
					theImage.src = "http://www.craterfish.org/smilies/hmm.png";
				}
				theTD.style.paddingRight = "5px";
				theTD.appendChild(theImage);

				theTD = document.createElement("td");
				theTD.innerHTML = detailArray[DETAILS_PICCODE];
				theTD.style.borderBottom = "1px solid #DDDDDD";
				theTD.style.paddingRight = "5px";
				theTR.appendChild(theTD);

				if (detailArray[DETAILS_USERNAME])
				{
					str = "";
					if (detailArray[DETAILS_FIRSTNAME])
					{
						str += detailArray[DETAILS_FIRSTNAME];
					}
					if (detailArray[DETAILS_LASTNAME])
					{
						if (str) str += " ";
						str += detailArray[DETAILS_LASTNAME];
					}

					newSize = 18;
					var theTD = document.createElement("td");
					if (str.length > 18)
					{
						newSize = 14 - (str.length - 14) / 2;
						if (newSize < 9) newSize = 9;
						theTD.style.fontSize = newSize + "px";
					}

					str = highlightText(str, theRegExp);
					if (!str) str = "&nbsp;";

					theTD.style.width = "1px";
					if (newSize == 18) str = str.replace(/ /g, "&nbsp;");
					theTD.innerHTML = str;
					theTD.style.borderBottom = "1px solid #DDDDDD";
					theTR.appendChild(theTD);

					theTD = document.createElement("td");
					theTD.innerHTML = highlightText(detailArray[DETAILS_USERNAME], theRegExp);
					theTD.className = detailArray[DETAILS_IDLE];
					theTD.style.borderBottom = "1px solid #DDDDDD";
					theTD.style.paddingLeft = "10px";
					theTD.style.paddingRight = "10px";
					theTD.style.fontSize = "13pt";
					theTD.style.fontWeight = "bold";
					theTD.style.textAlign = "right";
					theTD.style.whiteSpace = "nowrap";
					theTR.appendChild(theTD);
				}
				else if (detailArray[DETAILS_EMAIL])
				{
					theTD = document.createElement("td");
					theTD.innerHTML = highlightText(detailArray[DETAILS_EMAIL], theRegExp);
					theTD.style.borderBottom = "1px solid #DDDDDD";
					theTD.colSpan = 2;
					theTR.appendChild(theTD);
				}

				if (this.online)
				{
					theTD = document.createElement("td");
					theTD.style.borderBottom = "1px solid #DDDDDD";
					theTD.style.paddingLeft = "10px";
					theTD.style.paddingRight = "10px";
					theTD.title = "Send " + detailArray[DETAILS_USERNAME] + " a Message!";
					theTR.appendChild(theTD);

					theImage = document.createElement("img");
					theImage.src = "http://www.craterfish.org/email.png";
					theTD.appendChild(theImage);

					this.addEmailFunctionality(theTD, detailArray[DETAILS_USERNAME], theImage);
					addEvent(theTD, "mouseup", function(event){if (event.stopPropagation) {event.stopPropagation();} else event.cancelBubble = true;});


					theTD = document.createElement("td");
					theTD.style.borderBottom = "1px solid #DDDDDD";
					theTD.title = "Start a chat with " + detailArray[DETAILS_USERNAME] + "!";
					theTD.style.paddingRight = "10px";
					theTR.appendChild(theTD);

					theImage = document.createElement("img");
					theImage.src = "http://www.craterfish.org/graphics/IM.png";
					theTD.appendChild(theImage);

					this.addChatFunctionality(theTD, detailArray[DETAILS_ID], theImage)
					addEvent(theTD, "mouseup", function(event){if (event.stopPropagation) {event.stopPropagation();} else event.cancelBubble = true;});
				}

				if (this.highlightedTR === null && !this.online)
				{
					this.highlightTR(theTR.thisIndex);
				}
			}
		}

		if (!this.focused || usefulStr === null || (!this.online && (this.theInput.value == "" || this.theInput.value.length <= this.lastSearch.length - this.replaceLength)))
		{
			if (!this.online)
			{
				this.theDiv.style.visibility = "hidden";
				this.visible = false;
			}
		}
		else this.visible = true;

		this.theDiv.appendChild(this.theTable);

		if (theOnlineDestination)
		{
			theOnlineDestination.appendChild(this.theDiv);
		}
		else document.body.appendChild(this.theDiv);

		if (this.theTable.offsetHeight > 400)
		{
			this.theDiv.style.height = "400px";
			this.theDiv.style.overflowY = "scroll";

			this.theDiv.style.width = this.theTable.offsetWidth + 20;
		}
		else this.theDiv.style.width = this.theTable.offsetWidth;

		if (theOnlineDestination)
		{
			if (positionMenu) positionMenu(menuArray[4], menuHeaderArray[4]);
		}
		else if (!this.online)
		{
			this.positionTable();
		}

		if (this.visible && this.waitingToSelect && this.theInput.value === this.lastSearch)
		{
			this.waitingToSelect = false;
			this.selectEntry();
		}

		theTBody = null;
		theTD = null;
		theTR = null;
		theImage = null;
	}

	this.addChatFunctionality = function(theTD, theID, theImage)
	{
		var myself = this;

		theTD.onmouseup = function(evnt)
		{
			if (evnt) window.event = evnt;
			if (event.button != 2)
			{
				top.openingIM = true;
				top.openWindow(theID);
			}
		}

		theTD.onmouseover = function()
		{
			theImage.src = "http://www.craterfish.org/graphics/IM2.png";
		}

		theTD.onmouseout = function()
		{
			theImage.src = "http://www.craterfish.org/graphics/IM.png";
		}

		theTD.oncontextmenu = function(evnt)
		{
			if (evnt) window.event = evnt;

			if (event.stopPropagation) event.stopPropagation();
			event.cancelBubble = true;

			if (event.preventDefault) event.preventDefault();
			event.returnValue = false;
		}
	}

	this.addEmailFunctionality = function(theTD, theUsername, theImage)
	{
		var myself = this;

		theTD.onmouseup = function(evnt)
		{
			if (evnt) window.event = evnt;
			if (event.button != 2)
			{
				top.document.location = "http://www.craterfish.org/?compose.php?username=" + theUsername;
			}
		}

		theTD.onmouseover = function()
		{
			theImage.src = "http://www.craterfish.org/graphics/email2.png";
		}

		theTD.onmouseout = function()
		{
			theImage.src = "http://www.craterfish.org/email.png";
		}

		theTD.oncontextmenu = function()
		{
			myself.contextURL = "http://www.craterfish.org/?compose.php?username=" + theUsername;
		}
	}

	//this must be a separate function so that the variable references point to the right variables
	this.addTDFunctionality = function(theTD, str)
	{
		var myself = this;

		var thisIndex = this.TRArray.length;

		theTD.usefulStr = str;
		theTD.thisIndex = thisIndex;

		this.TRArray[thisIndex] = theTD;

		theTD.onmouseover = function()
		{
			myself.highlightTR(thisIndex);
			myself.mouseOverMe = true;
		}

		theTD.onmouseout = function()
		{
			myself.mouseOverMe = false;

			if (!myself.focused && !myself.online)
			{
				if (myself.theDiv) myself.theDiv.style.visibility = "hidden";
				myself.visible = false;
			}
		}

		theTD.oncontextmenu = function(evnt)
		{
			if (evnt) window.event = evnt;

			if (event.preventDefault) event.preventDefault();
			event.returnValue = false;

			if (myself.contextMenu) myself.contextMenu.parentNode.removeChild(myself.contextMenu);

			myself.cancelContextRemoval = true;
			myself.lastMouseDownWasContextMenu = true;

			myself.contextMenu = document.createElement("a");
			myself.contextMenu.style.position = "absolute";
			myself.contextMenu.style.left = event.clientX + 2;
			myself.contextMenu.style.top = event.clientY + 2;
			myself.contextMenu.innerHTML = "Open Link in New Tab";
			myself.contextMenu.style.border = "2px outset #DDDDDD";
			myself.contextMenu.target = "_blank";
			if (myself.contextURL)
			{
				myself.contextMenu.href = myself.contextURL;
				myself.contextURL = null;
			}
			else myself.contextMenu.href = "http://www.craterfish.org/users/" + str;
			myself.contextMenu.style.textDecoration = "none";
			myself.contextMenu.style.color = "#000000";
			myself.contextMenu.style.backgroundColor = "#FFFFFF";
			myself.contextMenu.style.zIndex = 100;
			myself.contextMenu.onclick = function(evnt)
			{
				if (evnt) window.event = evnt;
				if (event.button != 2) myself.removeContextMenu();
			}
			myself.contextMenu.onmouseover = function()
			{
				myself.contextMenu.style.backgroundColor = "#AAEEFF";
			}
			myself.contextMenu.onmouseout = function()
			{
				myself.contextMenu.style.backgroundColor = "#FFFFFF";
			}
			document.body.appendChild(myself.contextMenu);
		}

		if (this.online)
		{
			theTD.onmouseup = function(evnt)
			{
				if (evnt) window.event = evnt;
				if (event.button != 2) top.document.location = "http://www.craterfish.org/users/" + str;
			}
		}
		else
		{
			theTD.onmouseup = function(evnt)
			{
				if (evnt) window.event = evnt;
				if (event.button != 2) if (!myself.searching) myself.selectEntry();
			}
		}
	}

	this.selectEntry = function()
	{
		var myself = this;

		this.theDiv.style.visibility = "hidden";
		this.visible = false;

		this.theInput.value = this.theInput.value.substr(0, this.theInput.value.length - this.replaceLength) + myself.theText + (listStyle ? ", " : "");

		if (listStyle)
		{
			setTimeout(function()
			{
				myself.theInput.focus();

				//put the caret at the end & scroll to it (absolutely necessary in IE, nice for FF)
				if (usingIE)
				{
					var aRange = document.selection.createRange();
					aRange.move('character', myself.theInput.value.length);
					aRange.select();
				}
			}, 10); //it's actually very important that this be 10 and not 0, because when it's zero it makes it so that other keydown events that have been attached to the input don't happen.... very odd!
		}
	}

	this.caretPosition = function()
	{
		if (document.selection) //IE
		{
			var aRange = document.selection.createRange();

			aRange.moveStart ('character', -this.theInput.value.length);
			return aRange.text.length;
		}
		else if (this.theInput.selectionStart || this.theInput.selectionStart == '0') //FF
		{
			return this.theInput.selectionStart;
		}
	}

	this.highlightTR = function(theIndex)
	{
		if (this.highlightedTR !== null)
		{
			this.TRArray[this.highlightedTR].style.backgroundColor = "";
		}

		this.highlightedTR = theIndex;
		this.theText = this.TRArray[theIndex].usefulStr;

		this.TRArray[theIndex].style.backgroundColor = "#AAEEFF";
	}

	this.checkText();
	this.positionTable(true);
}
