/// Copyright (c) 2009
/// Version 1.3.7 (BETA) :: Last updated at 02-09-2009
///
/// 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 = {

    UI: (function() {
        return {
            getElementHeight: function(elm) {
                var xPos = 0;
                if (elm.clip) xPos = elm.clip.height;
                //else if (elm.style.pixelHeight) xPos = elm.style.pixelHeight;
                else if (elm.offsetHeight) xPos = elm.offsetHeight;
                return xPos;
            }
        }
    })(),

    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 "";
            },
            
            getQuery:function(){
		return window.location.search.substring(1, window.location.search.length);
            }
        }
    })(),

    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("tp://", 0) > 0) && !(uri.indexOf("tps://", 0) > 0))
                    rUri = ("http://").concat(uri);

                return rUri;
            }
        }
    })()

    /*Stream : (function(){
    return {
    		
    fileUpload: function(fileName){
    // Mozilla Firefox
    if(navigator.userAgent.indexOf("Mozilla") >= 0) {
    try {
    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
    }
    catch(e) {
    throw new Error("O upload do ficheiro falhou, devido à falta de permissões de acesso.");
    }
    				
    var file = Components.classes["@mozilla.org/file/local;1"].createInstance(
    Components.interfaces.nsILocalFile);
    file.initWithPath(fileName);		
    stream = Components.classes["@mozilla.org/network/file-input-stream;1"].createInstance(
    Components.interfaces.nsIFileInputStream);
    stream.init(file, 0x01, 00004, null);
    				
    var bstream =  Components.classes["@mozilla.org/network/buffered-input-stream;1"]
    .getService();
    bstream.QueryInterface(Components.interfaces.nsIBufferedInputStream);
    bstream.init(stream, 1000);
    bstream.QueryInterface(Components.interfaces.nsIInputStream);
    binary = Components.classes["@mozilla.org/binaryinputstream;1"]
    .createInstance(Components.interfaces.nsIBinaryInputStream);
    binary.setInputStream (stream);
    				
    var scriptManager = Sonic.Ajax.AjaxManager.instance();
    				
    //...
    }
    else {
    //MS Internet Explorer
    if(navigator.userAgent.indexOf("MSIE") >= 0) {
    //Comming Soon
    }
    }
    }
    }
    })()*/
};
//##########################################



// 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 AjaxManager() {

        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";

                        if (userHandlers.onError)
                            userHandlers.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 = new AjaxManager();

            return _instance;
        },

        /// <summary>  
        /// **************
        /// * Deprecated *
        /// **************
        /// Returns a callback function already implemented.
        /// </summary>
        createXhrCallback: function() {
            var callback = {
                success: function() { },
                failure: function() { }
            };
            return callback
        }
    };

})();
