/**
 * @package JLive! Chat
 * @version 3.6.4
 * @copyright (C) Copyright 2008-2009 CMS Fruit, CMSFruit.com. All rights reserved.
 * @license GNU/GPL http://www.gnu.org/licenses/gpl-3.0.txt

This program 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.

This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
 */

var liveChatUri = 'index.php?option=com_livechat&view=popup&do_not_log=true';
var liveChatWindow = null;

var client = null;
var config = new Array();
var chatSessionId = null;
var chatSessionActive = 0;
var chatSessionMdate = 0;
var chatClientName = null;

var refreshTimer = null;
var refreshTimerDelay = 1.5; // in seconds

var preChat = null;
var inChat = null;

var msgInput = null;
var sessionDisplay = null;
var name = null;
var errorLayer = null;
var introLayer = null;
var msgLayer = null;
var nameLayer = null;
var continueLayer = null;
var closeLayer = null;
var statusDisplayLayer = null;
var continueBtn = null;
var nameInput = null;
var operatorIsTyping = false;
var clientIsTyping = 0;
var typingTimeoutTimer = null;

var preChatSelector = 'pre-chat';
var inChatSelector = 'in-chat';
var msgInputSelector = 'msg-input';
var sessionDisplaySelector = 'session-content-display';
var statusDisplaySelector = 'status-display';
var nameSelector = 'name';
var errorWrapperSelector = 'error-wrapper';
var introWrapperSelector = '.intro-wrapper';
var msgWrapper = 'msg-wrapper';
var nameContainerSelector = 'name-container';
var continueLayerSelector = '.continue-wrapper';
var closeWrapperSelector = 'p.close-wrapper';
var sendBtnSelector = '#in-chat .send-button';

var processingSomething = false;
var chatIsOffline = false;

var connectingMsg = 'Connecting, please wait...';

var ChatSession = {
    end: function(){
	endChatSession();
    }
};

function attachCloseEvent()
{
    window.addEvent('domready', function() {
	window.addListener('beforeunload', function(){
	    window.addListener('unload', ChatSession.end);
	    if (window.ie) window.addListener('unload', ChatSession.end);
	});
    });
}

function requestLiveChat(popupUri)
{
    var w = 480, h = 340;

    if(screen.availWidth && screen.availHeight) {
        w = screen.availWidth;
        h = screen.availHeight;
    }
    
    var popW = 340;
    var popH = 315;
	
    if(window.webkit)
    {
        //	Safari popup window should be about 10px more
        popW = 350;
        popH = 325;
    }
	
    var leftPos = (w-popW)/2, topPos = (h-popH)/2;

    liveChatWindow = window.open(popupUri,'LiveChatWindow','menubar=0,scrollbars=0,status=1,resizable=0,location=0,toolbar=0,height='+popH+',width='+popW+',left='+leftPos+',top='+topPos);
    
    if (window.focus) {
        liveChatWindow.focus();
    }

    return false;
}

function initLayers(callbackFunc)
{
    loadConfig(callbackFunc);
	
    preChat = $(preChatSelector);
    inChat = $(inChatSelector);
	
    msgInput = $(msgInputSelector);
    sessionDisplay = $(sessionDisplaySelector);
    name = $(nameSelector);
    errorLayer = $(errorWrapperSelector);
    introLayer = $$(introWrapperSelector);
    msgLayer = $(msgWrapper);
    nameLayer = $(nameContainerSelector);
    statusDisplayLayer = $(statusDisplaySelector);
    continueLayer = $$(continueLayerSelector);
    closeLayer = $$(closeWrapperSelector);
	
    sendBtn = $$(sendBtnSelector);
	
    continueBtn = $$(continueLayerSelector).getElement('input[type=image]');
    nameInput = $(nameContainerSelector).getElement('input[type=text]');
    closeBtn = $$(closeWrapperSelector).getElement('input[type=image]');

    if(nameInput)
    {
        nameInput.addEvent('keydown', function (event) {
            if(event.keyCode == 13)
            {
                //	user pressed enter on the keyboard
                initChatSession();
				
                return false;
            }
        });
    }
	
    if($(msgInputSelector))
    {
        $(msgInputSelector).addEvent('keydown', function (event) {
            if(event.keyCode == 13)
            {
                //	user pressed enter on the keyboard
                sendMsg();
            }
	    else
	    {
		clientIsTyping = 1;

		if(typingTimeoutTimer)
		{
		    typingTimeoutTimer = $clear(typingTimeoutTimer);
		}

		var typingTimeoutFunc = function() {
		    typingTimeout();
		};

		typingTimeoutTimer = typingTimeoutFunc.delay(1100);
	    }
        });
    }	

    if(window.ie)
    {
	// If internet explorer
	sessionDisplay.setStyle('width', '92.5%');
	statusDisplayLayer.setStyle('width', '92.5%');
    }

    $(nameSelector).setStyle('width', '91%');
    $(nameSelector).setStyle('border', '1px solid #725742');
    $(nameSelector).setStyle('margin-top', '3px');
    $(nameSelector).setStyle('padding', '5px 3px');
    $(nameSelector).setStyle('font-size', '14px');
    $(nameSelector).setStyle('font-family', 'arial');
	
    $(msgInputSelector).setStyle('width', '92%');
    $(msgInputSelector).setStyle('height', '40px');
    $(msgInputSelector).setStyle('font-family', 'arial');
    $(msgInputSelector).setStyle('font-size', '12px');
    $(msgInputSelector).setStyle('background-color', 'white');
    $(msgInputSelector).setStyle('color', '#313528');
    $(msgInputSelector).setStyle('display', 'block');
    $(msgInputSelector).setStyle('clear', 'both');
    $(msgInputSelector).setStyle('float', 'none');
    $(msgInputSelector).setStyle('margin-bottom', '5px');
    $(msgInputSelector).setStyle('border', '1px solid #725742');

    sessionDisplay.setStyle('border', '1px solid #725742');
}

function typingTimeout()
{
    clientIsTyping = 0;
}

function sendMsg()
{
    var sendTxt = $(msgInputSelector).getValue();
	
    var options = {
        method: 'post',
        onSuccess: function(response) {
            //	Clear Box
            clientIsTyping = 0;
	    
	    $(msgInputSelector).setProperty('value', '');
        }
    };

    var handlerUri = liveChatUri+'&task=send_message&t='+$time();

    var uriVars = 's='+URLEncode(chatSessionId)+'&m='+URLEncode(sendTxt)+'&n='+URLEncode(chatClientName);
	
    var myXhr = new XHR(options).send(handlerUri, uriVars);
	
    return false;
}

function endChatSession()
{
    if(chatSessionActive == 1)
    {
	var options = {
	    method: 'post',
	    onSuccess: function(response) {
		window.close();
	    }
	};

	var handlerUri = liveChatUri+'&task=end_session&t='+$time();

	var uriVars = 's='+URLEncode(chatSessionId)

	var myXhr = new XHR(options).send(handlerUri, uriVars);
    }
    
    return false;
}

function initChatSession()
{
    if(processingSomething == false)
    {
        processingSomething = true;
		
        var options = {
            method: 'post',
            onSuccess: function(response) {
                var data = Json.evaluate(response);
						
                if(data.success == 0)
                {
                    $each(data.errors, function (item, index) {
                        $(errorWrapperSelector).setText(item+"\n");
                    });

		    processingSomething = false;
                }
                else
                {
                    //	Waiting for Operator Response
                    chatClientName = $(nameSelector).getProperty('value');
                    continueBtn.removeEvents('click');
                    nameInput.removeEvents('keydown');
								
                    $(errorWrapperSelector).setText(connectingMsg);
								
                    chatSessionId = data.chat_session_id;
		    
                    startOfflineTimer();
								
                    checkIfChatAccepted();
                }
            },
            headers: {
                'X-Request': 'JSON'
            }
        };

	var handlerUri = liveChatUri+'&task=start_session&t='+$time();

	var uriVars = 'name='+URLEncode($(nameSelector).getProperty('value'));
	
        var myXhr = new XHR(options).send(handlerUri, uriVars);
    }
	
    return false;
}

function tryNextOperator()
{
    if(processingSomething == false)
    {
        processingSomething = true;
		
        var options = {
            method: 'post',
            onSuccess: function(response) {
                var data = Json.evaluate(response);
							
                processingSomething = false;
							
                //	Waiting for Operator Response
                chatClientName = $(nameSelector).getProperty('value');
                continueBtn.removeEvents('click');
                nameInput.removeEvents('keydown');
							
                $(errorWrapperSelector).setText('Connecting, please wait...');
							
                chatSessionId = data.chat_session_id;
							
                startOfflineTimer();
							
                checkIfChatAccepted();
            },
            headers: {
                'X-Request': 'JSON'
            }
        };

	var handlerUri = liveChatUri+'&task=try_next_operator&t='+$time();

	var uriVars = 'name='+URLEncode($(nameSelector).getProperty('value'));
	
        var myXhr = new XHR(options).send(handlerUri, uriVars);
    }
	
    return false;
}

function startOfflineTimer()
{
    var options = {
        method: 'get',
        onSuccess: function(response) {
            var data = Json.evaluate(response);
	    
            if(data)
            {
                var delayInMicroSeconds = parseInt(data.operator_timeout) * 1000;

		var newClientFunction = function () {
		    getNewClient();
		};

		newClientFunction.delay(delayInMicroSeconds);
            }
            else
            {
                // Key is not setup yet
                getNewClient();
            }
        },
        headers: {
            'X-Request': 'JSON'
        }
    };

    var uriVars = 'task=get_key_details&t='+$time();
	
    var myXhr = new XHR(options).send(liveChatUri, uriVars);
}

function getNewClient()
{
    if(chatSessionActive == 0 && chatIsOffline == false)
    {
        var options = {
            method: 'get',
            onSuccess: function(response) {
                var data = Json.evaluate(response);
					
                if(data != false)
                {
                    //	We got a new client successfully
                    processingSomething = false;
						
                    //	Retry request with new client
                    tryNextOperator();

		    var delayInMicroSeconds = parseInt(data.operator_timeout) * 1000;

		    var newClientFunction = function () {
			getNewClient();
		    };
		    
		    newClientFunction.delay(delayInMicroSeconds);
                }
                else
                {
		    var offlineFunction = function () {
			chatOffline();
		    };
		    
		    offlineFunction.delay(2000);
                }
            },
            headers: {
                'X-Request': 'JSON'
            }
        };
	
        var uriVars = 'task=get_new_client&t='+$time();
		
        var myXhr = new XHR(options).send(liveChatUri, uriVars);
    }
}

function checkIfChatAccepted()
{
    var options = {
        method: 'post',
        onSuccess: function(response) {
            var data = Json.evaluate(response);
						
            chatSessionActive = data.is_active;
	    
            if(chatSessionActive == 0 && data.mdate == 0)
            {
                //	Chat Still Pending
                var checkFunction = function () {
		    checkIfChatAccepted();
                };

                checkFunction.delay(3000);
            }
            else if(chatSessionActive == 0 && data.mdate > 0)
            {
                //	Chat Declined
                getNewClient();
            }
            else if(chatSessionActive == 1 && data.mdate > 0)
            {
                //	Chat Accepted
                chatAccepted();
            }
        },
        headers: {
            'X-Request': 'JSON'
        }
    };
    
    var handlerUri = liveChatUri+'&task=check_session_active&t='+$time();

    var uriVars = 'i='+URLEncode(chatSessionId);
	
    var myXhr = new XHR(options).send(handlerUri, uriVars);
}

function loadConfig(callbackFunc)
{
    var options = {
        method: 'get',
        onSuccess: function(response) {
            var data = Json.evaluate(response);
						
            $each(data.vars, function (item, index) {
                config[index] = item;
            });

	    if(callbackFunc) {
		callbackFunc();
	    }
        },
        headers: {
            'X-Request': 'JSON'
        }
    };
	
    var uriVars = 'task=get_config&t='+$time();
	
    var myXhr = new XHR(options).send(liveChatUri, uriVars);
}

function chatAccepted()
{
    $(preChatSelector).setStyle('display', 'none');
    $(inChatSelector).setStyle('display', 'block');
	
    refreshSession(false);

    var startRefreshFunction = function () {
	startRefreshTimer();
    };

    startRefreshFunction.delay(1000);
}

function chatOffline()
{
    if(chatSessionActive == 0)
    {
        chatIsOffline = true;
		
        $$(introWrapperSelector).setStyle('display', 'none');
        $(errorWrapperSelector).setStyle('display', 'none');
        $(nameContainerSelector).setStyle('display', 'none');
        $$(continueLayerSelector).setStyle('display', 'none');
		
        $(msgWrapper).setStyle('display', 'block');
        $$(closeWrapperSelector).setStyle('display', 'block');
		
        $(msgWrapper).setHTML(config['offline_msg']);
    }
}

function refreshSession(keepRefreshing)
{
    var options = {
        method: 'get',
        onSuccess: function(response) {
            var data = Json.evaluate(response);
	    
            if(chatSessionMdate != data.mdate)
            {
		if(parseInt(data.session_data.is_operator_typing) == 0)
		{
		    //	Operator is not typing
		    window.status='';
		    statusDisplayLayer.setText('');
		}
		else
		{
		    //	Operator is typing
		    window.status='Operator is currently typing...';
		    statusDisplayLayer.setText('Operator is currently typing...');
		}

                var sessionTxt = '';
                var lineColor = null;
                var a = 0;

		var reExcludePattern = new RegExp('(^[^:]+[\.]{3}$)');

                $each(data.session_lines, function (item, index) {
		    if(!reExcludePattern.test(item)) {
			sessionTxt += item+"\n";
		    }
		    
                    a += 1;
                });
		
                $(sessionDisplaySelector).setHTML(sessionTxt);
							
                chatSessionMdate = data.mdate;
							
                //	Keep scroll position at the bottom
                $(sessionDisplaySelector).scrollTop = $(sessionDisplaySelector).scrollHeight - $(sessionDisplaySelector).clientHeight;
            }

	    if(keepRefreshing)
            {
                startRefreshTimer();
            }
        },
        headers: {
            'X-Request': 'JSON',
	    'Connection': 'Keep-Alive'
        }
    };
    
    var handlerUri = liveChatUri+'&task=refresh_session&t='+$time();

    var uriVars = 's='+chatSessionId+'&client_is_typing='+clientIsTyping;
    
    var myXhr = new XHR(options).send(handlerUri, uriVars);
}

function startRefreshTimer()
{
    var refreshFunc = function () {
        refreshSession(true);
    }
	
    var refreshTime = refreshTimerDelay * 1000; // convert to miliseconds
	
    refreshTimer = refreshFunc.delay(refreshTime);
}

function URLEncode( str ) {       
    var histogram = {}, histogram_r = {}, code = 0, tmp_arr = [];
    var ret = str.toString();
    
    var replacer = function(search, replace, str) {
        var tmp_arr = [];
        tmp_arr = str.split(search);
        return tmp_arr.join(replace);
    };
    
    // The histogram is identical to the one in urldecode.
    histogram['!']   = '%21';
    histogram['%20'] = '+';
    
    // Begin with encodeURIComponent, which most resembles PHP's encoding functions
    ret = encodeURIComponent(ret);
    
    for (search in histogram) {
        replace = histogram[search];
        ret = replacer(search, replace, ret) // Custom replace. No regexing
    }
    
    // Uppercase for full PHP compatibility
    return ret.replace(/(\%([a-z0-9]{2}))/g, function(full, m1, m2) {
        return "%"+m2.toUpperCase();
    });
    
    return ret;
}

RegExp.escape = function(text) {
  if (!arguments.callee.sRE) {
    var specials = [
      '/', '.', '*', '+', '?', '|',
      '(', ')', '[', ']', '{', '}', '\\'
    ];
    arguments.callee.sRE = new RegExp(
      '(\\' + specials.join('|\\') + ')', 'g'
    );
  }
  return text.replace(arguments.callee.sRE, '\\$1');
}
