/**
 * @author msalla
 */
var Pb = Pb ||
{};

(function() {
    if (window.jQuery) {
        (function($) {
            /**
            * Portalbuilder Pb.Utils namespace and functions.
            * @author msalla
            * @namespace Pb.Utils
            */
            var TUtils = function() {

                /**
                * Generates a random number inside a given range.
                * @access private
                * @static
                * @param {Object} range
                */
                var getRandomNumber = function(range) {
                    return Math.floor(Math.random() * range);
                };
                /**
                * Generates a random alphabetic character.
                * @access private
                * @static
                */
                var getRandomAplhaChar = function() {
                    var chars = "abcdefghijklmnopqurstuvwxyzABCDEFGHIJKLMNOPQURSTUVWXYZ";
                    return chars.substr(getRandomNumber(52), 1);
                };
                /**
                * Generates a random alphanumeric character.
                * @access private
                * @static
                */
                var getRandomChar = function() {
                    var chars = "0123456789abcdefghijklmnopqurstuvwxyzABCDEFGHIJKLMNOPQURSTUVWXYZ";
                    return chars.substr(getRandomNumber(62), 1);
                };
                /**
                * Generates a random alphanumeric string of a given size.
                * @access private
                * @static
                * @param {int} size - The text size of the random id to generate
                * @param {int} alphaStart - Starts with an alphanumeric char.
                * @return {string} - The random generated id.
                */
                var randomText = function(size, alphaStart) {
                    var str = alphaStart ? getRandomAplhaChar() : "";
                    for (var i = alphaStart ? 1 : 0; i < size; i++) {
                        str += getRandomChar();
                    }
                    return str;
                };

                /**
                * Basic system utilities. In the future we should migrate progressively the
                * current seUtils here or as an extension plugin.
                * @namespace Pb.Utils
                */
                function Utils() {
                }
                Utils.prototype = {
                    /**
                    * Gets the most accessible top window. Used in the backoffice to set
                    * common global object references and global event bindings. If the
                    * most top window is not accessible because of SDP then the current
                    * window is returned instead.
                    */
                    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;
                        }
                    },
                    /**
                    * Curry delegate function. If Ms ajax framework is present we use it.
                    * @param {Object} aInstance - Object context method.
                    * @param {Function} aFunction - Function to be called.
                    * @return - The function delegate.
                    * @type {Function}
                    */
                    createDelegate: Function.createDelegate ||
                    function(aInstance, aFunction) {
                        return function() {
                            return aFunction.apply(aInstance, arguments);
                        };
                    },
                    /**
                    * From O'Reilly Javascript and DHTML Cookbook:
                    * To determine the mouse event location in the coordinate plane of the entire
                    * document, the getPageEventCoords( ) function shown in the following example
                    * has two main branches. The first gets the simpler pageX and pageY properties
                    *  of the Netscape event object. For IE, many more calculations need to be
                    * carried out to derive the coordinates to accurately position an element at
                    * the specified location. The clientX and clientY properties need additional
                    * factors for any scrolling of the body content and some small padding that
                    * IE automatically adds to the body (normally two pixels along both axes).
                    * In the case of IE 6 running in CSS-compatibility mode, the html element's
                    * small padding must also be factored out of the equation.
                    * @param {Object} evt
                    */
                    getPageEventCoords: function(evt) {
                        var coords = {
                            left: 0,
                            top: 0
                        };
                        if (evt.pageX) {
                            coords.left = evt.pageX;
                            coords.top = evt.pageY;
                        }
                        else
                            if (evt.clientX) {
                            coords.left = evt.clientX + document.body.scrollLeft - document.body.clientLeft;
                            coords.top = evt.clientY + document.body.scrollTop - document.body.clientTop;
                            // include html element space, if applicable
                            if (document.body.parentElement && document.body.parentElement.clientLeft) {
                                var bodParent = document.body.parentElement;
                                coords.left += bodParent.scrollLeft - bodParent.clientLeft;
                                coords.top += bodParent.scrollTop - bodParent.clientTop;
                            }
                        }
                        return coords;
                    },
                    /**
                    * Clears the current text selection.
                    */
                    clearTextSelection: function() {
                        var sel;
                        if (document.selection && document.selection.empty) {
                            document.selection.empty();
                        }
                        else
                            if (window.getSelection) {
                            sel = window.getSelection();
                            if (sel && sel.removeAllRanges) {
                                sel.removeAllRanges();
                            }
                            if (sel && sel.collapse) {
                                sel.collapse();
                            }
                        }
                    },

                    /**
                    * Gets the global object reference manager.
                    */
                    getGlobal: function() {
                        return this.safeGetWindowTop().seGlobal;
                    },
                    /**
                    * Gets the global object reference refresh manager.
                    */
                    getGlobalRefreshManager: function() {
                        return this.safeGetWindowTop().GlobalRefreshManager;
                    },
                    /**
                    * Generates a random NOT Globally But Locally 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;
                    },
                    /**
                    * Generates a randomClientId
                    * @param {Object} size
                    */
                    generateRandomClientId: function(size) {
                        return randomText(size, true);
                    },
                    /**
                    * Generates a random text.
                    * @param {int} size - The text size of the random id to generate
                    * @param {int} alphaStart - Starts with an alphanumeric char.
                    */
                    generateRandomText: function(size, alphaStart) {
                        return randomText(size, true);
                    },                    /**
                    * 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
                    * @param {function} aCallback : fn(aCallbackData, 'success', aNewIFrame)
                    * @param {object} aCallBackContext
                    * @param {object} aCallbackData
                    */
                    createXssFrame: function(/*string */aIFrameSrc, aCallback, aCallBackContext, aCallbackData) {
                        var lCallBackContext = aCallBackContext ||
                        {};
                        var lCallBackData = aCallbackData || null;
                        var lNewIFrame = document.createElement('iframe');
                        var lNewIFrameId = 'iTempFrame__' + Pb.Utils.generateGuid();
                        lNewIFrame.setAttribute('id', lNewIFrameId);
                        lNewIFrame.style.display = 'none';
                        lNewIFrame.setAttribute('src', aIFrameSrc);
                        document.body.appendChild(lNewIFrame);
                        function checkIframeLoading() {
                            try {
                                // Check if loading is complete
                                if (lNewIFrame.document.readyState == 'complete') {
                                    // The loading is complete, call the function we want executed once the iframe is loaded
                                    try {
                                        aCallback.apply(lCallBackContext, [aCallbackData, 'success', lNewIFrame]);
                                    }
                                    catch (ex) {
                                        //alert(ex.message);
                                    }
                                    document.body.removeChild(lNewIFrame);
                                    return;
                                }
                                // If we are here, it is not loaded. Set things up so we check   the status again in 100 milliseconds
                                window.setTimeout(checkIframeLoading, 100);
                            }
                            catch (ex) {
                            }
                        }
                        checkIframeLoading();
                    },

                    pageIsValid: function() {
                        // Si hay validadores de .NET
                        if (typeof (Page_Validators) != "undefined") {
                            return Page_ClientValidate();
                            if (!Page_IsValid)  // Comprobar validez de página
                                return false;
                        }
                        return true;
                    },

                    /* Recorrer todos los editores recogiendo valores */
                    getClientPropertyValues: function() {
                        // Recoger los valores de todos los editores
                        var clientPropertyValueList = new Array();
                        var hasAnyPropertyValueChanged = false;
                        var errors = new Array();
                        $.each(EditorsList, function(i, val) {
                            var editor = $find(val);
                            if (editor.get_isNotUpdateable()) return true;
                            var clientPropertyValue = {
                                PropertyName: editor.get_propertyName(),
                                Value: editor.get_data(),
                                IsDefault: editor.is_default()
                            };
                            clientPropertyValue.HasChanged = editor.dataHasChanged();
                            if (editor.isValid()) {
                                clientPropertyValueList.push(clientPropertyValue);
                                if (clientPropertyValue.HasChanged) {
                                    hasAnyPropertyValueChanged = true;
                                }
                            } else {
                                errors.push("La propiedad '" + clientPropertyValue.PropertyName + "' tiene un valor incorrecto.");
                            }
                        });
                        var result = {
                            clientPropertyValueList: clientPropertyValueList,
                            hasAnyPropertyValueChanged: hasAnyPropertyValueChanged,
                            errors: errors
                        };
                        return result;
                    },

                    saveWithOptions: function(saveOptions) {
                        if (!Pb.Utils.pageIsValid()) {
                            return;
                        }

                        // Recorrer todos los editores recogiendo valores
                        var result = Pb.Utils.getClientPropertyValues();

                        var clientPropertyValueList = result.clientPropertyValueList;
                        var hasAnyPropertyValueChanged = result.hasAnyPropertyValueChanged;
                        var errors = result.errors;

                        if (errors.length == 0 || saveOptions.saveMethod == "AutoSave") {

                            if ((saveOptions.saveMethod == "AutoSave") && (hasAnyPropertyValueChanged == false)) {
                                return;
                            }

                            arguments = saveOptions.generateArgumentsFunction(saveOptions, clientPropertyValueList);
                            saveOptions.executeServiceFunction(saveOptions, arguments);
                        } else {
                            if (saveOptions.showErrorMessageFunction)
                                saveOptions.showErrorMessageFunction();
                        }
                    },

                    publicSave: function(successCallback, failCallback) {
                        // Manera de detectar si es modificación.Algo cutre, ya veremos que es mejor
                        var isNew = $.query.get('dfid') != "";
                        var executeService;
                        var generateArgumentsFunction;
                        if (isNew) {
                            /* 
                            Redirección para editar el contenido recién creado.
                            
                            TODO: Para entrada de datos masivos, quiza lo mejor no es editar
                            lo que acabamos de crear sino simplemente limpiar el formulario, para
                            entrar un nuevo contenido */

                            var editCreatedContentFunction = Function.createDelegate(this, function(result) {
                                successCallback(result);
                                // Si estamos en modal
                                if (Pb.Utils.StringContains(window.location.search, 'framecontentid')) {
                                    // Lo mejor es cerrar y volver.
                                    var wnd = TLK.GetCurrentRadWindow();
                                    if (wnd)
                                        wnd.close();
                                }
                                else {
                                    var newUrl = window.location.href.replace(window.location.search, '');
                                    newUrl += '?ctid=' + result.d.ContentId;
                                    if (result.d.MultiValue === true) {
                                        newUrl += '&ivrowid=' + result.d.RowId;
                                    }
                                    window.location.href = newUrl;
                                }
                            });

                            executeService = Function.createDelegate(this, function(options, arguments) {
                            Pb.Utils.execAjaxSvcMethod('FormService.asmx', 'CreateContent', arguments, editCreatedContentFunction, failCallback);
                            });

                            generateArgumentsFunction = Function.createDelegate(this, function(saveOptions, clientPropertyValueList) {
                                // TODO: Ver si los parámertos se siguen obteniendo del querystring.
                                var arguments = $.compactJSON({
                                    "aDefinitionId": $.query.get('dfid'),
                                    "aParentContentId": $.query.get('pctid'),
                                    "aContentName": '',
                                    "aValues": clientPropertyValueList
                                });
                                return arguments;
                            });
                        }
                        else {
                            executeService = Function.createDelegate(this, function(options, arguments) {
                            Pb.Utils.execAjaxSvcMethod("FormService.asmx", "SaveContentPropertyRowAutoPublishAndCheckOut", arguments, successCallback, failCallback);
                            });

                            // Obtengo el primer editor para obtener contentVersionId y rowId, es algo guarro, se aceptan sugerencias
                            var editor = $find(EditorsList[0]);
                            generateArgumentsFunction = Function.createDelegate(this, function(saveOptions, clientPropertyValueList) {
                                // Si es autosave nos hemos saltado valores incorrectos 
                                // y guardamos el resto igualmente
                                var arguments = $.compactJSON({
                                    "aContentVersionId": editor.get_contentVersionId(),
                                    "aRowId": editor.get_rowId(),
                                    "aPropertyValues": clientPropertyValueList
                                });
                                return arguments;
                            });
                        }

                        var options = {
                            executeServiceFunction: executeService,
                            generateArgumentsFunction: generateArgumentsFunction
                        };
                        Pb.Utils.saveWithOptions(options);
                    },

                    publicWFMove: function(aBranchId, aStepTo, aSuccessCallback) {
                        var arguments = $.compactJSON({
                            "aBranchId": aBranchId,
                            "aStepTo": aStepTo
                        });

                        Pb.Utils.execAjaxSvcMethod("Web20Service.asmx", "WFMove", arguments, aSuccessCallback);
                    },

                    /**
                    * Executes a service method call using the default parameters.
                    * @param {Object} serviceName
                    * @param {Object} methodName
                    * @param {Object} methodArguments
                    * @param {Object} onSuccess
                    * @param {Object} onFail
                    * @param {Object} sync - Syncronous or async call
                    */
                    execAjaxSvcMethod: function(serviceName, methodName, methodArguments, onSuccess, onFail, sync) {
                        $.ajax({
                            async: !sync,
                            type: "POST",
                            url: "/pb/services/" + serviceName + "/" + methodName + "?pbl=" + Pb.Utils.Url.getPageLang(),
                            data: methodArguments,
                            contentType: "application/json; charset=utf-8",
                            dataType: "json",
                            success: onSuccess,
                            error: onFail ||
                            function(XMLHttpRequest, textStatus, errorThrown) {
                                try {
                                    var msg;
                                    if ($.evalJSON(XMLHttpRequest.responseText).ExceptionType.indexOf("SdkValidationException") != -1) {
                                        msg = $.evalJSON(XMLHttpRequest.responseText).Message;
                                    }
                                    else {
                                        msg = 'Error al realizar la llamada ajax: ' + serviceName + '/' + methodName + ": " + $.evalJSON(XMLHttpRequest.responseText).Message;
                                    }
                                    if (TLK.RadAlert) {
                                        TLK.RadAlert(msg, 600, ' ');
                                    }
                                    else {
                                        alert(msg);
                                    }

                                }
                                catch (e) {
                                    var msg = 'Error al realizar la llamada ajax: ' + serviceName + '/' + methodName;
                                    if (TLK.RadAlert) {
                                        TLK.RadAlert(msg);
                                    }
                                    else {
                                        alert(msg);
                                    }
                                }
                            }
                        });
                    },

                    // Función chorra pero útil
                    StringContains: function(aEntireString, aStringPart) {
                        return aEntireString.toLowerCase().search(aStringPart) != -1;
                    },

                    /**
                    * Sets an iframe new url with steroids.
                    * @param {Object} aIframe : to change the url to.
                    * @param {Object} url : New iframe url.
                    * @param {Object} onLoad : function to be executed on iframe load event.
                    * @param {Object} options : Steroid options.
                    * 	{
                    * 		timeout : 0, // frame timeout in milliseconds
                    * 		onTimeout : null, //timeout callback function. function(iframe,timeoutElapdsedMilliSeconds)
                    * 		onReady: null //on iframe ready callback function. function(iframe,readyElapdsedMilliSeconds)
                    * 	}
                    */
                    setIframeUrl: function(aIframe, url, onLoad, options) {
                        var iframe = $(aIframe);
                        var timer = iframe.data("timer");
                        iframe.unbind("load");
                        if (timer) {
                            clearTimeout(timer);
                            iframe.data("timer", null);
                        }

                        var defaults = {
                            timeout: 0,
                            onTimeout: null,
                            onReady: null
                        };
                        var opts = $.extend(defaults, options);

                        opts.frameactive = true;

                        var startTime = (new Date()).getTime();

                        if (opts.timeout) {
                            iframe.data("timer", setTimeout(function() {
                                opts.frameactive = false;
                                iframe.load(null);
                                if (opts.onTimeout) {
                                    opts.onTimeout(iframe.get(0), opts.timeout);
                                }
                            }, opts.timeout));
                            timer = iframe.data("timer");
                        }

                        if (opts.onReady) {
                            iframe.unbind("ready");
                            iframe.ready(function() {
                                if (opts.frameactive) {
                                    var duration = (new Date()).getTime() - startTime;
                                    opts.onReady(this, duration);
                                }
                            });
                        }

                        var onloadHandler = function() {
                            var duration = (new Date()).getTime() - startTime;
                            if (iframe.data("timer")) {
                                clearTimeout(timer);
                                iframe.data("timer", null);
                            }
                            if (onLoad && opts.frameactive) {
                                onLoad(this, duration);
                            }
                            opts.frameactive = false;
                        };
                        iframe.attr("src", url);
                        iframe.get()[0].onload = onloadHandler;
                        iframe.data("onloadHandler", onloadHandler);
                        opts.completeReadyStateChanges = 0;
                        var IeOnlyOnreadystatechange = function() { // IE ftw
                            if (++(opts.completeReadyStateChanges) == 3) {
                                onloadHandler();
                            }
                        };
                        iframe.get()[0].onreadystatechange = IeOnlyOnreadystatechange;
                        iframe.data("onreadystatechange", IeOnlyOnreadystatechange);
                    },
                    /**
                    * Clear the iFrame operation timer and load function.
                    * @param {Object} aIframe
                    */
                    clearIframeOperationTimer: function(aIframe) {
                        var iframe = $(aIframe);
                        var timer = iframe.data("timer");
                        if (timer) {
                            clearTimeout(timer);
                            iframe.data("timer", null);
                        }
                        iframe.unbind("load", iframe.data("onloadHandler"));
                        iframe.get()[0].onreadystatechange = null;
                    },
                    /**
                    * Includes JavaScript file in the head of the page dinamically.
                    * Non compatible safari versions (maybe < v2.0)
                    * @param {String} scriptUrl.
                    */
                    includeJs: function(scriptUrl) {
                        // Handle multiple include attempts 
                        if ($("script[src='" + scriptUrl + "']").size() === 0) {
                            $('head').createAppend('script', {
                                type: 'text/javascript',
                                src: scriptUrl
                            });
                        }
                    },
                    /**
                    * Includes JavaScript file in the head of the iframe document dinamically.
                    * Non compatible safari versions (maybe < v2.0)
                    * @param {String} scriptUrl.
                    */
                    includeIframeJs: function(aIframe, scriptUrl) {
                        var lIframeElContentWindow = aIframe.contentWindow || (aIframe.contentDocument ? aIframe.contentDocument.defaultView : null);
                        // TODO: Avoid the need for jQuery in the iFrame window.
                        if (lIframeElContentWindow && lIframeElContentWindow.document) {
                            var jDoc = $(lIframeElContentWindow.document);
                            // Handle multiple include attempts 
                            if (jDoc.find("script[src='" + scriptUrl + "']").size() === 0) {
                                jDoc.find('head').createAppend('script', {
                                    type: 'text/javascript',
                                    src: scriptUrl
                                });
                            }
                        }
                    },
                    /**
                    * Loads and executes a local JavaScript file dinamically synchronously.
                    * @param {String} scriptUrl
                    */
                    loadScript: function(scriptUrl) {
                        // Change requests to be sent synchronous 
                        $.ajaxSetup({
                            async: false
                        });
                        try {
                            // Loads and executes a local JavaScript file 
                            $.getScript(scriptUrl);
                        }
                        finally {
                            // Restore requests to be sent asynchronous 
                            $.ajaxSetup({
                                async: true
                            });
                        }
                    }

                };
                return {
                    Utils: new Utils()
                };
            } ();
            $.extend(Pb, TUtils);

            $.pbUtils = Pb.Utils;

            //var extensions = {
            //};

            //$.each( extensions, function( i )
            //{
            //	$.fn[i] = this;
            //});
        })(window.jQuery);
    }
})();

