/**
* @author msalla
*/
var Pb = Pb || {};

Pb.Utils = Pb.Utils || {};

(function() {
    if (window.jQuery) {
        (function($) {
            /**
            * Gets the most top window document embedded in a jQuery object manager.
            * The top document must have jQuery loaded otherwise this method will fail.
            * @access private
            * @static
            * @return {Object} - The most top window document embedded in a jQuery object manager.
            */
            var getjQueryTopDocument = function() {
                var lWindowTop = Pb.Utils.safeGetWindowTop();
                var jTopDocument = lWindowTop.$(lWindowTop.document);
                return jTopDocument;
            };

            var TTopEvents = function() {

                var TopEvents = function() {
                };

                TopEvents.prototype = {
                    /**
                    * Bind a top event using jQuery event binding.
                    * @access public
                    * @param Object evt - Event.
                    * @param Function fn - Event - Event handler of type function(event,param1, param2). Handlers can access bind data using event.data.
                    * @param Object data - Event data to be passed inside the event as event.data extensions to each handler.
                    * @param Object currentWindow - current active window to set automatic on unload.
                    * @return Object jQuery
                    */
                    topBind: function(evt, fn, data, currentWindow) {
                        var jTopDocument = getjQueryTopDocument();
                        if (data) {
                            jTopDocument.bind(evt, data, fn);
                        }
                        else {
                            jTopDocument.bind(evt, fn);
                        }
                        var lCurrentWindow = currentWindow ? currentWindow : window;
                        $(lCurrentWindow).unload(function() {
                            jTopDocument.unbind(evt, fn);
                        });
                    },
                    /**
                    * Unbinds a topEvent.
                    * @access public
                    * @param Object evt - Event.
                    * @param Function fn - Event handler of type function(event,param1, param2).
                    * @return Object jQuery
                    */
                    topUnBind: function(evt, fn) {
                        var jTopDocument = getjQueryTopDocument();
                        jTopDocument.unbind(evt, fn);
                    },
                    /**
                    * Triggers a top event to all its subscriptors.
                    * @param {Object} evt - Event.Remember that by namespacing all subnamespaced event handlers will also be called.
                    * @param {Object} data. Data must be passed as an array of argument values [param1,param2,...].
                    *
                    */
                    topTrigger: function(evt, data) {
                        var jTopDocument = getjQueryTopDocument();
                        jTopDocument.trigger(evt, data);
                    }
                };
                return {
                    TopEvents: new TopEvents()
                };
            } ();
            $.extend(Pb.Utils, TTopEvents);

            $.pbTopEvents = Pb.Utils.TopEvents;

            var extensions = {
                /**
                * Bind a top event using jQuery event binding.
                * @access public
                * @param String evt - Event name.
                * @param Function fn - Event - handler(event). Can access data using event.data.
                * @param Object data - Event data to be passed inside the event as event.data to each handler.
                * @param Object doDelegation - Create delegate on each item forcing the context to each item executing the handler function.
                * @return Object jQuery
                */
                topBind: function(evt, fn, data, doDelegation) {
                    var jTopDocument = getjQueryTopDocument();
                    // Aquí recorremos el array de objetos
                    return this.each(function() {
                        // Forzamos contexto de ejecución de evento si se indica aunque nos 
                        // suscribamos a nivel de documento. Aquí this es el objeto del dom 
                        // del array de jQuery.
                        var lHandler = doDelegation ? Pb.Utils.createDelegate(this, fn) : fn;
                        var lEvt = evt;
                        if (typeof lEvt == "string" && lEvt !== '') {
                            var jCurrentElement = $(this);
                            // Usamos event namespacing con los id's de los elementos para
                            // poder distinguir en el unbind por el id
                            lEvt += '.';
                            // Si el elemento tiene id lo usamos
                            if (jCurrentElement.attr('id') && jCurrentElement.attr('id') !== "") {
                                lEvt += '.' + jCurrentElement.attr('id');
                            }
                            else {
                                // Si no tiene id generamos uno se lo establecemos y lo usamos
                                var lRandomGeneratedClientId = Pb.Utils.generateRandomClientId();
                                lEvt += '.' + lRandomGeneratedClientId;
                                jCurrentElement.attr({
                                    id: lRandomGeneratedClientId
                                });
                            }
                            if (data) {
                                jTopDocument.bind(lEvt, data, lHandler);
                            }
                            else {
                                jTopDocument.bind(lEvt, lHandler);
                            }
                            var lCurrentWindow = this.ownerDocument.parentWindow ? this.ownerDocument.parentWindow : this.ownerDocument.defaultView;
                            lCurrentWindow = lCurrentWindow ? lCurrentWindow : window;
                            $(lCurrentWindow).unload(function() {
                                jTopDocument.unbind(lEvt, lHandler);
                            });
                        }
                    });
                },
                /**
                * Unbinds a topEvent using event namespacing.
                * @access public
                * @param String evt - Event name.
                * @param Function fn - Event - handler(event).
                * @return Object jQuery
                */
                topUnBind: function(evt, fn) {
                    var jTopDocument = getjQueryTopDocument();
                    // Aquí recorremos el array de objetos
                    return this.each(function() {
                        // Forzamos contexto de ejecución de evento aunque nos suscribamos a nivel de documento
                        // aquí this es el objeto del dom del array de jQuery.
                        var lEvt = evt;
                        if (typeof lEvt == "string" && lEvt !== '') {
                            var jCurrentElement = $(this);
                            // Usamos event namespacing con los id's de los elementos para
                            // poder distinguir en el unbind por el id
                            lEvt += '.';
                            // Si el elemento tiene id lo usamos
                            if (jCurrentElement.attr('id') && jCurrentElement.attr('id') !== "") {
                                lEvt += jCurrentElement.attr('id');
                            }
                            jTopDocument.unbind(lEvt);
                        }
                    });
                },
                /**
                * Triggers a top event to all its subscriptors.
                * @param {String} evt - Event name. Remember that by namespacing all subnamespaced event handlers will also be called.
                * @param {Object} data - Data must be passed as an array of argument values [param1,param2,...]. Extended to include the source property if not set.
                */
                topTrigger: function(evt, data) {
                    this.each(function() {
                        var self = this;
                        var lData = data || {};
                        lData = $.extend(lData, {
                            source: self
                        });
                        Pb.Utils.TopEvents.topTrigger(evt, lData);
                    });
                }
            };

            $.each(extensions, function(i) {
                $[i] = $.fn[i] = this;
            });
        })(window.jQuery);
    }
})();
