/// Copyright (c) 2008
/// Version 1.3.5 (BETA) :: Last updated at 17-11-2008
///
/// by João Pinho (jpe.pinho@gmail.com)
///
/// Permission is hereby granted, free of charge, to any person obtaining a copy of this library and associated 
/// documentation files (the "Library"), to deal in the Library without restriction, including without limitation 
/// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the libraries, and 
/// to permit persons to whom the library is furnished to do so, subject to the following conditions:
///
/// The above copyright notice and this permission notice shall be included in all copies or substantial portions 
/// of the libraries.
///
/// Sonic Framework

var Sonic = { };
//##########################################


// Utils Namespace
Sonic.Utils = { 
    
    QueryString:(function(){
        return {
            getQueryParams: function(pName)
            {
                var query = window.location.search.substring(1, window.location.search.length).toLowerCase();
                if (query.length > 0){
                    var parameters = new Array();
                    parameters = query.split("&");
                    for (i = 0; i < parameters.length; i++)
                    {
                        if (parameters[i].indexOf(pName.toLowerCase()) >= 0)
                            return parameters[i].split("=")[1];
                    }
                }

                return "";
            }        
        }
    })(),
    
    Validators : (function(){
        return {
            
            validEmail:function(email)
            {
                var emailRegex = "\\w+([-+.\']\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*";
                var match = email.match(emailRegex);
                return (match != null);
            },
            
            checkUriHttpString: function(uri) {
				var rUri = uri;

				if (!(uri.indexOf("http://", 0) > 0) || !(uri.indexOf("https://", 0) > 0))
					rUri = ("http://").concat(uri);

				return rUri;
			}
        }
    })()
};
//##########################################



// Ajax Namespace
Sonic.Ajax = { };
//##########################################

Sonic.Ajax.AjaxWebServiceManager = (function() { 

	return { 
		instance: function()
		{ 
		    return "Commig Soon"; 
		} 
	}; 
})();

Sonic.Ajax.AjaxManager = (function() {

    //# Private Section

    var _instance = null;
    var _xhrReusedObjectsCount = 0;

    function managerConstructor() {
    
        var _xhrStates = new Array();
        var _xhrObjects = new Array();
        var _reuseXhrObjects = false;
        
        // Constants
        _xhrStates[0] = "UNSENT";
        _xhrStates[1] = "OPENED";
        _xhrStates[2] = "HEADERS RECEIVED";
        _xhrStates[3] = "LOADING";
        _xhrStates[4] = "DONE";

        /// <summary>
        /// Ajax events object.
        /// </summary>
        function _ajaxEvents(){
            this.onReady = function(){};
            this.onStart = function(){};
            this.onStop = function(){};
            this.onComplete = function(){};
            this.onError = function(){};
        }; 

        function getXhrState(xhrObj) {
            if (xhrObj) { return _xhrStates[xhrObj.readyState]; }
            else { return "Undefined"; }
            
            return "EMPTY";
        }

        function isXhrAvailable(xhrObj) {
            return getXhrState(xhrObj) === "UNSENT" ? true : false;
        }

        function getAvailableXhr(availableXhrId) {
            for (var i = 0, j = _xhrObjects.length; i < j; i++) {
                if (isXhrAvailable(_xhrObjects[i])) {
                    availableXhrId = i;
                    return _xhrObjects[i];
                }
                else continue;
            }
            return null;
        }

        function getXhrObject(callbackHandler, ajaxEvents) {
            var xhrObject = null;
            var availableXhrId = null;
            var customReadyStateChange = function() { callbackHandler(ajaxEvents, xhrObject, _xhrObjects.length); };

            if (_reuseXhrObjects)
                if (_xhrObjects.length > 0) 
                    xhrObject = getAvailableXhr(availableXhrId);

            if (xhrObject == null) {
                var methods = [
                    function() { return new XMLHttpRequest(); },
                    function() { return new ActiveXObject("Msxml2.XMLHTTP"); },
                    function() { return new ActiveXObject("Microsoft.XMLHTTP"); }
                ];

                for (var i = 0, len = methods.length; i < len; i++) {
                    try { xhrObject = methods[i](); }
                    catch (e) { continue; }

                    if (navigator.userAgent.indexOf("MSIE") >= 0) { xhrObject.onreadystatechange = customReadyStateChange; }
                    else if (navigator.userAgent.indexOf("Mozilla") >= 0) {
                        xhrObject.onload = customReadyStateChange;
                        xhrObject.onerror = customReadyStateChange;
                    }
                    else { xhrObject.onreadystatechange = customReadyStateChange; }
                    
                    _xhrObjects.push(methods[i]());
                    return xhrObject;
                }
                throw new Error("Ajax Manager: Não foi possível criar o objecto XHR");
            }
            else {
                if (navigator.userAgent.indexOf("MSIE") >= 0) { xhrObject.onreadystatechange = customReadyStateChange; }
                else if (navigator.userAgent.indexOf("Mozilla") >= 0) {
                    xhrObject.onload = customReadyStateChange;
                    xhrObject.onerror = customReadyStateChange;
                }
                else { xhrObject.onreadystatechange = customReadyStateChange; }

                _xhrReusedObjectsCount++;
                return xhrObject;
            }
        };

        function clearRequestsPool() {
            for (var i = 0, j = _xhrObjects.length; i < j; i++) {
                if (_xhrObjects[i] != null)
                    if (_xhrObjects[i].readyState >= 4){
                        _xhrObjects[i] = null;
                        _xhrObjects.splice(i, 1);
                    }
            }
        };
        
        function clearRequestFromPool(xhrId)
        {
            try{
                _xhrObjects[xhrId] = null;
                _xhrObjects.splice(xhrId, 1);
            }
            catch(e){e = null;}
        }

        function processResponse(ajaxEvents, _xhrRef, xhrRefId) {
            try {
                switch(_xhrRef.readyState)
                {
                    case 1:{
                        ajaxEvents.onReady(); break;
                    }
                    case 2:{
                        ajaxEvents.onStart(); break;
                    }
                    case 3:{
                        ajaxEvents.onStop(); break;
                    }
                    case 4:{
                        document.body.style.cursor = "default";
                        if(_xhrRef.status === 200) { ajaxEvents.onComplete(_xhrRef.responseText, _xhrRef.responseXML); }
                        else {ajaxEvents.onError(_xhrRef.status, _xhrRef.statusText);}
                        
                        if (!_reuseXhrObjects) { clearRequestsPool(); }
                        else { clearRequestFromPool(xhrRefId); }
                        
                        break;
                    }
                }
            }
            catch (e) {
                _xhrRef.abort();
                document.body.style.cursor = "default";
                ajaxEvents.onError(e.number, e.message);
            }
        };
        
        var deprecated = {
            processResponse: function(_callback, _xhrRef, xhrRefId) {
                try {
                    if (_xhrRef.readyState == 4) {
                        if (_xhrRef.status === 200) {
                            document.body.style.cursor = "default";
                            _callback.success(_xhrRef.responseText, _xhrRef.responseXML);
                        }
                        else 
                        {
                            document.body.style.cursor = "default";
                            _callback.failure(_xhrRef.status, _xhrRef.statusText);
                        }
                        
                        if (!_reuseXhrObjects) { clearRequestsPool(); }
                        else { clearRequestFromPool(xhrRefId); }
                    }
                }
                catch (e) {
                    _xhrRef.abort();
                    document.body.style.cursor = "default";
                    _callback.failure(e.number, e.message);
                }
            }
        }

        return {

            //# Public Section

            handlers: new _ajaxEvents(),

            /// <summary>
            /// Performs an ajax request to a specified URI.
            /// </summary>
            /// <param name="uri"></param>
            /// <param name="callback">The callback method should implement the success and failure functions.</param>
            /// <param name="async">Performs the request asynchronously. (true | false)</param>
            /// <param name="user"></param>
            /// <param name="password"></param>
            /// <returns>The XML HTTP Request object associated with the request.</returns>
			execute: function(uri, userHandlers) 
			{
                var sendMethod = "GET";
                var async = true;
                var user = "";
                var password = "";
                var handlersParameter = userHandlers != null ? userHandlers : this.handlers;
                
                if(arguments.length > 2)
                {                    
				    switch(arguments.length) 
				    {
                        case 3:{
                            sendMethod = (arguments[2].toUpperCase() == "GET" || 
                                arguments[2].toUpperCase() == "POST") ? arguments[2].toUpperCase() : "GET";
                            break;
                        }
                        case 4:{
                            sendMethod = (arguments[2].toUpperCase() == "GET" ||
                                arguments[2].toUpperCase() == "POST") ? arguments[2].toUpperCase() : "GET";
                            async = arguments[3].toLowerCase() == "false" ? false : true;
                            break;
                        }
                        case 5:{
                            sendMethod = (arguments[2].toUpperCase() == "GET" ||
                                arguments[2].toUpperCase() == "POST") ? arguments[2].toUpperCase() : "GET";
                            async = arguments[3].toLowerCase() == "false" ? false : true;
                            user = arguments[5].toLowerCase();
                            password = arguments.length > 0 ? arguments[6] : "";
                            break;
                        }
                    }
                }

                var _postVars, _xhr = null;
                
                if(!handlersParameter.success)
                    _xhr = getXhrObject(processResponse, handlersParameter);
                else
                    _xhr = getXhrObject(deprecated.processResponse, handlersParameter); 

                if (_xhr != null) {
                    document.body.style.cursor = "wait";

                    try
                    {
                        if (arguments.length > 4)
                            _xhr.open(sendMethod, uri, async, user, password);
                        else
                            _xhr.open(sendMethod, uri, async);

                        if (sendMethod.toUpperCase() == "POST") {
                            uri = uri.split("?");
                            _postVars = uri[1];
                            _xhr.setRequestHeader("Method", "POST " + uri[0] + " /HTML 1.1");
                            _xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
                            _xhr.setRequestHeader("Charset", "UTF-8");
                        }
                        _xhr.send(_postVars);
                    }
                    catch(e){
						_xhr.abort();
						document.body.style.cursor = "default";
						this.handlers.onError(e.number, ("Exception '").concat(e.number).concat("': ").concat(e.message).concat("\nPlease, contact the administrator."));
                    }
                }
                else
                    throw new Error("Objecto XHR inexistente!");
            },          

            update: function(uri, control, property, userHandlers)
            {                              
                var _xhrEvents = userHandlers == null ? new _ajaxEvents() : userHandlers;
				var userOnComplete = _xhrEvents.onComplete;
				
				function updateOnComplete(rspTxt)
				{
					try{
                        eval(("document.getElementById('" + control + "')." + property + "=rspTxt;"));
						userOnComplete(rspTxt);
                    }
                    catch(e){
                        throw Error("Exception: ".concat(e.number).
                            concat("\nMessage: ").
                            concat(e.message));
                    }
				}
				
                _xhrEvents.onComplete =  updateOnComplete;
                
                var _xhr = this.execute(uri, _xhrEvents);
            },
            
            //BETA VERSION :: Not Working
            //            
            //periodicalUpdate: function(uri, control, property, interval, nTimes)
            //{
            //    var _xhrEvents = new _ajaxEvents();
            //    _xhrEvents.onComplete = function(rspTxt){
            //        eval("control."+property+"=rspTxt;");
            //    }
            //    
            //    var interval;
            //    var executeRef = this.execute;
            //    
            //    function _updater(delay, _nTimes)
            //    {
            //        if(_nTimes>0){
            //            executeRef(uri, _xhrEvents);
            //            _nTimes--;
            //            interval = setInterval("_updater("+delay+","+_nTimes+")", delay);
            //        }
            //    }
            //    _updater(interval,nTimes);
            //},

            /// <summary>
            /// Aborts all active requests.
            /// </summary>
            abortAllActiveRequests: function() {
                for (var i = 0, j = _xhrObjects.length; i < j; i++) {
                    if (_xhrObjects[i] != null)
                        if (_xhrObjects[i].readyState > 0 && _xhrObjects[i].readyState < 4)
                            _xhrObjects[i].abort();
                }
				document.body.style.cursor = "default";
            },

            /// <summary>
            /// Gets the state of the current XHR
            /// </summary>
            getXhrState: function() {
                return getXhrState(_xhr);
            },

            /// <summary>
            /// Gets the total number of XHR objects in memory.
            /// </summary>
            getXhrObjectsCount: function() {
                return _xhrObjects.length;
            },

            /// <summary>
            /// Gets the total number of reused XHR objects in memory.
            /// </summary>
            getXhrReusedObjectsCount: function() {
                return _xhrReusedObjectsCount;
            },
            
            /// <summary>
            /// Returns a callback function already implemented.
            /// </summary>
            createHandlers: function(){ return new _ajaxEvents(); },
            
            config: (function() {
                return {
                    /// <summary>
                    /// When set to true, reuses XHR objects instead of performing their disposal.
                    /// </summary>
                    reuseXhrObjects: function(areReusable) {
                        _reuseXhrObjects = areReusable;
                    }
                };
            }
            )()
        }
    };

    return {

        //# Public Section

        /// <summary>
        /// Gets the unique instance of the Ajax Manager Object
        /// </summary>
        instance: function() {
            if (!_instance)
                _instance = managerConstructor();

            return _instance;
        },
        
        /// <summary>  
        /// **************
        /// * Deprecated *
        /// **************
        /// Returns a callback function already implemented.
        /// </summary>
        createXhrCallback: function() {
            var callback = {
                success: function() { },
                failure: function() { }
            };
            return callback
        }
    };

})();
