/**
* Utilitats javascript. Per compatibilitat amb el codi existent no he volgut modificar
* les funcions existents i he creat un nou namespace utils.
* @classDescription Funcions de javascript d'utilitats de validació i tractaments de cadenes.
* @author msalla
* @id utils
* @namespace utils
*/
/**
* @classDescription Utilitats varies en javascript.
* @author msalla
*/
//var XMLHttpRequest;
/* extern seGlobal.js*/
var ManageConsole;

var utils = {

    ajax: {
        executeMethod: function(serviceName, methodName, methodArguments, onSuccess, onFail, sync) {
            $.ajax({
                async: !sync,
                type: "POST",
                url: "/pb/services/" + serviceName + "/" + methodName + "?pbl=" + utils.url.get_PageLang(),
                data: methodArguments,
                contentType: "application/json; charset=utf-8",
                dataType: "json",
                success: onSuccess,
                error: onFail || function() { alert('Error al realizar la llamada ajax: ' + serviceName+ '/' + methodName); }
            });
        }
    },

    url: {
        get_PageLang: function()
        {
            // Necesario cuando estamos ejecutando dentro del frame del análisis externo de SEO.
            try
            {
                if (!utils.dom.safeGetWindowTop().GlobalRefreshManager)
                {
                    return "es-es";
                }
            }
            catch (e) {
                return "es-es";
            }

            // En caso de BackOffice Manda el selector de idioma
            if (utils.dom.safeGetWindowTop().GlobalRefreshManager.IsBackOffice)
            {
                return utils.dom.safeGetWindowTop().GlobalRefreshManager.CurrentLanguage;
            }
            var re = new RegExp("[a-z]{2}\\-[a-z]{2}", "i");
            var lRet = re.exec(window.location.pathname);
            return lRet;
            //            var lPath = window.location.pathname.split('/');
            //            // es la posicion 1 porque en 0 viene vacio
            //            // el path es de la forma /es-es/caca, por lo que tras el split tenemos {"","es-es","caca"}
            //            if (lPath.length < 2) return '';
            //            if (lPath[1])
            //                return lPath.length >= 2 ? lPath[1] : '';
        },
        /**
        * Method for uri encoding.
        * @param {Object} string
        */
        encode: function(string)
        {
            return escape(this._utf8_encode(string));
        },
        /**
        * Method for uri decoding.
        * @param {Object} string
        */
        decode: function(string)
        {
            return this._utf8_decode(decodeURIComponent(string));
        },
        /**
        * private method for UTF-8 encoding
        * @param {Object} string
        */
        _utf8_encode: function(string)
        {
            string = string.replace(/\r\n/g, "\n");
            var utftext = "";

            for (var n = 0; n < string.length; n++)
            {
                var c = string.charCodeAt(n);

                if (c < 128)
                {
                    utftext += String.fromCharCode(c);
                }
                else if ((c > 127) && (c < 2048))
                {
                    utftext += String.fromCharCode((c >> 6) | 192);
                    utftext += String.fromCharCode((c & 63) | 128);
                }
                else
                {
                    utftext += String.fromCharCode((c >> 12) | 224);
                    utftext += String.fromCharCode(((c >> 6) & 63) | 128);
                    utftext += String.fromCharCode((c & 63) | 128);
                }
            }
            return utftext;
        },
        /**
        * private method for UTF-8 decoding
        * @param {Object} utftext
        */
        _utf8_decode: function(utftext)
        {
            var string = "";
            var i = 0;
            var c = 0;
            var c1 = 0;
            var c2 = 0;
            var c3 = 0;

            while (i < utftext.length)
            {

                c = utftext.charCodeAt(i);

                if (c < 128)
                {
                    string += String.fromCharCode(c);
                    i++;
                }
                else if ((c > 191) && (c < 224))
                {
                    c2 = utftext.charCodeAt(i + 1);
                    string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
                    i += 2;
                }
                else
                {
                    c2 = utftext.charCodeAt(i + 1);
                    c3 = utftext.charCodeAt(i + 2);
                    string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
                    i += 3;
                }
            }
            return string;
        },
        /**
        * Devuelve el QueryString de una URL en formato clave-valor
        * @param {Object} aURL
        */
        getQueryString: function(aURL)
        {
            // define an object to contain the parsed query data
            var result = {};
            var queryString;
            aURL = String(aURL);

            if (aURL.length === 0)
            {
                return;
            }

            // Check if there are any variables
            if (aURL.indexOf('?') != -1)
            {
                queryString = String(aURL.substring(aURL.indexOf('?') + 1, aURL.length));
            }
            else
            {
                // No variables
                return;
            }

            // replace plus signs in the query string with spaces
            //queryString = queryString.replace('+', ' ');

            // split the query string around ampersands and semicolons
            var queryComponents = queryString.split(/[&;]/g);

            // loop over the query string components
            for (var i = 0; i < queryComponents.length; i++)
            {

                // extract this component's key-value pair
                var keyValuePair = queryComponents[i].split('=');
                var key = decodeURIComponent(keyValuePair[0]);
                var value = decodeURIComponent(keyValuePair[1]);

                // update the parsed query data with this component's key-value pair
                if (!result[key])
                {
                    result[key] = [];
                }
                result[key].push((keyValuePair.length == 1) ? '' : value);

            }

            // return the parsed query data
            return result;
        },
        /**
        * Devuelve una URL con las nuevas clave-valor o, modificada si no existe, en el QueryString
        * @param {Object} aURL : Url inicial.
        * @param {Object} aParameters : array de objetos tipo {{key:'key1', value:'value1'},{key:'key2', value:'value2'}}
        */
        buildUrl: function(aURL, aParameters)
        {
            var lQueryData = utils.url.getQueryString(aURL);
            var lPath;
            var lQueryString = new String();
            var isNew = true;

            // comprobamos que la url tenga parámetros
            if (aURL.indexOf('?') != -1)
            {
                lPath = String(aURL.substring(0, aURL.indexOf('?')));
            }
            else
            {
                lPath = aURL;
            }
            for (var i = 0; i < aParameters.length; i++)
            {
                var lKey = aParameters[i].key;
                var lValue = aParameters[i].value;
                // recorremos el QueyString modificando el valor si procede
                for (var key in lQueryData)
                {
                    if (lQueryString.length === 0)
                    {
                        lQueryString += "?";
                    }
                    else
                    {
                        lQueryString += "&";
                    }
                    if (key.toString().toLowerCase() == lKey.toString().toLowerCase())
                    {
                        isNew = false;
                        lQueryData[key] = lValue;
                    }
                    lQueryString += key + "=" + lQueryData[key];
                }
                // sino hemos encontrado la clave requerida, incluimos el nuevo valor
                if (isNew)
                {
                    if (lQueryString.length === 0)
                    {
                        lQueryString += "?";
                    }
                    else
                    {
                        lQueryString += "&";
                    }
                    lQueryString += lKey + "=" + lValue;
                }
            }

            return (lPath + lQueryString);
        },
        /**
        * Devuelve una URL con una nueva clave-valor o, modificada si no existe, en el QueryString
        * @param {Object} aURL
        * @param {Object} aKey
        * @param {Object} aValue
        */
        getNewURL: function(aURL, aKey, aValue)
        {
            var lQueryData = utils.url.getQueryString(aURL);
            var lPath;
            var lQueryString = new String();
            var isNew = true;

            // comprobamos que la url tenga parámetros
            if (aURL.indexOf('?') != -1)
            {
                lPath = String(aURL.substring(0, aURL.indexOf('?')));
            }
            else
            {
                lPath = aURL;
            }
            // recorremos el QueyString modificando el valor si procede
            for (var key in lQueryData)
            {
                if (lQueryString.length === 0)
                {
                    lQueryString += "?";
                }
                else
                {
                    lQueryString += "&";
                }

                if (key.toString().toLowerCase() == aKey.toString().toLowerCase())
                {
                    isNew = false;
                    lQueryData[key] = aValue;
                }

                lQueryString += key + "=" + lQueryData[key];
            }

            // sino hemos encontrado la clave requerida, incluimos el nuevo valor
            if (isNew)
            {
                if (lQueryString.length === 0)
                {
                    lQueryString += "?";
                }
                else
                {
                    lQueryString += "&";
                }
                lQueryString += aKey + "=" + aValue;
            }

            return (lPath + lQueryString);
        }
    },
    /**       
    * Funcions de tractament d'event
    * @namespace utils.evt
    */
    evt: {
        StopEventPropagation: function(e)
        {
            e.cancelBubble = true;
            if (e.stopPropagation)
            {
                e.stopPropagation();
            }
            e.returnValue = false;
            if (e.preventDefault)
            {
                e.preventDefault();
            }
        },
        /**
        * Funció per afegir una funció a la seqüència d'onload.
        * @param {Object} AOnloadFunction :Method
        * @param {Object} APreOnload :boolean
        */
        AfegirOnload: function(aOnloadFunction
        /*:Method*/
        , aPreOnload
        /*:boolean*/
        )
        /* void */
        {
            var lWindow;
            if (window == window.top)
            {
                lWindow = window.top;
            }
            else
            {
                lWindow = window;
            }
            utils.evt.AfegirOnloadWithTarget.apply(lWindow, [lWindow, aOnloadFunction, aPreOnload]);
        },
        /**
        * Funció per afegir una funció a la seqüència d'onload.
        * @param {Object} AOnloadFunction :Method
        * @param {Object} APreOnload :boolean
        */
        AfegirTopOnload: function(aOnloadFunction
        /*:Method*/
        , aPreOnload
        /*:boolean*/
        )
        /* void */
        {
            var lWindow;
            try
            {
                if (window.top && window.top.location.href)
                {
                    lWindow = window.top;
                }
                else
                {
                    lWindow = window;
                }
            }
            catch (e) {
                lWindow = window;
            }
            utils.evt.AfegirOnloadWithTarget.apply(lWindow, [lWindow, aOnloadFunction, aPreOnload]);
        },
        /**
        * Protected version to get the window location for possible xss problems.
        * @param {window} aWindow
        */
        GetWindowLocation: function(aWindow
        /* window */
        )
        {
            try
            {
                return unescape(aWindow.location.href);
            }
            catch (e) {
                return utils.str.format('Unable to retrieve href: %0', e.message);
            }
        },
        addEvent: function(obj, evType, fn)
        {
            if (obj.addEventListener)
            {
                obj.addEventListener(evType, fn, false);
                return true;
            }
            else if (obj.attachEvent)
            {
                var r = obj.attachEvent("on" + evType, fn);
                return r;
            }
            else
            {
                return false;
            }
        },
        /**
        * Funció per afegir una funció a la seqüència d'onload.
        * @param {Object} aWindow - Target window
        * @param {Object} aOnloadFunction - Method
        * @param {Object} aPreOnload - boolean
        */
        AfegirOnloadWithTarget: function(aWindow
        /* window */
        , aOnloadFunction
        /*:Method*/
        , aPreOnload
        /*:boolean*/
        )
        /* void */
        {
            var lOldOnload
            /*: Method */
            = aWindow.seOnload || null;
            var lOnloadEventHandlersArray
            /*: Method[] */
            ;
            // Si ja te gestió de handlers és que ja está registrada la funció correcta
            if (lOldOnload && typeof lOldOnload == 'function' && lOldOnload.Handlers)
            {
                var lPosition;
                lOnloadEventHandlersArray = lOldOnload.Handlers;
                if (!aPreOnload)
                {
                    var lFoundHole = false;
                    for (var j = lOnloadEventHandlersArray.length - 1; j >= 0; j--)
                    {
                        if (!lOnloadEventHandlersArray[j] || typeof lOnloadEventHandlersArray[j] != 'function')
                        {
                            lOnloadEventHandlersArray[j] = aOnloadFunction;
                            lFoundHole = true;
                            lPosition = j;
                            break;
                        }
                    }
                    if (!lFoundHole)
                    {
                        lOnloadEventHandlersArray[lOnloadEventHandlersArray.length] = aOnloadFunction;
                        lPosition = lOnloadEventHandlersArray.length - 1;
                    }

                }
                else
                {
                    for (var i = lOnloadEventHandlersArray.length; i > 0; i--)
                    {
                        lOnloadEventHandlersArray[i] = lOnloadEventHandlersArray[i - 1];
                    }
                    lOnloadEventHandlersArray[0] = aOnloadFunction;
                    lPosition = 0;
                }
                window.console.info('Added OnloadHandler ' + utils.evt.GetWindowLocation(aWindow) + ' at position: ' + lPosition);
                window.console.info(aOnloadFunction.toString());
            }
            else
            {
                ManageConsole();
                // Si no té gestió de handlers cal crear la funció de gestió
                lOnloadEventHandlersArray = [aOnloadFunction];
                window.console.info('Building OnloadHandler:' + utils.evt.GetWindowLocation(aWindow));
                window.console.info('Added OnloadHandler ' + utils.evt.GetWindowLocation(aWindow) + ' at position: ' + (lOnloadEventHandlersArray.length - 1).toString());
                window.console.info(aOnloadFunction.toString());

                var lOnloadEventHandlerManager = function()
                {
                    var lCurrentFunction; //: Object
                    var lResult; //: Object
                    ManageConsole();

                    for (var i = 0; i < lOnloadEventHandlersArray.length; i++)
                    {
                        lCurrentFunction = lOnloadEventHandlersArray[i];

                        if (lCurrentFunction)
                        {
                            window.console.info('Start OnloadHandler at position: ' + i);
                            try
                            {
                                lResult = lCurrentFunction.apply({},
                                arguments);
                            }
                            catch (e) {
                                if (e.number == -2146823277) {
                                    lOnloadEventHandlersArray[i] = undefined;
                                    window.console.warn('Forced free onload handler at position: ' + i + ' error: ' + e.message);
                                    window.console.info('Unregistered onload event handler at position: ' + i);
                                    window.console.info(lCurrentFunction.toString());
                                }
                                else
                                {
                                    //debugger;
                                    window.console.error('Error on onload handler at position: ' + i + ' error: :' + e.message);
                                }
                            }
                            window.console.info('End OnloadHandler at position: ' + i);
                            window.console.info(lCurrentFunction.toString());
                        }
                    }

                    if (typeof lResult != 'function')
                    {
                        return lResult;
                    }
                };
                lOnloadEventHandlerManager.Handlers = lOnloadEventHandlersArray;
                try
                {
                    if (aWindow == window.top)
                    {
                        //window.top.onload = lOnloadEventHandlerManager;
                        utils.evt.addEvent(window.top, 'load', lOnloadEventHandlerManager);
                        aWindow.seOnload = lOnloadEventHandlerManager;
                    }
                    else
                    {
                        if (aWindow == window)
                        {
                            //window.onload = lOnloadEventHandlerManager;
                            utils.evt.addEvent(window, 'load', lOnloadEventHandlerManager);
                            window.seOnload = lOnloadEventHandlerManager;
                        }
                        else
                        {
                            //aWindow.onload = lOnloadEventHandlerManager;
                            utils.evt.addEvent(aWindow, 'load', lOnloadEventHandlerManager);
                            aWindow.seOnload = lOnloadEventHandlerManager;
                        }
                    }
                }
                catch (ex) {
                    if (aWindow == window) {
                        //window.onload = lOnloadEventHandlerManager;
                        utils.evt.addEvent(window, 'load', lOnloadEventHandlerManager);
                        window.seOnload = lOnloadEventHandlerManager;
                    }
                    else
                    {
                        //aWindow.onload = lOnloadEventHandlerManager;
                        utils.evt.addEvent(aWindow, 'load', lOnloadEventHandlerManager);
                        aWindow.seOnload = lOnloadEventHandlerManager;
                    }
                }
                // Si existía una función de onload la añadimos al final de la lista de handlers
                if (lOldOnload && typeof lOldOnload == 'function')
                {
                    lOnloadEventHandlersArray[lOnloadEventHandlersArray.length] = lOldOnload;
                    window.console.info('Added OnloadHandler ' + utils.evt.GetWindowLocation(aWindow) + ' at position: ' + lOnloadEventHandlersArray.length - 1);
                    window.console.info(lOldOnload.toString());
                }
            }
        },

        /**
        * Gets the global event handler.
        * We should allways try to use the top window acting as the coordinator.
        */
        GetGlobalEventHandler: function()
        {
            //debugger;
            var lGlobalHandler;
            try
            {
                //We should allways try to use the top window acting as the coordinator.
                if (window.top.document && (window.top != window))
                {
                    lGlobalHandler = window.top.seGlobal;
                }
                else
                {
                    lGlobalHandler = window.seGlobal;
                }
            }
            catch (e) {
                // Probably an access denied error because of XDS
                lGlobalHandler = window.seGlobal;
            }
            return lGlobalHandler;
        },
        /**
        * Registra una subscripció a l'execució d'un event global. Si l'event no existia
        * es registra l'event en el moment de la cárrega de window.top i si ja s'ha carregat
        * el window.top es registra de forma normal al window.top.
        * @param {String} aGlobalEventName - Event name.
        * @param {Method} aGlobalEventFunctionHandler - Callback function.
        * @param {Boolean} aIsPreEvent - Add at the beginning or the end of the lists of event handlers.
        */
        AddGlobalEventHandler: function(aGlobalEventName
        /*: String*/
        , aGlobalEventFunctionHandler
        /*:Method*/
        , aIsPreEvent
        /*:boolean*/
        )
        /* void */
        {
            var lWindowTop = utils.dom.safeGetWindowTop();
            if (!utils.evt.ExistsGlobalEventHandler(aGlobalEventName)) {
                var state = lWindowTop.document ? lWindowTop.document.readyState : null;
                if (state == "complete") {
                    utils.evt.RegisterGlobalEvent(aGlobalEventName, aGlobalEventFunctionHandler, aIsPreEvent);
                }
                else
                {
                    utils.evt.AfegirTopOnload(function()
                    {
                        utils.evt.RegisterGlobalEvent(aGlobalEventName, aGlobalEventFunctionHandler, aIsPreEvent);
                    },
                    false);
                }
            }
            else
            {
                utils.evt.RegisterGlobalEvent.apply(lWindowTop, [aGlobalEventName, aGlobalEventFunctionHandler, aIsPreEvent]);
            }
        },
        RegisterGlobalEvent: function(aGlobalEventName
        /*: String*/
        , aGlobalEventFunctionHandler
        /*:Method*/
        , aIsPreEvent
        /*:boolean*/
        )
        /* void */
        {
            var lWindowTop = utils.dom.safeGetWindowTop();
            utils.evt._RegisterGlobalEvent.apply(lWindowTop, arguments);
        },
        /**
        * Registra una subscripció a l'execució d'un event global.
        * @param {String} aGlobalEventName : Event name.
        * @param {Method} aGlobalEventFunctionHandler : Callback function.
        * @param {Boolean} aIsPreEvent : Add at the beginning or the end of the lists of event handlers.
        */
        _RegisterGlobalEvent: function(aGlobalEventName
        /*: String*/
        , aGlobalEventFunctionHandler
        /*:Method*/
        , aIsPreEvent
        /*:boolean*/
        )
        /* void */
        {
            var lGlobalHandler = utils.evt.GetGlobalEventHandler();
            var lGlobalEventFunction
            /*: Method */
            = lGlobalHandler[aGlobalEventName];
            var lGlobalEventFunctionArray
            /*: Method[] */
            ;
            var lPosition;
            /*: integer*/
            //debugger;
            if ((lGlobalEventFunction !== null) && (lGlobalEventFunction !== undefined) && (typeof lGlobalEventFunction == 'function'))
            {
                lGlobalEventFunctionArray = lGlobalHandler[aGlobalEventName].Handlers;
                if (aGlobalEventFunctionHandler)
                {
                    if (!aIsPreEvent)
                    {
                        var lFoundHole = false;
                        for (var i = lGlobalEventFunctionArray.length - 1; i >= 0; i--)
                        {
                            if (!lGlobalEventFunctionArray[i] || typeof lGlobalEventFunctionArray[i] != 'function')
                            {
                                lGlobalEventFunctionArray[i] = aGlobalEventFunctionHandler;
                                lFoundHole = true;
                                lPosition = i;
                                break;
                            }
                        }
                        if (!lFoundHole)
                        {
                            lGlobalEventFunctionArray[lGlobalEventFunctionArray.length] = aGlobalEventFunctionHandler;
                            lPosition = lGlobalEventFunctionArray.length - 1;
                        }
                    }
                    else
                    {
                        for (var j = lGlobalEventFunctionArray.length; j > 0; j--)
                        {
                            lGlobalEventFunctionArray[j] = lGlobalEventFunctionArray[j - 1];
                        }
                        lGlobalEventFunctionArray[0] = aGlobalEventFunctionHandler;
                        lPosition = 0;
                    }
                }
            }
            else
            {
                lPosition = 0;
                lGlobalEventFunctionArray = [aGlobalEventFunctionHandler];
                window.console.info('Building GlobalEventFunctionHandler: ' + aGlobalEventName + '.');
                lGlobalHandler[aGlobalEventName] = function()
                {
                    var lCurrentFunction; //: Object
                    var lResult; //: Object
                    for (var i = 0; i < lGlobalEventFunctionArray.length; i++)
                    {
                        lCurrentFunction = lGlobalEventFunctionArray[i];
                        if (lCurrentFunction)
                        {
                            window.console.info('Start GlobalEventFunctionHandler ' + aGlobalEventName + ' at position: ' + i + '.');
                            window.console.info(lCurrentFunction.toString());
                            try
                            {
                                lResult = lCurrentFunction.apply({},
                                arguments);
                            }
                            catch (e) {
                                //debugger;
                                if (e.number == -2146823277)
                                {
                                    //debugger;
                                    lGlobalEventFunctionArray[i] = undefined;
                                    window.console.warn('Forced free GlobalEventFunctionHandler ' + aGlobalEventName + ' at position: ' + i + ', ErrorMessage: ' + e.message);
                                    window.console.info('Unregistered GlobalEventFunctionHandler ' + aGlobalEventName + ' at position: ' + i + '.');
                                    window.console.info(lCurrentFunction.toString());
                                }
                                else
                                {
                                    window.console.error('Error GlobalEventFunctionHandler ' + aGlobalEventName + ' at position: ' + i + ', ErrorMessage: ' + e.message);
                                }
                            }
                            window.console.info('End GlobalEventFunctionHandler ' + aGlobalEventName + 'at position: ' + i + '.');
                        }
                    }
                    if (typeof lResult != 'function')
                    {
                        return lResult;
                    }
                };
                lGlobalHandler[aGlobalEventName].Handlers = lGlobalEventFunctionArray;
            }
            if (aGlobalEventFunctionHandler)
            {
                window.console.info('Registering global event ' + aGlobalEventName + 'at position: ' + lPosition + '.');
                window.console.info(aGlobalEventFunctionHandler.toString());
            }
        },
        /**
        * Returns if any global event handler has been built for a given global event.
        * @param {String} aGlobalEventName:
        */
        ExistsGlobalEventHandler: function(aGlobalEventName
        /*: String*/
        )
        {
            var lGlobalHandler = utils.evt.GetGlobalEventHandler();
            var lGlobalEventFunction
            /*: Method */
            = lGlobalHandler[aGlobalEventName];

            //debugger;
            if ((lGlobalEventFunction !== null) && (lGlobalEventFunction !== undefined) && (typeof lGlobalEventFunction == 'function'))
            {
                return true;
            }
            else
            {
                return false;
            }
        },
        /**
        * Registra una subscripció a l'execució d'un event global.
        * @param {String} AGlobalEventName: String
        * @param {Method} AGlobalEventFunction:Method
        */
        UnRegisterGlobalEvent: function(aGlobalEventName
        /*: String*/
        , aGlobalEventFunction
        /*:Method*/
        )
        /* void */
        {
            var lGlobalHandler = utils.evt.GetGlobalEventHandler();
            var lOldGlobalEventFunction
            /*: Method */
            = lGlobalHandler[aGlobalEventName];
            var lGlobalEventFunctionArray
            /*: Method[] */
            ;

            // debugger;
            if ((lOldGlobalEventFunction !== null) && (lOldGlobalEventFunction !== undefined) && (typeof lOldGlobalEventFunction == 'function'))
            {
                lGlobalEventFunctionArray = lGlobalHandler[aGlobalEventName].Handlers;
                for (var i = 0; i < lGlobalEventFunctionArray.length; i++)
                {
                    if (lGlobalEventFunctionArray[i] === aGlobalEventFunction)
                    {
                        lGlobalEventFunctionArray[i] = undefined;
                        window.console.info('UnRegistered global event ' + aGlobalEventName + ' at position: ' + i + '.');
                        window.console.info(aGlobalEventFunction.toString());
                        break;
                    }
                }
            }
        },
        /**
        * Llença l'execució d'un event global.
        * @param {String} AGlobalEventName Nom de l'event global.
        * @param {arguments} AGlobalEventArgs Llista d'arguments.
        */
        ExecuteGlobalEvent: function(aGlobalEventName
        /*: String*/
        /*Array of args*/
        )
        /* : Object */
        {
            //debugger;
            var lGlobalHandler = utils.evt.GetGlobalEventHandler();
            var lGlobalEventArgs = [];
            var i = 1;

            while (i < arguments.length)
            {
                lGlobalEventArgs[i - 1] = arguments[i];
                i++;
            }

            var lResult
            /*: Object*/
            ;
            var lGlobalEventFunction = lGlobalHandler[aGlobalEventName];
            if ((lGlobalEventFunction !== null) && (lGlobalEventFunction !== undefined) && (typeof lGlobalEventFunction == 'function'))
            {
                window.console.info('Begin global event ' + aGlobalEventName + '(' + lGlobalEventArgs.toString() + ')');
                try
                {
                    lResult = lGlobalEventFunction.apply({},
                    lGlobalEventArgs);
                }
                catch (e) {
                    window.console.error('Error executing GlobalEventFunctionHandler ' + aGlobalEventName + '(' + lGlobalEventArgs.toString() + '); ErrorMessage:(' + e.message + ')');
                    window.console.error(lGlobalEventFunction.toString());
                }
                window.console.info('End global event ' + aGlobalEventName + '(' + lGlobalEventArgs.toString() + ')');
            }
            if (typeof lResult != 'function')
            {
                return lResult;
            }
        },
        /**
        * Generates a random NOT Globally Unique guid. Returns the guid as a string.
        */
        generateGuid: function()
        {
            var result, i, j;
            result = '';
            for (j = 0; j < 32; j++)
            {
                if (j == 8 || j == 12 || j == 16 || j == 20)
                {
                    result = result + '-';
                }
                i = Math.floor(Math.random() * 16).toString(16).toUpperCase();
                result = result + i;
            }
            return result;
        },
        /**
        * Creates a hidden temporary iframe with a given source to provide XSS functionality,
        * waits for it's load event and then it's destroyed.
        * @param {uri} aIFrameSrc
        */
        CreateCrossFrame: function(
        /*string */
        aIFrameSrc)
        {
            var lNewIFrame = document.createElement('iframe');
            var lNewIFrameId = 'ITemFrame' + utils.evt.generateGuid();

            // If we don't use a timeout the iframe page is destroyed before processing its own onload.
            //lNewIFrame.onafterupdate = RemoveFrame(lNewIFrame);
            var lNewIFrameOnLoad = function()
            {
                try
                {
                    window.console.info('Borrando el frame: ' + lNewIFrame.id);
                    document.body.removeChild(lNewIFrame);
                }
                catch (ex) {
                    window.console.error('Error al borrar el frame: ' + lNewIFrameId);
                }
            };
            lNewIFrame.onload = setTimeout(lNewIFrameOnLoad, 10000);
            lNewIFrame.setAttribute('id', lNewIFrameId);
            lNewIFrame.style.display = 'none';
            lNewIFrame.setAttribute('src', aIFrameSrc);
            window.console.info('Executing Xss call: ' + unescape(aIFrameSrc));
            document.body.appendChild(lNewIFrame);
        },
        /**
        * Executes a Xss global event.
        * @param {String} aGlobalEventName
        * @param {Object[]} Array of args
        */
        ExecuteXssGlobalEvent: function(aGlobalEventName
        /*: String*/
        /*Array of args*/
        )
        /* : Object */
        {
            var lSourceHostName = utils.evt.GetGlobalEventHandler().sourcehostname;

            if (lSourceHostName)
            {
                var lSb = new utils.str.StringBuilder();
                lSb.Append('http://');
                lSb.Append(lSourceHostName);
                // This is the Xss proxy url
                lSb.Append('/pb/forms/Common/XssProxy.htm');
                lSb.Append('?sourcehostname=');
                lSb.Append(window.location.hostname);
                lSb.Append('&globalfunction=');
                lSb.Append(aGlobalEventName);

                // We add the parameters if any
                if (arguments.length > 1)
                {
                    lSb.Append('&params=');
                    var lSbParams = new utils.str.StringBuilder();
                    // We add the first parameter
                    lSbParams.Append(escape(arguments[1]));
                    var i = 2;
                    // We add the other parameters if any
                    while (i < arguments.length)
                    {
                        lSbParams.Append(' ');
                        lSbParams.Append(escape(arguments[i]));
                        i++;
                    }
                    lSb.Append(escape(lSbParams.ConvertToString()));
                }
                var lRequestUri = lSb.ConvertToString();
                utils.evt.CreateCrossFrame(lRequestUri);
                // We also try to execute the local event if exists
                utils.evt.ExecuteGlobalEvent.apply({},
                arguments);
            }
            else
            {
                // We execute the local event if exists
                utils.evt.ExecuteGlobalEvent.apply({},
                arguments);
            }
        },
        /**
        * Curry delegate function.
        * @param {Object} aInstance - Object context method.
        * @param {Function} aFunction - Function to be called.
        * @return - The function delegate.
        * @type {Function}
        */
        createDelegate: function(aInstance, aFunction)
        {
            return function()
            {
                return aFunction.apply(aInstance, arguments);
            };
        }
    },
    ff: {
        /**
        * @type {String} ffjs info field. Modified by IE compat and utils.ff.dom
        */
        info: "ffjs-1.11",
        /**
        * @type {int} current wait level.
        */
        _wcnt: 0,
        /**
        * Creates a cross-brower XMLHttpRequest object
        * @return {XMLHttpRequest} xmlhttprequest object or null on fail
        */
        _createXHR: function()
        {
            var xhr = null;

            if (typeof XMLHttpRequest != 'undefined')
            {
                xhr = new XMLHttpRequest();
            }

            return xhr;
        },
        /**
        * Sets or clears the wait cursor for the document body.
        * It uses the utils.ff._wcnt counter to control recursive calls
        * before releasing the cursor to auto.
        * @param {boolean} wait
        */
        wait: function(
        /*{boolean}*/
        wait)
        {
            if (wait)
            {
                utils.ff._wcnt++;
                document.body.style.cursor = "wait";
            }
            else {
                if (utils.ff._wcnt-- <= 1) {
                    utils.ff._wcnt = 0;
                    document.body.style.cursor = "auto";
                }
            }
        },
        /**
        * Makes an AJAX request.
        * @param {Object} config Associative array configuring the request
        * config.attributes:
        *   url - URL to request,
        *   response - function to call with the response,
        *   error - function to call in case of error,
        *   method - "GET" or "POST",
        *   params - HTTP Parameters del request si es detecta un ? a la url s'afegeixen parelles clau-valor
        *            de l'array sinó s'afegeix primer ? i després parelles clau valor de l'array,
        *   body - raw body to post,
        *   waitCursor - set wait cursor
        * @param {boolean} sync Boolan switch for synchronous callbacks ansynchronous by default.
        */
        request: function(config, sync)
        {
            var Response = function(xhr)
            {
                this.xhr = xhr;
                this.text = function()
                {
                    return this.xhr.responseText;
                };

                this.xml = function()
                {
                    return this.xhr.responseXML;
                };

                this.json = function()
                {
                    var __json;
                    eval("__json=" + this.xhr.responseText);
                    return __json;
                };

                this.html = function()
                {
                    var div = document.createElement("div");
                    div.innerHTML = this.xhr.responseText;
                    return div.childNodes;
                };

                this.unlink = function()
                {
                    this.xhr = null;
                };

                xhr = null;
            };

            var lconsole = window.console;

            if ((!config.response) && (lconsole !== null) && (lconsole !== undefined))
            {
                lconsole.error("No response function.");
            }

            if ((!config.url) && (lconsole !== null) && (lconsole !== undefined))
            {
                lconsole.error("No URL to request.");
            }

            var url = config.url;
            var method = config.method || "GET";
            var params = config.params;

            var body = config.body;

            if (!body && params)
            {
                var key;

                if (method == "GET") {
                    var divider = url.indexOf("?") < 0 ? "?" : "&";

                    for (key in params)
                    {
                        url = url + divider + key + "=" + escape(params[key]);
                        divider = "&";
                    }
                }
                else if (method == "POST")
                {
                    body = "";

                    for (key in params)
                    {
                        if (body.length > 0)
                        {
                            body += "&";
                        }

                        body += key + "=" + escape(params[key]);
                    }
                }
                else
                {
                    if ((lconsole !== null) && (lconsole !== undefined))
                    {
                        lconsole.error("Unsupported HTTP Method " + method);
                    }

                    return;
                }
            }

            var xhr = utils.ff._createXHR();

            if (!xhr)
            {
                if ((lconsole !== null) && (lconsole !== undefined))
                {
                    lconsole.error("no xmlhttp");
                }

                return null;
            }

            if (config.waitCursor)
            {
                utils.ff.wait(true);
            }
            var lAsynchCallback = true;

            if ((sync !== null) && (sync !== undefined) && (sync === true))
            {
                lAsynchCallback = false;
            }
            xhr.open(method, url, lAsynchCallback);
            xhr.onreadystatechange = function()
            {
                try
                {
                    if (xhr.readyState == 4)
                    {
                        var response = new Response(xhr);
                        var status = xhr.status;

                        if (status == 200)
                        {
                            if (config.waitCursor)
                            {
                                utils.ff.wait(false);
                            }

                            var resp = config.response;
                            resp(response, config.data);
                        }
                        else
                        {
                            throw "HTTP error " + status;
                        }

                        response.unlink();
                    }
                }
                catch (e) {
                    if (config.waitCursor) {
                        utils.ff.wait(false);
                    }

                    if (config.error)
                    {
                        config.error(response, e, config.data);
                    }
                    else
                    {
                        if ((lconsole !== null) && (lconsole !== undefined))
                        {
                            lconsole.error(e);
                        }
                    }

                    if (response)
                    {
                        response.unlink();
                    }
                }
            };

            if (method == "POST")
            {
                xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
            }

            xhr.send(body);
        },
        /**
        * Returns the current state of the given form element as associative array.
        * @param {DOMElement} formElement DOM form element
        * @return {Object} associative array containing the form state
        */
        readParameter: function(formElement)
        {
            if (formElement && formElement.nodeName == "FORM")
            {
                var params = [];
                var elements = formElement.elements;

                for (var i = 0; i < elements.length; i++)
                {
                    var e = elements[i];

                    if (e.name && e.name.length > 0)
                    {
                        params[e.name] = e.value;
                    }
                }

                return params;
            }
            else
            {
                throw "no form";
            }
        },
        /**
        * Calls the given function for every dom element of the given type having the given
        * classname. If the top element is given, only dom elements below that are checked.
        * @param {String} name tag type to search
        * @param {String} className class name to search
        * @param {Function} fn function to call
        * @param {DOMElement} [top] Top DOM element
        */
        forElement: function(name, className, fn, top)
        {
            var elements;
            elements = (top || document).getElementsByTagName(name);
            if (elements)
            {
                var re = utils.ff.style._re(className);
                for (var i = 0; i < elements.length; i++)
                {
                    var e = elements[i];

                    if (re.test(utils.ff.style.getClass(e)))
                    {
                        try
                        {
                            fn(e);
                        }
                        catch (ex) {
                            window.console.error('Error processing forElement (exception: ' + ex + ')(elem: ' + e + '), (function: ' + fn.toString() + ')');
                        }
                    }
                }
            }
        },
        /**
        * Returns true if the browser supports XMLHttpRequest, and basic DOM operations.
        * @return {boolean} supports?
        */
        hasCapabilities: function()
        {
            var xhr = utils.ff._createXHR();
            return (xhr !== null && document.createElement && document.getElementById);
        },
        /**
        * Contains the DOM related functions of the ff javascript library
        */
        dom: {
            /**
            * Removes all children from the given DOMElement
            * @param {DOMElement} elem DOM element
            */
            clear: function(elem)
            {
                while (elem.hasChildNodes())
                {
                    elem.removeChild(elem.firstChild);
                }
            },
            /**
            * Appends the given children to the children of the given DOM element
            * @param {DOMElement} e DOM element
            * @param {DOMElement,Array} c child/children to append
            */
            append: function(e, c)
            {
                if (c.length)
                {
                    while (c.length)
                    {
                        e.appendChild(c[0]);
                    }
                }
                else
                {
                    e.appendChild(c);
                }
            },
            /**
            * Replaces the current children of the DOM element with the given child(ren)
            * @param {DOMElement} elem DOM element
            * @param {DOMElement,Array} The new child/children
            */
            replace: function(elem, newChildren)
            {
                utils.ff.dom.clear(elem);
                utils.ff.dom.append(elem, newChildren);
            },
            /**
            * Creates a DOM creation function for every tag type
            * @param {Object} domBase base object which the DOM creation functions are properties of.
            */
            init: function(domBase)
            {
                domBase = domBase || utils.ff.dom;
                var createDOMFn = function(name)
                {
                    return function()
                    {
                        return utils.ff.dom.element(name, arguments);
                    };
                };

                var elems = "A ABBR ACRONYM ADDRESS APPLET AREA B BASE BASEFONT BDO BIG BLOCKQUOTE BODY BR BUTTON CAPTION CENTER CITE CODE COL COLGROUP DD DEL DFN DIR DIV DL DT EM FIELDSET FONT FORM FRAME FRAMESET H1 H2 H3 H4 H5 H6 HEAD HR HTML I IFRAME IMG INPUT INS ISINDEX KBD LABEL LEGEND LI LINK MAP MENU META NOFRAMES NOSCRIPT OBJECT OL OPTGROUP OPTION P PARAM PRE Q S SAMP SCRIPT SELECT SMALL SPAN STRIKE STRONG STYLE SUB SUP TABLE TBODY TD TEXTAREA TFOOT TH THEAD TITLE TR TT U UL VAR".split(" ");

                for (var i = 0; i < elems.length; i++)
                {
                    var elem = elems[i];
                    domBase[elem] = createDOMFn(elem);
                }

                window.console.info("init DOM");
            },
            /**
            * Generic DOM creation function. This function always exists, even when utils.ff.dom.init is not called
            * @param {String} name Tag name of the DOM element
            * @param {Array} child Array containing the children of the new DOM element. Can be either DOM elements or strings or numbers
            * @see utils.ff.dom#init
            */
            element: function(name, child)
            {
                child = child || [];
                var i = 0;
                var attr = {};

                if (child.length > 0 && !child[0].appendChild && typeof child[0] == "object")
                {
                    attr = child[0];
                    i++;
                }
                return this._el2(name, i, child, attr);
            },
            /**
            * Creates a new tag element.
            * @param {DomElementTag} Dom element tag name.
            * @param {ChildStartIndex} Child node index to stat adding childs from.
            * @param {ChildNodes[]} Child nodes array.
            * @param {Attributes[]} Attributes array.
            */
            _el2: function(
            /*DomElementTag*/
            name,
            /*ChildStartIndex*/
            i,
            /*childnodes[]*/
            child,
            /*attributes[]*/
            attr)
            {
                var elem = document.createElement(name);

                for (var m in attr)
                {
                    if (typeof m != "function")
                    {
                        this.setAttribute(elem, m, attr[m]);
                    }
                }

                while (i < child.length)
                {
                    var c = child[i++];

                    if (c.appendChild)
                    {
                        elem.appendChild(c);
                    }
                    else
                    {
                        elem.appendChild(document.createTextNode(new String(c).valueOf()));
                    }
                }

                return elem;
            },
            /**
            * Sets the given attribute on the given DOM element to the given value.
            * @param {DOMElement} e DOM element
            * @param {String} a attribute name
            * @param {String} v value
            */
            setAttribute: function(e, a, v)
            {
                e.setAttribute(a, v);
            },
            /**
            * Returns the value of the given attribute of the given DOM element
            * @param {DOMElement} e DOM element
            * @param {String} a attribute name
            */
            getAttribute: function(e, a)
            {
                return e.getAttribute(a);
            }
        },
        /**
        * Style class related functions of the ff javascript library.
        */
        style: {
            /**
            * Sets all class names for the given DOM element.
            * @param {DOMElement} elem DOM element
            * @param {String} class names separated by spaces
            */
            setClass: function(elem, c)
            {
                utils.ff.dom.setAttribute(elem, "class", c);
            },
            /**
            * Returns all class names of the given DOM element
            * @param {DOMElement} elem DOM element
            * @return {String} class names separated by spaces
            */
            getClass: function(elem)
            {
                return utils.ff.dom.getAttribute(elem, "class");
            },
            /**
            * Adds a class name to the class names of the given DOM element.
            * @param {DOMElement} elem DOM element
            * @param {String} c class name to add
            */
            addClass: function(elem, c)
            {
                var klass = utils.ff.style.getClass(elem);

                if (klass)
                {
                    klass += " " + c;
                }
                else
                {
                    klass = c;
                }

                utils.ff.style.setClass(elem, klass);
            },
            /**
            * Removes all occurences of teh given class name from the class names of the given DOM element
            * @param {DOMElement} elem DOM element
            * @param {String} c class name to remove
            */
            removeClass: function(elem, c)
            {
                var klass = utils.ff.style.getClass(elem);

                if (klass)
                {
                    var newClass = "";
                    var classes = klass.split(" ");

                    for (var i = 0; i < classes.length; i++)
                    {
                        var curClass = classes[i];

                        if (curClass != c)
                        {
                            if (newClass.length > 0)
                            {
                                newClass += " ";
                            }

                            newClass += curClass;
                        }
                    }

                    utils.ff.style.setClass(elem, newClass);
                }
            },
            /**
            * Builds a regular expression ending with word boundaries to search for a given text.
            * @param {string} c - Expression to search.
            */
            _re: function(c)
            {
                return new RegExp("\\b" + c + "\\b");
            },
            /**
            * Checks if a given element contains a class.
            * @param {Element} el
            * @param {ClassName} c
            */
            hasClass: function(el, c)
            {
                return this._re(c).test(this.getClass(el));
            },
            /**
            * Toggles adding or removing a css class from a given element.
            * @param {Element} el
            * @param {ClassName} c
            */
            toggleClass: function(el, c)
            {
                if (this.hasClass(el, c))
                {
                    this.removeClass(el, c);
                }
                else
                {
                    this.addClass(el, c);
                }
            }
        },
        /**
        * Contains all event related functions of the ff javascript library.
        * Based on John Resig's winning entry to the addEvent recoding contest ( http://ejohn.org/projects/flexible-javascript-events/ )
        */
        event: {
            /**
            * Adds an event handler to the given DOM element
            * @param {DOMElement} obj DOM element
            * @param {String} type Event type to handle ("click" , "focus" etc)
            * @param {Function} fn Event Handler function.
            */
            add: function(obj, type, fn)
            {
                obj.addEventListener(type, fn, false);
            },
            /**
            * Removes an event handler from the given DOM element
            * @param {DOMElement} obj DOM element
            * @param {String} type Event type to handle ("click" , "focus" etc)
            * @param {Function} fn Event Handler function.
            */
            remove: function(obj, type, fn)
            {
                obj.removeEventListener(type, fn, false);
            },
            /**
            * Adds a function to call when the page is loaded. Supports multiple functions.
            * @param {DOMElement} obj DOM element
            * @param {String} type Event type to handle ("click" , "focus" etc)
            * @param {Function} fn Event Handler function.
            */
            onload: function(func)
            {
                var oldonload = window.onload;

                if (typeof window.onload != "function")
                {
                    window.onload = func;
                }
                else
                {
                    window.onload = function()
                    {
                        oldonload();
                        func();
                    };
                }
            },
            /**
            * Prevents the giving event from bubbling up
            * @param {Event} e
            */
            noBubble: function(e)
            {
                e.stopPropagation();
            },
            /**
            * Prevents the default handling of the given event
            * @param {Event} e
            */
            preventDefault: function(e)
            {
                e.preventDefault();
            }
        }
    },
    /**
    * Funcions de processament d'elements dins el DOM.
    * @namespace utils.dom
    */
    dom: {
        safeGetWindowTop: function()
        {
            try
            {
                //We should allways try to use the top window acting as the coordinator.
                if ((window.top != window) && window.top.document.readyState)
                {
                    return window.top;
                }
                else
                {
                    return window;
                }
            }
            catch (e) {
                // Probably an access denied error because of XDS
                return window;
            }
        },
        findRecursive: function(aId, aDocumentSource)
        {
            var lDoc;
            if (!aDocumentSource)
            {
                lDoc = window.top;
            }
            else
            {
                lDoc = aDocumentSource;
            }
            var lCurrentDoc;
            var lSearchedElement = null;
            if (lDoc.frames.length > 0)
            {
                for (var i = 0;
                (i < lDoc.frames.length && !lSearchedElement); i++)
                {
                    //debugger;
                    lCurrentDoc = lDoc.frames[i].frameElement.contentWindow.document;
                    lSearchedElement = lCurrentDoc.getElementById(aId);
                    if (!lSearchedElement)
                    {
                        lSearchedElement = utils.dom.findRecursive(aId, lCurrentDoc);
                    }
                }
            }
            return lSearchedElement;
        },
        /**
        * The infamous $ function.
        * @param {Object} AId
        */
        $: function(AId)
        /*Object*/
        {
            return document.getElementById(AId);
        },
        /**
        * Create dynamically an stylesheet.
        * @param {Object} {Uri} aHref
        */
        createDocumentStyleSheet: function(
        /*{id}*/
        aId,
        /*{Uri}*/
        aHref)
        {
            if (document.createStyleSheet)
            {
                // Añadimos al final
                var css = document.createStyleSheet(aHref ? aHref : '', document.styleSheets.length);
                //css.id = aId;
                return css;
            }
            else
            {
                var newSS = document.createElement('link');
                newSS.id = aId;
                newSS.rel = 'stylesheet';
                newSS.type = 'text/css';

                if (aHref !== undefined)
                {
                    newSS.href = escape(aHref);
                }
                // Añadimos al final
                document.getElementsByTagName("head")[0].appendChild(newSS);
                return document.styleSheets[document.styleSheets.length - 1];
            }
        },
        /**
        * Adds a css rule array to a given css.
        * @param {css}aCss
        * @param {string[]} aNewRuleArray
        */
        AddCssRules: function(
        /*{css}*/
        aCss,
        /*{string[]}*/
        aNewRuleArray)
        {
            var lNewRule;
            var lNewRuleKey;
            var lNewRuleValues;

            if (aCss)
            {
                if (aCss.insertRule)
                {
                    // Moz Only
                    for (var i = 0; i < aNewRuleArray.length; i++)
                    {
                        var lSb = new utils.str.StringBuilder();
                        lNewRule = aNewRuleArray[i];
                        lNewRuleKey = lNewRule.Key;
                        lSb.Append(lNewRuleKey);
                        lNewRuleValues = lNewRule.Values;
                        lSb.Append(' {');
                        lSb.Append(lNewRuleValues);
                        lSb.Append(' }');
                        var lNewRuleText = lSb.ConvertToString();
                        aCss.insertRule(lNewRuleText, 0);
                    }
                }
                else
                {
                    // IE only
                    if (aCss.addRule)
                    {
                        for (var j = 0; j < aNewRuleArray.length; j++)
                        {
                            lNewRule = aNewRuleArray[j];
                            lNewRuleKey = lNewRule.Key;
                            lNewRuleValues = lNewRule.Values;
                            aCss.addRule(lNewRuleKey, lNewRuleValues);
                        }
                    }
                }
            }
        },
        /**
        * Scroll element vertically. To scroll up use a negative number
        * @param {DOMObject} el : Document element.
        * @param {integer} num : Pixels can be negative.
        */
        scrollElmVert: function(el, num)
        {
            // to scroll up use a negative number
            var re = /html$/i;
            while (!re.test(el.tagName) && (1 > el.scrollTop))
            {
                el = el.parentNode;
            }
            if (0 < el.scrollTop)
            {
                el.scrollTop += num;
            }
        },
        /**
        * Scroll element horizontally. 
        * To scroll to the left use a negative number.
        * @param {DOMObject} el : Document element.
        * @param {integer} num : Pixels can be negative.
        */
        scrollElmHorz: function(el, num)
        {
            // to scroll to the left use a negative number
            var re = /html$/i;
            while (!re.test(el.tagName) && (1 > el.scrollLeft))
            {
                el = el.parentNode;
            }
            if (0 < el.scrollLeft)
            {
                el.scrollLeft += num;
            }
        },
        /**
        * Returns an object absolute position 
        * param {object[]} aDomObject.
        */
        getPosition: function(aDomObject
        /*:object*/
        )
        /* [] Position object array */
        {
            var curleft = 0;
            var curtop = 0;

            if (aDomObject.offsetParent)
            {
                var lDomObject = aDomObject;
                do
                {
                    curleft += lDomObject.offsetLeft;
                    curtop += lDomObject.offsetTop;
                    lDomObject = lDomObject.offsetParent;
                } while (lDomObject);

                return [curleft, curtop];
            }
            else
            {
                curleft += aDomObject.offsetLeft;
                curtop += aDomObject.offsetTop;
            }
            return [curleft, curtop];
        },
        /**
        * Sets an image Url attribute.
        * @param {string} AHTMLImgId.
        * @param {string} ANewImageURL.
        */
        setImageURL: function(AHTMLImgId
        /*: string*/
        , ANewImageURL
        /*: String*/
        )
        /* boolean*/
        {
            var lHTMLImg
            /*:HTMLImg*/
            = document.getElementById(AHTMLImgId);

            if (lHTMLImg)
            {
                lHTMLImg.src = ANewImageURL;
                return true;
            }
            else
            {
                return false;
            }
        },
        /**
        * Estableix el valor emmagatzemat en un hiddenfield basant-se en l'id del hiddenfield.
        * @param {Object} AHiddenFieldId: string
        * @return {boolean} Si s'ha trobat i canviat el valor del hiddendfield o no.
        */
        setHiddenFieldValueById: function(AHiddenFieldId
        /*: string*/
        , AValue
        /*: object*/
        )
        /*boolean*/
        {
            var lHf
            /*:HTMLHiddenField*/
            = document.getElementById(AHiddenFieldId);

            if (lHf)
            {
                lHf.value = AValue;
                return true;
            }
            else
            {
                return false;
            }
        },
        /**
        * Retorna el valor emmagatzemat en un hiddenfield basant-se en l'id del hiddenfield.
        * @param {Object} AHiddenFieldId: string
        */
        getHiddenFieldValueById: function(AHiddenFieldId
        /*: string*/
        )
        /*Object*/
        {
            var lHf
            /*:HTMLHiddenField*/
            = document.getElementById(AHiddenFieldId);

            if (lHf)
            {
                return (lHf.value);
            }
            else
            {
                return undefined;
            }
        },
        disableControl: function(AControl
        /*: string*/
        )
        /*Object*/
        {
            var lHf
            /*:HTMLHiddenField*/
            = utils.dom.$(AControl);

            if (lHf)
            {
                lHf.disabled = true;
            }
        },
        enableControl: function(AControl
        /*: string*/
        )
        /*Object*/
        {
            var lHf
            /*:HTMLHiddenField*/
            = utils.dom.$(AControl);

            if (lHf)
            {
                lHf.disabled = false;
            }
        },
        /**
        * Fa que la  selecció d'un check d'una llista sigui exclusiva.
        * @param {Object} AObjId: checkbox
        * @param {Object} ACheckArray: checkbox[]
        */
        checkExclusiu: function(AObjId
        /*string*/
        , ACheckArray
        /*checkbox[]*/
        )
        {
            for (var i
            /*:integer*/
            = 0; i < ACheckArray.length; i++)
            {
                if ((ACheckArray[i].id !== AObjId) && (ACheckArray[i].checked))
                {
                    ACheckArray[i].checked = false;
                }
            }
        },
        setText: function(name, text)
        {
            var lyr = utils.dom.$(name);

            if ((lyr !== undefined) && (lyr !== null))
            {
                lyr.innerText = text;
            }
        },
        getText: function(name)
        {
            var lyr = utils.dom.$(name);

            if ((lyr !== undefined) && (lyr !== null))
            {
                return lyr.innerText;
            }
            else
            {
                return '';
            }
        },
        setHTML: function(name, text)
        {
            var lyr = utils.dom.$(name);

            if ((lyr !== undefined) && (lyr !== null))
            {
                lyr.innerHTML = text;
            }
        },
        getHTML: function(name)
        {
            var lyr = utils.dom.$(name);

            if ((lyr !== undefined) && (lyr !== null))
            {
                return lyr.innerHTML;
            }
            else
            {
                return '';
            }
        },
        setValue: function(ACtrlId, AText)
        {
            var lCtrl = utils.dom.$(ACtrlId);

            if ((lCtrl !== undefined) && (lCtrl !== null))
            {
                lCtrl.value = AText;
            }
        },
        getValue: function(name, text)
        {
            var lyr = utils.dom.$(name);

            if ((lyr !== undefined) && (lyr !== null))
            {
                return lyr.value;
            }
        },
        displayLyr: function(name, isDisplay)
        {
            var lyr = utils.dom.$(name);

            if ((lyr !== undefined) && (lyr !== null))
            {
                if (isDisplay)
                {
                    lyr.style.display = 'block';
                }
                else
                {
                    lyr.style.display = 'none';
                }
            }
        },
        showLyr: function(name, isDisplay)
        {
            var lyr = utils.dom.$(name);

            if ((lyr !== undefined) && (lyr !== null))
            {
                if (isDisplay)
                {
                    lyr.style.visibility = 'visible';
                }
                else
                {
                    lyr.style.visibility = 'hidden';
                }
            }
        },
        isShownLyr: function(name)
        {
            var lyr = utils.dom.$(name);

            if ((lyr !== undefined) && (lyr !== null))
            {
                return (lyr.style.visibility != 'hidden' && lyr.style.visibility !== '');
            }
        },
        isDisplayedLyr: function(name)
        {
            var lyr = utils.dom.$(name);

            if ((lyr !== undefined) && (lyr !== null))
            {
                return (lyr.style.display != 'none' && lyr.style.display !== '');
            }
            else
            {
                return false;
            }
        },
        isEmptyLyr: function(name)
        {
            var lyr = utils.dom.$(name);

            if ((lyr !== undefined) && (lyr !== null))
            {
                return (lyr.innerText === '');
            }
            else
            {
                return true;
            }
        },
        positionLyr: function(name, left, top)
        {
            var lyr = utils.dom.$(name);

            if ((lyr !== undefined) && (lyr !== null))
            {
                lyr.style.left = left + 'px';
                lyr.style.top = top + 'px';
            }
        },
        resizeLyr: function(name, width, height)
        {
            var lyr = utils.dom.$(name);

            if ((lyr !== undefined) && (lyr !== null))
            {
                lyr.width = width;
                lyr.height = height;
            }
        },
        getFrameHeight: function(name)
        {
            if ((window.parent.frames[name] !== undefined) && (window.parent.frames[name] !== null))
            {
                return window.parent.frames[name].document.body.scrollHeight;
            }
            return 0;
        },
        getFrameWidth: function(name)
        {
            if ((window.parent.frames[name] !== undefined) && (window.parent.frames[name] !== null))
            {
                return window.parent.frames[name].document.body.scrollWidth;
            }
        },
        selectListBoxItems: function(lbxobj, spacedValues)
        {
            var arrayValues;
            var 
            /*integer*/
            i, j;
            arrayValues = spacedValues.split(" ");

            for (i = 0; i < arrayValues.length; i++)
            {
                for (j = 0; j < lbxobj.length; j++)
                {
                    if (lbxobj.options[j].value == arrayValues[i])
                    {
                        lbxobj.options[j].selected = true;
                    }
                }
            }
        },
        getElementHeight: function(elem)
        {
            if (elem !== null)
            {
                return elem.offsetHeight;
            }

            return 0;
        },
        getElementWidth: function(elem)
        {
            if (elem !== null)
            {
                return elem.offsetWidth;
            }

            return 0;
        },
        setElementZIndex: function(elem, value)
        {
            if (elem !== null)
            {
                elem.style.zIndex = value;
            }
        },
        redimTable: function(tableName)
        {
            var table = utils.dom.$(tableName);

            if ((table !== null) || (table !== undefined))
            {
                var altura = utils.dom.getDocumentHeight();
                table.height = altura;
            }
        },
        getDocumentHeight: function()
        {
            return document.body.scrollHeight;
        },
        findPosY: function(obj)
        {
            var curtop = 0;

            if (obj.offsetParent)
            {
                while (obj.offsetParent)
                {
                    curtop += obj.offsetTop;
                    obj = obj.offsetParent;
                }
            }
            else if (obj.y)
            {
                curtop += obj.y;
            }
            else if (obj.clientY)
            {
                curtop += obj.clientY;
            }
            return curtop;
        },
        findPosX: function(obj)
        {
            var curleft = 0;
            if (obj.offsetParent)
            {
                while (obj.offsetParent)
                {
                    curleft += obj.offsetLeft;
                    obj = obj.offsetParent;
                }
            }
            else if (obj.x)
            {
                curleft += obj.x;
            }
            else if (obj.clientX)
            {
                curleft += obj.clientX;
            }
            return curleft + 10;
        },
        totalOffsetTop: function(what)
        {
            var totaloffset = what.offsetTop;
            var parentEl = what.offsetParent;
            while (parentEl !== null)
            {
                totaloffset += parentEl.offsetTop;
                parentEl = parentEl.offsetParent;
            }
            return totaloffset;
        }
    },
    /**
    * Funcions de tractament de cadenes
    * @namespace utils.str
    */
    str: {
        StringBuilder: function()
        {
            this.buffer = [];
            this.Append = function(str)
            {
                this.buffer[this.buffer.length] = str;
            };

            this.ConvertToString = function()
            {
                return this.buffer.join('');
            };
        },

        trim: function(inputString)
        {
            if (typeof inputString != "string")
            {
                return inputString;
            }

            var retValue = inputString;
            var ch = retValue.substring(0, 1);

            while (ch == " ")
            {
                retValue = retValue.substring(1, retValue.length);
                ch = retValue.substring(0, 1);
            }

            ch = retValue.substring(retValue.length - 1, retValue.length);

            while (ch == " ")
            {
                retValue = retValue.substring(0, retValue.length - 1);
                ch = retValue.substring(retValue.length - 1, retValue.length);
            }
            while (retValue.indexOf("  ") != -1)
            {
                retValue = retValue.substring(0, retValue.indexOf("  ")) + retValue.substring(retValue.indexOf("  ") + 1, retValue.length);
            }

            return retValue;
        },
        /**
        * Formateja la cadena rebuda com a primer paràmetre amb la resta de paràmetres.
        * @param {String[]} arguments Arguments de la funció.
        * alias utils.str.format
        * alias format
        */
        format: function(
        /*arguments : String[]*/
        )
        {
            var lMsg
            /*: String*/
            = arguments[0];
            var lPos
            /*: int*/
            = 1;

            while (lPos < arguments.length)
            {
                lMsg = lMsg.replace(/\%[0-9\.a-zA-Z]/, arguments[lPos++]);
            }
            return String(lMsg);
        },
        formatClassic: function(str, arg
        /*array : String[]*/
        )
        {
            var lMsg
            /*: String*/
            = str;
            var lPos
            /*: int*/
            = 0;

            while (lPos < arg.length)
            {
                lMsg = lMsg.replace(/\%[0-9\.a-zA-Z]/, arg[lPos++]);
            }
            return String(lMsg);
        },
        /**
        * Formateja la cadena rebuda com a primer paràmetre amb la resta de paràmetres.
        * @param {Object} evt :Event
        * @return {boolean} Si el caracter es numeric o no.
        * alias utils.str.parseNumeric
        * alias parseNumeric
        */
        parseNumeric: function(evt
        /*:Event*/
        )
        /*boolean*/
        {
            evt = (evt) ? evt : event;
            var charCode = (evt.charCode) ? evt.charCode : ((evt.keyCode) ? evt.keyCode : ((evt.which) ? evt.which : 0));

            if (charCode > 31 && (charCode < 48 || charCode > 57))
            {
                return false;
            }
            return true;
        }
    },
    /**
    * 
    * @param {Object} offset
    */
    cookies: {
        getCookieVal: function(offset)
        {
            var endstr = document.cookie.indexOf(";", offset);
            if (endstr == -1)
            {
                endstr = document.cookie.length;
            }
            return unescape(document.cookie.substring(offset, endstr));
        },
        fixCookieDate: function(date)
        {
            var base = new Date(0);
            var skew = base.getTime(); // dawn of (Unix) time - should be 0
            if (skew > 0) // Except on the Mac - ahead of its time
            {
                date.setTime(date.getTime() - skew);
            }
        },
        getCookie: function(name)
        {
            var arg = name + "=";
            var alen = arg.length;
            var clen = document.cookie.length;
            var i = 0;
            while (i < clen)
            {
                var j = i + alen;
                if (document.cookie.substring(i, j) == arg)
                {
                    return utils.cookies.getCookieVal(j);
                }
                i = document.cookie.indexOf(" ", i) + 1;
                if (i === 0)
                {
                    break;
                }
            }
            return null;
        },
        setCookie: function(name, value, expires, path, domain, secure) {
            window.top.document.cookie = name + "=" + escape(value) + ((expires) ? "; expires=" + expires.toGMTString() : "") + ((path) ? "; path=" + path : "") + ((domain) ? "; domain=" + domain : "") + ((secure) ? "; secure" : "");
        },
        deleteCookie: function(name, path, domain) {
            if (utils.cookies.getCookie(name)) {
                document.cookie = name + "=" + ((path) ? "; path=" + path : "") + ((domain) ? "; domain=" + domain : "") + "; expires=Thu, 01-Jan-70 00:00:01 GMT";
            }
        }
    }
};

// IE compat code
/*@cc_on@*/
/*@if (@_jscript_version >= 5)
utils.ff.__cxhr = utils.ff._createXHR;
utils.ff.progIds = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'];
utils.ff._createXHR = function() {
    var xhr = utils.ff.__cxhr();
    for (var i = 0; !xhr && i < utils.ff.progIds.length; i++) {
        try {
            xhr = new ActiveXObject(utils.ff.progIds[i]);
            utils.ff.progIds = [utils.ff.progIds[i]];
        }
        catch (e) {
            var lconsole = window.console;

            if ((lconsole !== null) && (lconsole !== undefined)) {
                lconsole.error(e);
            }
        }
    }

    return xhr;
};
utils.ff.event.add = function(obj, type, fn) {
    obj['e' + type + fn] = fn;
    obj[type + fn] = function() {
        obj['e' + type + fn](window.event);
    };
    obj.attachEvent('on' + type, obj[type + fn]);
};
utils.ff.event.remove = function(obj, type, fn) {
    obj.detachEvent("on" + type, obj[type + fn]);
    obj[type + fn] = null;
    obj["e" + type + fn] = null;
};
utils.ff.event.noBubble = function(e) {
    window.event.cancelBubble = true;
};
utils.ff.event.preventDefault = function(e) {
    window.event.returnValue = false;

    return false;
};
utils.ff.dom._ar = {
    "class": "className",
    "checked": "defaultChecked",
    "usemap": "useMap",
    "for": "htmlFor"
};
utils.ff.dom.setAttribute = function(e, a, v) {
    var a2 = this._ar[a];

    if (a2) {
        e.setAttribute(a2, v);
    }
    else

        if (a == "style") {
        e.style.cssText = v;
    }
    else

        if (a.substring(0, 2) == "on") {
        e[a] = new Function(v);
    }
    else {
        e.setAttribute(a, v);
    }
};

utils.ff.dom.getAttribute = function(e, a) {
    var a2 = this._ar[a];

    if (a2) {

        return e.getAttribute(a2);
    }
    else {

        return e.getAttribute(a);
    }
};

utils.ff.dom.__el2 = utils.ff.dom._el2;
utils.ff.dom._el2 = function(n, i, c, a) {

    if (i < c.length && n == "TEXTAREA") {
        a.value = c[i];
        // only text is valid inside a textarea
        c = [];
    }
    var n2 = "<" + n;

    if (a.name) {
        n2 += " name=\"" + a.name + "\"";
    }

    if (n == "INPUT" && a.type) {
        n2 += " type=\"" + a.type + "\"";
    }
    n2 += ">";

    return this.__el2(n2, i, c, a);
};
utils.ff.info += " ( IE compat )";
@end@*/
ManageConsole = function()
{
    function CheckConsole()
    {
        var lseGlobal = utils.evt.GetGlobalEventHandler();

        if ((!lseGlobal) || (!lseGlobal.console))
        {
            if (window.console)
            {
                lseGlobal.console = window.console;
            }
            else
            {
                lseGlobal.console = {};
                window.console = lseGlobal.console;
            }
            var nopFn = function(aName)
            {

                return function()
                {
                    if (!lseGlobal.nopFnArray)
                    {
                        lseGlobal.nopFnArray = [];
                    }
                    if (arguments && arguments.length > 0)
                    {
                        var lArgs;
                        lArgs = [];
                        for (var i = 0; i < arguments.length; i++)
                        {
                            lArgs[i] = arguments[i];
                        }
                        lseGlobal.nopFnArray[lseGlobal.nopFnArray.length] = {
                            name: aName,
                            args: lArgs
                        };
                    }
                    else
                    {
                        lseGlobal.nopFnArray[lseGlobal.nopFnArray.length] = {
                            name: aName
                        };
                    }
                };
            };
            var createFns = function(a, p)
            {
                var lIdName;
                for (var i = 0; i < a.length; i++)
                {
                    lIdName = p + a[i];
                    if (window.console[lIdName] && typeof window.console[lIdName] == 'function')
                    {
                        var lOlfFn = window.console[lIdName];
                        window.console[lIdName] = function()
                        {
                            nopFn(lIdName).apply({},
                            arguments);
                            lOlfFn.apply({},
                            arguments);
                        };
                    }
                    else
                    {
                        window.console[lIdName] = nopFn(lIdName);
                    }
                }
            };
            //debugger;  bge ege code rgeh ugeh bgeh egeh roleh uoleh boleh eoleh 
            createFns("debug info warn error trace time timeEnd count".split(" "), "");
            var a = "x Equals NotEquals Greater NotGreater Less NotLess Contains NotContains True False Null NotNull Undefined NotUndefined InstanceOf NotInstanceOf TypeOf NotTypeOf".split(" ");
            a[0] = "";
            createFns(a, "assert");
        }
        if (lseGlobal.console && ((!window.console) || (window.console != lseGlobal.console)))
        {
            window.console = lseGlobal.console;
        }
    }
    function CheckDebug()
    {
        var query = window.location.search;
        var debug = query && query.indexOf("ffdebug") >= 0;
        var lseGlobal = utils.evt.GetGlobalEventHandler();

        // emulate firebug console if firebug is not installed
        if (debug && !lseGlobal.ConsoleLoadPrepared)
        {
            var lConsoleOnload = function()
            {
                var container = utils.ff.dom.element("DIV", [{
                    "id": "ffdebug"
}]);
                    window.console._container = container;
                    document.body.appendChild(window.console._container);
                    utils.ff.event.add(container, "dblclick",
                function(ev) {
                    utils.ff.style.toggleClass(this, "minimized");
                    utils.ff.event.preventDefault(ev);
                });
                    window.console._log = function(name, args) {
                        var msg
                        /*:string*/
                    = args[0];
                        var pos = 1;
                        while (pos < args.length) {
                            msg = msg.replace(/\%[0-9\.a-zA-Z]/, args[pos++]);
                        }
                        window.console._container.appendChild(utils.ff.dom.element("DIV", [{
                            "class": name
                        },
                    msg]));
                    };
                    var logFn = function(name) {
                        window.console[name] = function() {

                            return window.console._log(name, arguments);
                        };
                    };
                    logFn("debug");
                    logFn("info");
                    logFn("warn");
                    logFn("error");
                    logFn("trace");
                    //                     // Begin global event exec
                    //                     logFn("bge");
                    //                     // End global event exec
                    //                     logFn("ege");
                    //                     // Code
                    //                     logFn("code");
                    //                     // Register global event handler exec
                    //                     logFn("rgeh");
                    //                     // Unregister global event handler exec
                    //                     logFn("ugeh");
                    //                     // Begin global event handler exec
                    //                     logFn("bgeh");
                    //                     // End global event handler exec
                    //                     logFn("egeh");
                    //                     // Register onload event handler exec
                    //                     logFn("roleh");
                    //                     // Unregister onload event handler exec
                    //                     logFn("uoleh");
                    //                     // Begin onload event handler exec
                    //                     logFn("boleh");
                    //                     // End onload event handler exec
                    //                     logFn("eoleh");
                    var lseGlobal = utils.evt.GetGlobalEventHandler();
                    window.console.info(utils.ff.info);

                    if (lseGlobal && lseGlobal.nopFnArray) {
                        var lTraceMessage;
                        for (var i = 0; i < lseGlobal.nopFnArray.length; i++) {
                            lTraceMessage = lseGlobal.nopFnArray[i];

                            if (lTraceMessage.args && lTraceMessage.args.length > 0) {
                                window.console._log(lTraceMessage.name, lTraceMessage.args);
                            }
                            else {
                                window.console._log(lTraceMessage.name);
                            }
                        }
                    }
                    lseGlobal.nopFnArray = [];
                };

                lseGlobal.ConsoleLoadPrepared = true;
                utils.evt.AfegirOnload(lConsoleOnload, true);
                /*var ffdebugcss = */
                utils.dom.createDocumentStyleSheet('ffdebugcss', '/pb/css/Common/ffdebug.css');
            }
        }
        /**
        * Secure the MS Ajax toolkit to enable XSS whithout problems.
        */
        function CheckSecureSys() {
            try {
                if (typeof Sys !== 'undefined') {
                    if ((undefined !== Sys) && (undefined !== Sys.UI) && (undefined !== Sys.UI.DomElement) && (undefined !== Sys.UI.DomElement.getLocation) && ('function' == typeof Sys.UI.DomElement.getLocation)) {
                        var lOldGetLocation = Sys.UI.DomElement.getLocation;
                        if (!lOldGetLocation.Secured) {
                            Sys.UI.DomElement.getLocation = function() {
                                try {
                                    lOldGetLocation.apply({},
                                arguments);
                                }
                                catch (e) {
                                    window.console.error('Error on calling secure Sys.UI.DomElement.getLocation(). Error: ' + e.message);
                                }
                            };
                            Sys.UI.DomElement.getLocation.Secured = true;
                        }
                        if (Sys$UI$DomElement$getLocation && (typeof Sys$UI$DomElement$getLocation == 'function')) {
                            var lOldGetLocationAux = Sys$UI$DomElement$getLocation;
                            if (!lOldGetLocationAux.Secured) {
                                Sys$UI$DomElement$getLocation = function() {
                                    try {
                                        lOldGetLocationAux.apply({},
                                    arguments);
                                    }
                                    catch (e) {
                                        window.console.error('Error on calling secure Sys$UI$DomElement$getLocation(). Error: ' + e.message);
                                    }
                                };
                                Sys$UI$DomElement$getLocation = true;
                            }
                        }
                        else {
                            window.console.info('Not found Sys$UI$DomElement$getLocation.');
                        }
                    }
                    else {
                        window.console.info('Not found Sys or Sys.UI.DomElement.getLocation().');
                    }
                }
                else {
                    window.console.info('Not found Sys');
                }
            }
            catch (e) {
                window.console.info('Not found Sys. Error: ' + e.message);
            }
        }
        /**
        * Add ff debug rules dinamically to a given stylesheet.
        * If the css file is not present this method could be used.
        * @param {Object} affdebugcss
        */
        function AddFFDebugRules(affdebugcss) {
            if (affdebugcss) {
                // style debug console 
                utils.dom.AddCssRules(affdebugcss, [{
                    Key: '#ffdebug',
                    Values: 'position: absolute; width: 90%; border: 1px solid #666; top: 0px; background: #fff; padding: 10px; cursor: nw-resize;'
}]);
                    // styles for the minimized console
                    utils.dom.AddCssRules(affdebugcss, [{
                        Key: '#ffdebug.minimized',
                        Values: 'width: 4px; height: 4px; background: #fff; border: 3px solid #000; overflow: hidden; padding: 0px; cursor: nw-resize;'
}]);
                        // style error messages 
                        utils.dom.AddCssRules(affdebugcss, [{
                            Key: '#ffdebug.error',
                            Values: 'background: #fcc; padding: 2px;'
}]);
                            // style info messages 
                            utils.dom.AddCssRules(affdebugcss, [{
                                Key: '#ffdebug.info',
                                Values: 'background: #eef; padding: 2px;'
}]);
                            }
                        }
                        CheckConsole();
                        CheckDebug();
                        CheckSecureSys();
                    };

                    ManageConsole();
