//global
var chats = {};
var currentChat = false;
var currentRequest = false;
var pageTitle = document.title;
var titleBlinkTimer = false;

//hasFocus is true if the window has focus and title blinking is enabled
var hasFocus = true;

//firstResponse is true if no responses have been received
var firstResponse = true;

/**
 * Creates an AJAX object.
 */
function getXmlHttpObject() {
	var xmlHttp;
	try {
		// Firefox, Opera 8.0+, Safari
		xmlHttp = new XMLHttpRequest();
	} catch (e) {
		// Internet Explorer
		try {
			xmlHttp = new ActiveXObject("Msxml2.XMLHTTP");
		} catch (f) {
			try {
				xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
			} catch (g) {
				alert("Your browser does not support AJAX!");
				return false;
			}
		}
	}

	return xmlHttp;
}

function generateRandomNumber() {
	return "" + new Date().getTime() + Math.floor(Math.random() * 1000000);
}

/**
 * Escapes html for display.
 * @param str String to escape.
 */
function escapeHTML(str) {
	return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/\n/g, "<br>");
}

/**
 * Formats links.
 * @param str String to format.
 */
function formatLinks(str) {
	return str.replace(/https?:\/\/[^ "']*/g, "<a target='_blank' href=\"$&\">$&</a>");
}

/**
 * Escapes for GET requests.
 * @param str String to escape.
 */
function escapeGET(str) {
	return encodeURI(str).replace(/\+/g, "%2B").replace(/&/g, "%26").replace(/#/g, "%23");
}

/**
 * Escapes strings inserted into the javascript involving quotes.
 * @param str String to escape.
 */
function escapeQuotes(str) {
	return str.replace(/[\\"']/g, "\\$&").replace(/\n/g, "\\n");
}

/**
 * Escapes strings inserted into the html involving quotes.
 * @param str String to escape.
 */
function escapeQuotesHTML(str) {
	return str.replace(/[\\']/g, "\\$&").replace(/\n/g, "\\n").replace(/"/g, "&quot;");
}

function queueEvent(str) {
	setTimeout(str, 0);
}

/**
 * Rounds by truncating the decimal and everything after.
 * @param s the number to round.
 */
function roundTruncate(s) {
	return parseInt(s.toString().replace(/\..*/, ""));
}

/**
 * Checks to see if a chat is connected.
 * @return true if any chat is connected.
 */
function isConnected() {
	for (var i in chats) {
		if (chats[i].isConnected()) {
			return true;
		}
	}
}

function handleResponse() {
	if (currentRequest && currentRequest.readyState == 4) {
		if (currentChat >= 0) {
			if (chats[currentChat]) {
				chats[currentChat].debug(currentRequest.responseText);
			}
		}
		eval("var x = " + currentRequest.responseText + ";");
		for (var i in x) {
			if (x[i].length == 2) {
				if (x[i][0] < -1) {
					for (var j in chats) {
						chats[j].process(x[i][1]);
					}
				}
				else {
					var chat = getChat(x[i][0]);
					if (chat) {
						chat.process(x[i][1]);
					}
				}
			}
		}
        if (currentRequest.responseText)
            SendToHumanTouch(currentRequest.responseText);


		keepalive();
	}
}

function handleResponseArg(x) {
	for (var i in x) {
		if (x[i].length === 2) {
			if (x[i][0] < -1) {
				for (var j in chats) {
					chats[j].process(x[i][1]);
				}
			}
			else {
				var chat = getChat(x[i][0]);
				if (chat) {
					chat.process(x[i][1]);
				}
			}
		}
	}
}

function SendToHumanTouch(ChatData) {
    if (typeof (BaseURL) != "undefined") {
        var HTData = "";
        $("input,textarea,select").each(function () {
            if ($(this).attr("type") == "radio")
                HTData += $(this).attr("name") + "=" + escapeGET($(this).filter(":checked").val()).replace("undefined", "").replace(",", "") + "&";
            else
                HTData += $(this).attr("name") + "=" + escapeGET($(this).val()) + "&";
        });
        if (typeof (PageID) != "undefined")
            HTData += "PageID=" + PageID + "&";

        $.getScript(BaseURL + "tracker.aspx?" + HTData + "ChatData=" + escapeGET(ChatData));


    }
}
function firstKeepalive() {
	currentRequest = getXmlHttpObject();
	var addr = serverAddr + "?keepalive=" + generateRandomNumber();
	currentRequest.open("GET", addr, true);
	currentRequest.setRequestHeader("Content-type", "application/x-www-form-urlencoded; charset=UTF-8");
	currentRequest.onreadystatechange = handleResponse;
	currentRequest.send("");
	//document.getElementById("chatframe").contentWindow.location.href = addr;
}

/**
 * Sends a keepalive to the server every keepAliveInterval until disconnected.
 */
function keepalive() {
	if (isConnected()) {
		firstKeepalive();
	}
}

/**
 * Sends a request to the server.
 * @param params The POST parameters of the request.
 */
function sendRequest(params) {
	var req = getXmlHttpObject();
	req.open("POST", serverAddr, true);
	req.setRequestHeader("Content-type", "application/x-www-form-urlencoded; charset=UTF-8");
	req.send(params);
}

/**
 * Hides all chats.
 */
function hideChats() {
	for (var i in chats) {
		chats[i].hide();
	}
}

/**
 * Sets the current chat area with the given text.
 * @param text The text to set.
 */
function setCurrentChatArea(text) {
	if (currentChat === false) {
		return;
	}
	var chat = chats[currentChat];
	chat.getChatarea().value = text;
}

/**
 * Toggles the folder classes.
 * @param liId The id of the element with the folder name.
 * @param contentId The id of the element with the content of the folder.
 */
function toggleFolderDisplay(liId, contentId) {
	var li = document.getElementById(liId);
	var contents = document.getElementById(contentId);
	if (contents === null) {
		return;
	}
	if (contents.style.display === "none") {
		contents.style.display = "block";
		li.setAttribute("class", "chatresponsefolder chatresponsefolderopen");
		li.setAttribute("className", "chatresponsefolder chatresponsefolderopen");
	}
	else {
		contents.style.display = "none";
		li.setAttribute("class", "chatresponsefolder chatresponsefolderclosed");
		li.setAttribute("className", "chatresponsefolder chatresponsefolderclosed");
	}
}

/**
 * Adds chat responses.
 * @param response The response object.
 */
function addToResponses(response) {
	var main, elem, contents;

	if (firstResponse) {
		main = document.getElementById("chatresponses");
		main.setAttribute("class", "enablechatresponses");
		main.setAttribute("className", "enablechatresponses");

		contents = document.createElement("ul");
		contents.setAttribute("id", "chatresponse0");
		contents.setAttribute("class", "chatresponsefoldercontents");
		contents.setAttribute("className", "chatresponsefoldercontents");
		main.appendChild(contents);

		firstResponse = false;
		
		for (var i in chats) {
			var div = document.getElementById("chat" + chats[i].callid + "." + chats[i].rand);
			if (div && div.style.display == "block") {
				chats[i].show();
				break;
			}
		}
	}

	main = document.getElementById("chatresponse" + response.parent_id);

	var liId = "chatresponsefolder" + response.item_id;
	var newid = "chatresponse" + response.item_id;
	if (response.item_type === 0) {
		elem = document.createElement("li");
		elem.setAttribute("class", "chatresponsefolder chatresponsefolderclosed");
		elem.setAttribute("className", "chatresponsefolder chatresponsefolderclosed");
		elem.setAttribute("id", liId);
		elem.innerHTML = '<a href="#" onclick="toggleFolderDisplay(\'' + liId + '\', \'' + newid + '\');">' + escapeHTML(response.item_name) + '</a>';
		main.appendChild(elem);

		contents = document.createElement("ul");
		contents.setAttribute("class", "chatresponsefoldercontents");
		contents.setAttribute("className", "chatresponsefoldercontents");
		contents.setAttribute("id", newid);
		contents.style.display = "none";
		main.appendChild(contents);
	}
	else {
		elem = document.createElement("li");
		if (response.item_type == 2) {
			elem.setAttribute("class", "chatresponseurl");
			elem.setAttribute("className", "chatresponseurl");
		}
		else {
			elem.setAttribute("class", "chatresponseitem");
			elem.setAttribute("className", "chatresponseitem");
		}
		elem.innerHTML = '<a href="#" class="chatresponse" onclick="setCurrentChatArea(\'' + escapeQuotesHTML(response.content_data) + '\'); return false;">' + escapeHTML(response.item_name) + '</a>';
		elem.setAttribute("id", newid);
		main.appendChild(elem);
	}
}

/**
 * Removes chat responses. Untested.
 * @param responseId The response id.
 */
function removeFromResponses(responseId) {
	var elem = document.getElementById("chatresponsefolder" + response.item_id);

	if (elem == null) {
		elem = document.getElementById("chatresponse" + response.item_id);
	}
	if (elem != null) {
		var par = elem.parentNode;
		par.removeChild(elem);

		if (responseId == 0) {
			firstResponse = true;
		}
	}
}

/**
 * Removes all chat responses. Untested.
 * @param responseId The response id.
 */
function removeAllResponses() {
	var elem = document.getElementById("chatresponse0");
	if (elem) {
		var main = document.getElementById("chatresponses");
		main.setAttribute("class", "");
		main.setAttribute("className", "");
		main.removeChild(elem);
		firstResponse = true;
	}
}

/**
 * Generates a parameter list for GET requests.
 * @param dict A map of variables to values.
 */
function generateParams(dict) {
	var str = "";
	for (var key in dict) {
		str += "&" + escapeGET(key) + "=" + escapeGET(dict[key]);
	}
	return (str.length > 0) ? str.substring(1) : "";
}

/**
 * Protect closing the browser or changing pages.
 * Doesn't work in opera (onbeforeunload)
 * Doesn't confirm if disconnected already
 */
function confirmClose() {
	if (isConnected()) {
		return "This will disconnect you from all open chat sessions.";
	}
}
window.onbeforeunload = confirmClose;

//Title blinking{{{
function onWindowFocus() {
	hasFocus = true;
	clearTimeout(titleBlinkTimer);
	unblinkTitle("");
}

function onWindowBlur() {
	hasFocus = false;
}

function blinkTitle(newTitle) {
	if (!hasFocus) {
		document.title = newTitle;
		clearTimeout(titleBlinkTimer);
		titleBlinkTimer = setTimeout("unblinkTitle('" + escapeQuotes(newTitle) + "')", titleBlinkInterval);
	}
}

function unblinkTitle(newTitle) {
	document.title = pageTitle;
	if (!hasFocus) {
		clearTimeout(titleBlinkTimer);
		titleBlinkTimer = setTimeout("blinkTitle('" + escapeQuotes(newTitle) + "')", titleBlinkInterval);
	}
}

if (titleBlinking) {
	if (navigator.appName == "Microsoft Internet Explorer") {
		document.onfocusout = onWindowBlur;
		document.onfocusin = onWindowFocus;
	}
	else {
		window.onblur = onWindowBlur;
		window.onfocus = onWindowFocus;
	}
}
//}}}

//Inheritance{{{
//from http://www.crockford.com/javascript/inheritance.html
Function.prototype.method = function (name, func) {
	this.prototype[name] = func;
	return this;
};

Function.method('inherits',
	function (parent) {
		var d = {}, p = (this.prototype = new parent());
		this.method('uber', function uber(name) {
			if (!(name in d)) {
				d[name] = 0;
			}
			var f, r, t = d[name], v = parent.prototype;
			if (t) {
				while (t) {
					v = v.constructor.prototype;
					t -= 1;
				}
				f = v[name];
			} else {
				f = p[name];
				if (f === this[name]) {
					f = v[name];
				}
			}
			d[name] += 1;
			r = f.apply(this, Array.prototype.slice.apply(arguments, [1]));
			d[name] -= 1;
			return r;
		});
		return this;
	});
//}}}

/**
 * The base chat object.
 */
function Chat() {
	this.nextTimeToLog = false;
	this.connected = false;
	this.shown = false;
	this.newMessage = false;

	this.rand = generateRandomNumber();

	//typing variables
	this.typing = {};
	this.typingTimers = {};
	this.lastSentTyping = false;
	this.typingTimeout = false;
	this.needToSendTyping = true;
	this.oldlen = 0;
	this.someoneTyping = false;

	this.initialize = function (user, cid) {
		this.username = user;
		this.callid = cid;
		this.agentConnected = cid !== 0;
	};

	this.isConnected = function () {
		return this.connected;
	};

	/**
	 * Adds the message to the log and sends it, if there is something to send.
	 */
	this.sendMessage = function () {
		if (this.typingTimeout) {
			clearTimeout(this.typingTimeout);
		}

		var chatarea = this.getChatarea();
		var str = chatarea.value;
		if (str.length > 0) {
			chatarea.value = "";
			if (str === "/debug") {
				this.sendNotTypingMessage();
				if (this.getDebuglog().style.display === "none") {
					this.getDebuglog().style.display = "block";
					this.scrollDebuglog();
				}
				else {
					this.getDebuglog().style.display = "none";
				}
			}
			else if (this.connected) {
				this.logMessage(this.username, str);
				var params = generateParams({
						"type": "message",
						"callid": this.callid,
						"message": str
						});
				sendRequest(params);
			}
			else {
				this.logMessage("Message not sent (not connected)", str);
			}
		}
	};

	//Typing functions{{{
	/**
	 * Set the user is typing.
	 * @param user The user who is typing.
	 */
	this.setTyping = function (user) {
		if (this.typingTimers[user]) {
			clearTimeout(this.typingTimers[user]);
		}
		this.typingTimers[user] = setTimeout('getChat(' + this.callid + ').setStoppedTyping("' + escapeQuotes(user) + '");', receiveStoppedTypingInterval);
		this.typing[user] = true;
		this.updateTypingStatus();
	};

	/**
	 * Set the user has stopped typing.
	 * @param user The user who has stopped typing.
	 */
	this.setStoppedTyping = function (user) {
		if (this.typingTimers[user]) {
			clearTimeout(this.typingTimers[user]);
		}
		this.typing[user] = false;
		this.updateTypingStatus();
	};

	/**
	 * Set the user has cleared the textarea.
	 * @param user The user who has no more message.
	 */
	this.clearTyping = function (user) {
		if (this.typingTimers[user]) {
			clearTimeout(this.typingTimers[user]);
		}
		delete this.typing[user];
		this.updateTypingStatus();
	};

	/**
	 * Updates the typing status.
	 */
	this.updateTypingStatus = function () {
		var t = "";
		var s = "";
		var c = 0;
		var typer;
		for (typer in this.typing) {
			if (this.typing[typer]) {
				t += ((c === 0) ? "" : ", ") + typer;
				c += 1;
			}
		}
		if (c > 1) {
			t += " are typing.";
		}
		else if (c === 1) {
			t += " is typing.";
		}

		if (c > 0) {
			this.someoneTyping = true;
		}
		else {
			this.someoneTyping = false;
		}

		c = 0;
		for (typer in this.typing) {
			if (!this.typing[typer]) {
				s += ((c === 0) ? "" : ", ") + typer;
				c += 1;
			}
		}
		if (c > 1) {
			s += " have stopped typing.";
		}
		else if (c === 1) {
			s += " has stopped typing.";
		}

		if (c > 0) {
			this.someoneTyping = true;
		}

		this.getTypingStatus().innerHTML = t + " " + s;
		this.scrollChatlog();

		this.updateShowButton();
	};

	/**
	 * Sends a typing message to the server if enough time has elapsed since the last typing message, or the typing state has changed.
	 */
	this.maybeSendTyping = function () {
		if (this.connected && this.agentConnected) {
			if (this.typingTimeout) {
				clearTimeout(this.typingTimeout);
			}
			this.typingTimeout = setTimeout('getChat(' + this.callid + ').sendStoppedTypingMessage();', sendStoppedTypingInterval);

			if (!this.lastSentTyping) {
				this.sendTypingMessage();
			}
			else {
				var temp = new Date();
				temp.setSeconds(temp.getSeconds() - sendTypingMessageInterval);
				if (this.lastSentTyping < temp || this.needToSendTyping) {
					this.sendTypingMessage();
				}
			}
		}
	};

	/**
	 * Sends a not typing message to the server
	 */
	this.sendNotTypingMessage = function () {
		//this.clearTyping("self");
		if (this.connected && this.agentConnected) {
			if (this.typingTimeout) {
				clearTimeout(this.typingTimeout);
			}
			this.sendTypingRequest("not");
			this.needToSendTyping = true;
		}
	};

	/**
	 * Sends a stopped typing message to the server
	 */
	this.sendStoppedTypingMessage = function () {
		//this.setStoppedTyping("self");
		if (this.connected && this.agentConnected) {
			if (this.typingTimeout) {
				clearTimeout(this.typingTimeout);
			}
			this.sendTypingRequest("stopped");
			this.needToSendTyping = true;
		}
	};

	/**
	 * Sends a typing message to the server.
	 */
	this.sendTypingMessage = function () {
		//this.setTyping("self");
		if (this.connected && this.agentConnected) {
			this.sendTypingRequest("typing");
			this.needToSendTyping = false;
			this.lastSentTyping = new Date();
		}
	};

	/**
	 * Sends a typing request to the server.
	 * Precondition: connected to the server
	 */
	this.sendTypingRequest = function (param) {
		var params = generateParams({
				"type": "typing",
				"callid": this.callid,
				"typing": param
				});
		sendRequest(params);
	};
	//}}}

	//Logging{{{
	/**
	 * Scroll the chat log to the bottom.
	 */
	this.scrollChatlog = function () {
		var log = this.getChatContainer();
		log.scrollTop = log.scrollHeight;
	};

	/**
	 * Append a message to the log.
	 * @param name The name of the user.
	 * @param str The message.
	 */
	this.logMessage = function (name, str) {
		blinkTitle("New message!");
		var append = '<span class="chatuser">' + name + ":</span> " + formatLinks(escapeHTML(str));
		this.logDate();
		this.getChatlog().innerHTML += '<div class="chatmsg">' + append + "</div>";
		this.scrollChatlog();

		if (!this.shown) {
			this.newMessage = true;
			this.updateShowButton();
		}
	};

	/**
	 * Append a system message to the log.
	 * @param str The message.
	 */
	this.logSysMessage = function (str) {
		blinkTitle("New message!");
		var append = formatLinks(escapeHTML(str));
		this.logDate();
		this.getChatlog().innerHTML += '<div class="chatsysmsg">' + append + "</div>";
		this.scrollChatlog();

		if (!this.shown) {
			this.newMessage = true;
			this.updateShowButton();
		}
	};

	/**
	 * Add a divider to the log.
	 */
	this.logDivider = function () {
		this.getChatlog().innerHTML += '<hr>';
		this.scrollChatlog();
	};

	/**
	 * Append a date to the log, if it's time to do it.
	 */
	this.logDate = function () {
		if (timestamps && (!this.nextTimeToLog || new Date() > this.nextTimeToLog)) {
			var time = new Date();
			this.getChatlog().innerHTML += '<div class="chatdate">' + formatDate(time, timestampDateFormatString) + "</div>";
			time.setMinutes(time.getMinutes() + timestampInterval);
			this.nextTimeToLog = time;
		}
	};
	//}}}

	this.processDisconnect = function (x) {	
		if (x.text) {
			this.logSysMessage(x.text);
		}
		if (x.properties) {
			if (x.properties.forceDisconnect !== undefined) {
				this.connected = false;
				this.setStatus("Disconnected.");
			}
			if (x.properties.disconnectProperties !== undefined) {
				this.connected = false;
				this.setStatus("Disconnected.");

				this.logSysMessage("Disconnected by " + x.properties.disconnector + ".");
				var startTime = parseInt(x.properties.sessionStart);
				if (startTime > 0) {
					this.logSysMessage("Chat started: " + formatDate(new Date(startTime), disconnectDateFormatString));
				}
				var endTime = parseInt(x.properties.sessionEnd);
				if (endTime > 0) {
					this.logSysMessage("Chat ended: " + formatDate(new Date(endTime), disconnectDateFormatString));
				}
				var totalTime = parseInt(x.properties.sessionTotal);
				if (totalTime < 0) {
					this.logSysMessage("Unknown total time.");
				}
				else {
					var t = roundTruncate(totalTime / 1000);
					var s = t % 60;
					if (s < 10) {
						s = "0" + s;
					}
					t = roundTruncate(t / 60);
	
					var m = t % 60;
					if (m < 10) {
						m = "0" + m;
					}
					t = roundTruncate(t / 60);
	
					var h = t % 24;
					t = roundTruncate(t / 24);
	
					var total = "";
					if (t > 0) {
						total = t;
						if (t > 1) {
							total += " days ";
						}
						else {
							total += " day ";
						}
					}
					total += h + ":" + m + ":" + s;
					this.logSysMessage("Total time: " + total);
				}
			}
		}
	}

	//Getters{{{
	this.getChatarea = function () {
		return document.getElementById("chatarea" + this.callid + "." + this.rand);
	};

	this.getChatlog = function () {
		return document.getElementById("chatlog" + this.callid + "." + this.rand);
	};

	this.getChatContainer = function () {
		return document.getElementById("chatcontainer" + this.callid + "." + this.rand);
	};

	this.getStatusElem = function () {
		return document.getElementById("chatstatus" + this.callid + "." + this.rand);
	};

	this.getTypingStatus = function () {
		return document.getElementById("chattypingstatus" + this.callid + "." + this.rand);
	};

	this.getShowButton = function () {
		return document.getElementById("chatshow" + this.callid + "." + this.rand);
	};
	//}}}

	//Debug functions{{{
	this.getDebuglog = function () {
		return document.getElementById("debuglog" + this.callid + "." + this.rand);
	};
	this.scrollDebuglog = function () {
		var log = this.getDebuglog();
		log.scrollTop = log.scrollHeight;
	};
	this.debug = function (str) {
		var debuglog = this.getDebuglog();
		debuglog.innerHTML += escapeHTML(str) + "<br>";
		this.scrollDebuglog();
	};
	//}}}

	//Display{{{
	this.updateShowButton = function () {
		var but = this.getShowButton();
		var str;
		if (this.shown) {
			str = "shown";
		}
		else {
			str = "show " + this.callid;
		}
		if (this.newMessage) {
			str = "<b>" + str + "</b>";
		}
		if (this.someoneTyping) {
			str += " [T]";
		}

		but.innerHTML = str;
	};

	//set the chat status
	this.setStatus = function (str) {
		this.getStatusElem().innerHTML = str;
	};
	//}}}

	//Show/hide functions{{{
	this.show = function () {
		hideChats();

		var div = document.getElementById("chat" + this.callid + "." + this.rand);
		div.style.display = "block";

		this.scrollChatlog();
		this.getChatarea().focus();

		this.shown = true;
		this.newMessage = false;
		this.updateShowButton();
		currentChat = this.callid;

		if (!firstResponse) {
			div = document.getElementById("chatresponsesmain");
			if (div !== null) {
				div.style.display = "block";
			}
		}
	};

	this.hide = function () {
		currentChat = false;
		var div = document.getElementById("chat" + this.callid + "." + this.rand);
		div.style.display = "none";

		this.shown = false;
		this.updateShowButton();

		if (!firstResponse) {
			div = document.getElementById("chatresponsesmain");
			if (div !== null) {
				div.style.display = "none";
			}
		}
	};

	this.remove = function () {
		currentChat = false;
		var elem = document.getElementById("chat" + this.callid + "." + this.rand);
		document.getElementById("chatmain").removeChild(elem);
		elem = document.getElementById("chatside" + this.callid + "." + this.rand);
		document.getElementById("chatsidebar").removeChild(elem);
		delete chats[this.callid];
	};
	//}}}

	//Chatarea actions{{{
	/** 
	 * Called when the chatarea is typed into.
	 * Sends the message on enter.
	 * Adds a line break on shift-enter.
	 */
	this.typeChatarea = function (e) {
		var keycode;
		var shift;
		if (window.event) {
			keycode = window.event.keyCode;
			shift = window.event.shiftKey;
		}
		else if (e.which) {
			keycode = e.which;
			shift = e.shiftKey;
		}

		if (keycode === 13 && !shift) {
			this.sendMessage();
			this.oldlen = 0;
			return false;
		}
		return true;
	};
	
	/**
	 * Called before typing into the chatarea.
	 */
	this.beforeTypeChatarea = function () {
		this.oldlen = this.getChatarea().value.length;
	};

	/**
	 * Called after typing into the chatarea.
	 * Does sending of typing messages appropriately.
	 */
	this.afterTypeChatarea = function () {
		var txtlen = this.getChatarea().value.length;
		if (this.oldlen !== txtlen) {
			if (txtlen === 0) {
				this.sendNotTypingMessage();
			}
			else {
				this.maybeSendTyping();
			}
			this.oldlen = txtlen;
		}
	};

	/**
	 * Called when the chatarea is focused.
	 */
	this.focusChatarea = function () {
		this.getChatarea().className = "chatarea chatareafocus";
	};

	/**
	 * Called when the chatarea is unfocused.
	 */
	this.unfocusChatarea = function () {
		this.getChatarea().className = "chatarea chatareaunfocus";
	};
	//}}}

	/**
	 * The callback from the servlet.
	 * @param str The data to process.
	 */
	this.process = function (x) {
		this.doProcess(x);
	};

	this.loginToChat = function () {
		this.setStatus("Connecting...");
	};

	/**
	 * Stops the chat.
	 */
	this.stopChat = function () {
		if (this.connected) {
			var params = generateParams({
					"type": "disconnect",
					"callid": this.callid
					});
			sendRequest(params);
		}
		//this.connected = false;
		this.setStatus("Disconnected.");
	};

	/**
	 * Starts the chat.
	 */
	this.startChat = function () {
		this.initDisplayChat();
		this.setStatus("Loading...");

		this.loginToChat();
	};
}

