/******************************************************************************
 * apc.js
 * ----------------------------------------------------------------------------
 * DO NOT MODIFY OR REMOVE THIS COPYRIGHT SECTION
 * ----------------------------------------------------------------------------
 * Author       : Marco Cosentino (technics@alice.it)
 * Copyright    : 2009 (c) Marco Cosentino
 * License      : GPL 2.0
 * Application  : AJAX Perl chat
 * Version      : 0.1
 * Date Started : 2009/02/15
 * Last Modified: 
 *
 * This is a shoubox written in Perl / Javascript
 *
 
  This file is part of AJAX Perl chat.

    AJAX Perl chat is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    AJAX Perl chat is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with AJAX Perl chat.  If not, see <http://www.gnu.org/licenses/>.

 ******************************************************************************/
 
 
function AJAXPerlChat() 
{
	// Config params
	this.cgiDir = "/cgi-bin/apc/";
	this.documentDir = "/apc/";
	///////////////////////////
	
	this.ajax = false;
	this.chatFrame = null;
	
	this.lastMsgId = 0;
	this.failedRequests = 0;
	
	this.stick = true;
	this.started = false;	
	this.resetted = false;
	
	this.nickInput = null;
	this.textInput = null;
	this.adminLink = null;
	
	this.refreshAJAXObj = null;
	this.submitAJAXObj = null;
}

AJAXPerlChat.prototype.InstallAJAXObjects = function()
{
	var self = this;

	// The AJAX Objects
	this.refreshAJAXObj = new AJAXObj();
	this.submitAJAXObj = new AJAXObj();
	
	
	
	// Data receive callback for refresh request
	this.refreshAJAXObj.onReceiveResponse = function(status,statusText,responseText)
	{
		switch(status)
		{
			case 200:
				self.failedRequests = 0;
				if(responseText != "")
					self.ReceiveChatData(responseText);
				break;
			default:
				// We had some troubles
				self.HandleFailedRequest();				
				break;
		}		
	}
		
	// Timeout callback for refresh request
	this.refreshAJAXObj.onRequestTimeout = function()
	{
		// We had timeout
		self.refreshAJAXObj.abort();
		//self.PushChatData('<div class="apc_chatentry">DEBUG : HTTP request timeout during refresh</div>');
		self.HandleFailedRequest();
	}
	if(this.refreshAJAXObj.CreateRequest())
		this.ajax = true;
	else
		return;

	
	// Data receive callback for submit request
	this.submitAJAXObj.onReceiveResponse = function(status,statusText,responseText)
	{
		self.nickInput.disabled = false;
		self.textInput.disabled = false;

		if(status != 200)
		{
			// We had some troubles
			self.HandleFailedRequest();
		}
		else
		{
			self.textInput.value = "";
			self.textInput.focus();
		}
	}
		
	// Timeout callback for submit request
	this.submitAJAXObj.onRequestTimeout = function()
	{
		// We had timeout
		self.submitAJAXObj.abort();
		self.HandleFailedRequest();
	}
	
	this.submitAJAXObj.onRequestAborted = function()
	{
		if( self.nickInput != undefined )
			self.nickInput.disabled = false;
		if( self.nickInput != undefined )
			self.textInput.disabled = false;
	}

	if(this.submitAJAXObj.CreateRequest())
		this.ajax = true;
	else
		return;
}

// This function can be overriden to install different handlers or to use different objects
AJAXPerlChat.prototype.InstallControls = function()
{
	var self = this;
	
	this.chatFrame = document.getElementById("apc_chatframe");	
	
	// Install handlers for chat controls
	this.nickInput = document.getElementById("apc_nick");
	this.textInput = document.getElementById("apc_text");
	this.adminLink = document.getElementById("apc_adminlink");
	
	this.nickInput.disabled = true;
	this.textInput.disabled = true;
	
	this.nickInput.onfocus = 	function(event) { if(self.nickInput.value == 'Nickname') self.nickInput.value = ''; }
	this.nickInput.onblur =  	function(event) { if(self.nickInput.value == '') self.nickInput.value = 'Nickname'; }
	this.nickInput.onkeydown = 	function(event) { if(event == undefined) event = window.event; if(event.keyCode && event.keyCode==13) self.textInput.focus(); }
	
	this.textInput.onkeydown = 	function(event) { if(event == undefined) event = window.event; if(event.keyCode && event.keyCode==13) self.Submit(); }
	this.adminLink.onclick = function(event)
	{
		open(self.documentDir + 'admin.html','AjaxPerlChatADMIN','width=620,height=500,status');
	}
	
	this.chatFrame.onscroll = function(event) 
	{ 
		if(self.chatFrame.scrollTop == self.chatFrame.scrollHeight - self.chatFrame.clientHeight)
			self.stick = true;
		else
			self.stick = false;
	}
}

AJAXPerlChat.prototype.Start = function()
{
	var self = this;
	this.interval = setInterval(function(){self.Refresh()},1000);
	this.started = true;
	
	if( this.nickInput != undefined )
		this.nickInput.disabled = false;
	if( this.textInput != undefined )
		this.textInput.disabled = false;
}

AJAXPerlChat.prototype.Stop = function()
{
	if(this.interval)
		clearInterval(this.interval);
	if(this.overloadTimer)
		clearTimeout(this.overloadTimer);
	this.started = false;
	
	if( this.nickInput != undefined )
		this.nickInput.disabled = true;
	if( this.textInput != undefined )
		this.textInput.disabled = true;
}

AJAXPerlChat.prototype.Overload = function()
{
	var self = this;
	this.Stop();
	this.PushChatData("<div class=\"apc_chatentry\">La chat &egrave; temporaneamente fuori uso. Attendere 10 secondi</div>");

	this.overloadTimer = setTimeout(function(){ self.Reset(); self.Start()},10000);
}

AJAXPerlChat.prototype.Refresh = function()
{
	if(!this.ajax || !this.started) return;
	this.refreshAJAXObj.SendRequest(this.cgiDir + "refresh.cgi?lid=" + this.lastMsgId,null,950,false);
}

AJAXPerlChat.prototype.Reset = function()
{
	this.resetted = true;
	this.lastMsgId = 0;
	this.failedRequests = 0;
}

AJAXPerlChat.prototype.ReceiveChatData = function(receivedText)
{
	if(receivedText == 'RESET')
	{
		this.Reset();
		return;
	}
	
	// Here we format the data
	var lines = receivedText.split('\n');
	var output = "";
	
	for(var i = 0; i<lines.length;i++)
	{
		var elements = lines[i].split('|');
		if(elements.length < 5)	continue;
		if(elements.length < 6)	elements[5] = "";
		//0:MSGID 1:IP 2:DATE 3:TIME 4:NICK 5:MESSAGE
		elements[5] = htmlentities(decode_utf8(elements[5]));
		output += '<div class="apc_chatentrydiv"><table><tr><td class="apc_littledate">' + elements[2] + '<br />' + elements[3] + '</td><td class="apc_chatentry"><span class = "apc_chatentrynick">' + elements[4] + ':</span> <span class = "apc_chatentrytext">' + elements[5] + '</span></td></tr></table></div>';
		this.lastMsgId = elements[0];
	}
	if(this.resetted)
	{
		this.resetted = false;
		this.chatFrame.innerHTML = "";
	}
	this.PushChatData(output);
}

AJAXPerlChat.prototype.PushChatData = function(formatted)
{
	this.chatFrame.innerHTML += formatted;
	if(this.chatFrame.scrollHeight > this.chatFrame.clientHeight && this.stick)
		this.chatFrame.scrollTop = this.chatFrame.scrollHeight - this.chatFrame.clientHeight;
}

AJAXPerlChat.prototype.Submit = function()
{
	if(!this.ajax) return;
	if(!this.started) return;
	
	// For old browser compatibility
	var username,usertext;
	if (encodeURIComponent) 
	{
    	username = encodeURIComponent(this.nickInput.value);
		usertext = encodeURIComponent(this.textInput.value);
	} 
	else 
	{
    	username = escape(this.nickInput.value);
		usertext = escape(this.textInput.value);
	}
	this.submitAJAXObj.SendRequest(this.cgiDir + "incoming.cgi?user=" + username + "&text=" + usertext,null,1500,false);
	
	if( this.nickInput != undefined )
		this.nickInput.disabled = true;
	if( this.textInput != undefined )
		this.textInput.disabled = true;
}
 
AJAXPerlChat.prototype.HandleFailedRequest = function()
{		
	this.failedRequests ++;
	if(this.failedRequests > 5) this.Overload();
}

function decode_utf8( s )
{
  return decodeURIComponent( escape( s ) );
}

function htmlentities (string, quote_style) {
    // http://kevin.vanzonneveld.net
    // +   original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +    revised by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +   improved by: nobbler
    // +    tweaked by: Jack
    // +   bugfixed by: Onno Marsman
    // +    revised by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // -    depends on: get_html_translation_table
    // *     example 1: htmlentities('Kevin & van Zonneveld');
    // *     returns 1: 'Kevin &amp; van Zonneveld'
 
    var histogram = {}, symbol = '', tmp_str = '', entity = '';
    tmp_str = string.toString();
    
    if (false === (histogram = get_html_translation_table('HTML_ENTITIES', quote_style))) {
        return false;
    }
    
    for (symbol in histogram) {
        entity = histogram[symbol];
        tmp_str = tmp_str.split(symbol).join(entity);
    }
    
    return tmp_str;
}

function get_html_translation_table(table, quote_style) {
    // http://kevin.vanzonneveld.net
    // +   original by: Philip Peterson
    // +    revised by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +   bugfixed by: noname
    // +   bugfixed by: Alex
    // +   bugfixed by: Marco
    // %          note: It has been decided that we're not going to add global
    // %          note: dependencies to php.js. Meaning the constants are not
    // %          note: real constants, but strings instead. integers are also supported if someone
    // %          note: chooses to create the constants themselves.
    // %          note: Table from http://www.the-art-of-web.com/html/character-codes/
    // *     example 1: get_html_translation_table('HTML_SPECIALCHARS');
    // *     returns 1: {'"': '&quot;', '&': '&amp;', '<': '&lt;', '>': '&gt;'}
    
    var entities = {}, histogram = {}, decimal = 0, symbol = '';
    var constMappingTable = {}, constMappingQuoteStyle = {};
    var useTable = {}, useQuoteStyle = {};
    
    useTable      = (table ? table.toUpperCase() : 'HTML_SPECIALCHARS');
    useQuoteStyle = (quote_style ? quote_style.toUpperCase() : 'ENT_COMPAT');
    
    // Translate arguments
    constMappingTable[0]      = 'HTML_SPECIALCHARS';
    constMappingTable[1]      = 'HTML_ENTITIES';
    constMappingQuoteStyle[0] = 'ENT_NOQUOTES';
    constMappingQuoteStyle[2] = 'ENT_COMPAT';
    constMappingQuoteStyle[3] = 'ENT_QUOTES';
    
    // Map numbers to strings for compatibilty with PHP constants
    if (!isNaN(useTable)) {
        useTable = constMappingTable[useTable];
    }
    if (!isNaN(useQuoteStyle)) {
        useQuoteStyle = constMappingQuoteStyle[useQuoteStyle];
    }
    
    if (useQuoteStyle != 'ENT_NOQUOTES') {
        entities['34'] = '&quot;';
    }
 
    if (useQuoteStyle == 'ENT_QUOTES') {
        entities['39'] = '&#039;';
    }
 
    if (useTable == 'HTML_SPECIALCHARS') {
        // ascii decimals for better compatibility
        entities['38'] = '&amp;';
        entities['60'] = '&lt;';
        entities['62'] = '&gt;';
    } else if (useTable == 'HTML_ENTITIES') {
        // ascii decimals for better compatibility
      entities['38']  = '&amp;';
      entities['60']  = '&lt;';
      entities['62']  = '&gt;';
      entities['160'] = '&nbsp;';
      entities['161'] = '&iexcl;';
      entities['162'] = '&cent;';
      entities['163'] = '&pound;';
      entities['164'] = '&curren;';
      entities['165'] = '&yen;';
      entities['166'] = '&brvbar;';
      entities['167'] = '&sect;';
      entities['168'] = '&uml;';
      entities['169'] = '&copy;';
      entities['170'] = '&ordf;';
      entities['171'] = '&laquo;';
      entities['172'] = '&not;';
      entities['173'] = '&shy;';
      entities['174'] = '&reg;';
      entities['175'] = '&macr;';
      entities['176'] = '&deg;';
      entities['177'] = '&plusmn;';
      entities['178'] = '&sup2;';
      entities['179'] = '&sup3;';
      entities['180'] = '&acute;';
      entities['181'] = '&micro;';
      entities['182'] = '&para;';
      entities['183'] = '&middot;';
      entities['184'] = '&cedil;';
      entities['185'] = '&sup1;';
      entities['186'] = '&ordm;';
      entities['187'] = '&raquo;';
      entities['188'] = '&frac14;';
      entities['189'] = '&frac12;';
      entities['190'] = '&frac34;';
      entities['191'] = '&iquest;';
      entities['192'] = '&Agrave;';
      entities['193'] = '&Aacute;';
      entities['194'] = '&Acirc;';
      entities['195'] = '&Atilde;';
      entities['196'] = '&Auml;';
      entities['197'] = '&Aring;';
      entities['198'] = '&AElig;';
      entities['199'] = '&Ccedil;';
      entities['200'] = '&Egrave;';
      entities['201'] = '&Eacute;';
      entities['202'] = '&Ecirc;';
      entities['203'] = '&Euml;';
      entities['204'] = '&Igrave;';
      entities['205'] = '&Iacute;';
      entities['206'] = '&Icirc;';
      entities['207'] = '&Iuml;';
      entities['208'] = '&ETH;';
      entities['209'] = '&Ntilde;';
      entities['210'] = '&Ograve;';
      entities['211'] = '&Oacute;';
      entities['212'] = '&Ocirc;';
      entities['213'] = '&Otilde;';
      entities['214'] = '&Ouml;';
      entities['215'] = '&times;';
      entities['216'] = '&Oslash;';
      entities['217'] = '&Ugrave;';
      entities['218'] = '&Uacute;';
      entities['219'] = '&Ucirc;';
      entities['220'] = '&Uuml;';
      entities['221'] = '&Yacute;';
      entities['222'] = '&THORN;';
      entities['223'] = '&szlig;';
      entities['224'] = '&agrave;';
      entities['225'] = '&aacute;';
      entities['226'] = '&acirc;';
      entities['227'] = '&atilde;';
      entities['228'] = '&auml;';
      entities['229'] = '&aring;';
      entities['230'] = '&aelig;';
      entities['231'] = '&ccedil;';
      entities['232'] = '&egrave;';
      entities['233'] = '&eacute;';
      entities['234'] = '&ecirc;';
      entities['235'] = '&euml;';
      entities['236'] = '&igrave;';
      entities['237'] = '&iacute;';
      entities['238'] = '&icirc;';
      entities['239'] = '&iuml;';
      entities['240'] = '&eth;';
      entities['241'] = '&ntilde;';
      entities['242'] = '&ograve;';
      entities['243'] = '&oacute;';
      entities['244'] = '&ocirc;';
      entities['245'] = '&otilde;';
      entities['246'] = '&ouml;';
      entities['247'] = '&divide;';
      entities['248'] = '&oslash;';
      entities['249'] = '&ugrave;';
      entities['250'] = '&uacute;';
      entities['251'] = '&ucirc;';
      entities['252'] = '&uuml;';
      entities['253'] = '&yacute;';
      entities['254'] = '&thorn;';
      entities['255'] = '&yuml;';
    } else {
        throw Error("Table: "+useTable+' not supported');
        return false;
    }
    
    // ascii decimals to real symbols
    for (decimal in entities) {
        symbol = String.fromCharCode(decimal);
        histogram[symbol] = entities[decimal];
    }
    
    return histogram;
}