$(document).ready(function(){
    new GandiInit({
        'container': 'body',
        'selector': {
            'genericBubule': '.tipster:not(.bottom):not(.right)',
            'rightBubule': '.tipster.right',
            'bottomBubule': '.tipster.bottom',
            'resetFocusEl': '.reset-focus',
            'fboxTable': '.box-fbox-table',
            'clearableInput': 'input.clearable'
        }
    });
});

var AJAX = Class.$extend({
    __classvars__: {
        AUTOHIDE_TIME: g_dev ? 5000 : 5000,
        _options: {},
        _timeStartFlashMssg: null,

        /**
         * Make a request ajax to el.attr url.
         * @params el : Element binded
         * @params settings : Hash of options
         * @return N/A
         */
        ajaxify: function(el, settings) {
            var that = this;

            that._options = {
                'attr': '',
                'url': '',
                'confirmationMessage': '',
                'redirectUriIf401': '/login',
                'params': {},
                'type': '',
                'dataType': 'html',
                'async': true,
                'beforeSend': false,
                'success': false,
                'error': false,
                'complete': false,
                'translations': {
                    'fr' : {
                        '404': 'La page demandée est introuvable.',
                        'login_required': 'Vous avez été déconnecté, merci de <a href="/login" rel="login">vous identifier</a> à nouveau.'
                    },
                    'en': {
                        '404': 'The page requested is not found.',
                        'login_required': 'You have been disconnected, please <a href="/login" rel="login">login</a> again.'
                    },
                    'es': {
                        '404': 'La página solicitada no se encuentra.',
                        'login_required': 'Ha sido desconectado, por favor <a href="/login" rel="login">conéctese</a> de nuevo.'
                    }
                }
            };
            that._options = $.extend(that._options, settings);

            var el_is_form = false;

            if (!that._options.attr || !that._options.type) {
                switch ($(el).tagName()) {
                    case 'form':
                        that._options.attr = that._options.attr || 'action';
                        that._options.type = that._options.type || 'POST';
                        el_is_form = true;
                        break;
                    case 'a':
                    default:
                        that._options.attr = that._options.attr || 'href';
                        that._options.type = that._options.type || 'GET';
                        break;
                }
            }

            /* Get url to the ajax controller */
            if (that._options.url == '') {
                that._options.url = $(el).attr(that._options.attr) || window.location.href;
            }

            /* Push sessid (csrf checks) if exists */
            var $sessid = $('input[name=sessid]');
            if($sessid.length) {
                $.extend(that._options.params, {
                    'sessid' : $sessid.val()
                });
            }

            var action = function(){
                $('body').addClass('progress');

                $.ajax({
                    type: that._options.type,
                    data: that._options.params,
                    dataType: that._options.dataType,
                    url: that._options.url,
                    async: that._options.async,
                    beforeSend: function(XMLHttpRequest) {
                        if (that._options.beforeSend) {
                            that._options.beforeSend(XMLHttpRequest);
                        }
                        if (el_is_form && that._options.params.beforeSend) {
                            eval(that._options.params.beforeSend)(XMLHttpRequest, $(el));
                        }
                    },
                    success: function(response) {
                        $('body').removeClass('progress');

                        if (that._options.success) {
                            that._options.success(response, $(el));
                        }
                        if (el_is_form && that._options.params.success) {
                            eval(that._options.params.success)(response, $(el));
                        }
                    },
                    error: function(XMLHttpRequest, textStatus, errorThrown) {
                        $('body').removeClass('progress');

                        if(g_dev) {
                            console.error(textStatus, XMLHttpRequest.status, errorThrown);
                        }

                        // Expiration login
                        if ( XMLHttpRequest.status == 401 ) {
                            var message = that.translate('login_required', {
                                '/login': that._options.redirectUriIf401
                            });
                            AJAX.showError(message);

                            return false;
                        }

                        // Not found
                        else if (XMLHttpRequest.status == 404) {
                            AJAX.showError(that._options['translations'][g_lang]['404']);
                            return false;
                        }

                        else if ( XMLHttpRequest.status ) {
                            if (that._options.error) {
                                that._options.error(XMLHttpRequest, textStatus, errorThrown, $(el));
                            }
                            else {
                                if (el_is_form && that._options.params.error) {
                                    eval(that._options.params.error)(XMLHttpRequest, textStatus, errorThrown, $(el));
                                }
                                else {
                                    AJAX.showError(XMLHttpRequest.responseText);
                                }
                            }
                        }
                    },
                    complete: function(XMLHttpRequest, textStatus){
                        if (that._options.complete) {
                            that._options.complete(XMLHttpRequest, textStatus, $(el));
                        }
                        if (el_is_form && that._options.params.complete) {
                            eval(that._options.params.complete)(XMLHttpRequest, textStatus, $(el));
                        }
                    }
                });
            }

            that._options.confirmationMessage = that._options.confirmationMessage || that._options.params.confirmationMessage;
            if (!that._options.confirmationMessage || Prompt.confirm(that._options.confirmationMessage)) {
                action();
            }

            $('tr').removeClass('open-action');
        },

        /**
         * Translate messages with replacement patterns.
         */
        translate: function(key, _replacements) {
            var replacements = _replacements || {};
            var message = this._options['translations'][g_lang][key];

            $.each(replacements, function(regexp, value) {
                if(value) {
                    message = message.replace(new RegExp(regexp), value);
                }
            });

            return message;
        },

        /**
         * Return a hash from a $(form) element.
         * @params el : Form
         * @return hash
         */
        hashifyForm: function(el, filter){
            var fields = Object();

            $.each($(el).serializeArray(), function(i, object){
                if(filter && !object.name.match(filter)) {
                    return 1;
                }

                /* make an array if multiple same input name */
                if (fields[object.name]) {
                    if (!$.isArray(fields[object.name])) {
                        var array = new Array();
                        array.push(fields[object.name]);
                        array.push(object.value);
                        fields[object.name] = array;
                    }
                    else {
                        fields[object.name].push(object.value);
                    }
                }
                else {
                    fields[object.name] = object.value;
                }
            });

            return fields;
        },

        /**
         * Show a message before the main content in a fbox box.
         */
        showMessage: function(mssg, _options){
            var options = {
                'container_id': 'ajax-messages',
                'class_box': 'fbox3',//this class will always be defined
                'klass': 'mssg',//this class will be overwritten if called by showError
                'id_box': '',
                'scroll_to': true,
                'redirect_uri': '',
                'sticky': false
            };
            options = $.extend(options, _options);

            if(!mssg) {
                return 1;
            }

            var ajax_messages = $('#' + options.container_id);
            var classes = [options.class_box];
            if(options['sticky']) {
                classes.push('sticky');
            }
            var fbox = $('<div class="' + classes.join(' ') + '" id="' + options.id_box + '"></div>').addClass(options.klass).html(mssg);

            if (!ajax_messages.length) {
                ajax_messages = $('<div id="' + options.container_id +'"></div>');
                $('#main').prepend(ajax_messages);
            }

            if (options.id_box && $('#' + options.id_box).length) {
                $('#' + options.id_box).replaceWith(fbox);
                $('#' + options.id_box).hide().fadeIn();
            }
            else {
                ajax_messages.append(fbox).fadeIn();
            }

            if (options.scroll_to && typeof($.scrollTo) == 'function') {
                $.scrollTo(fbox, 150);
            }

            var now = new Date();
            this._timeStartFlashMssg = now.getTime();
        },

        /**
         * Show a warning before the main content in a fbox box.
         */
        showWarning: function(mssg, _options){
            var options = {
                'klass': 'warning'
            };
            options = $.extend(options, _options);

            this.showMessage(mssg, options);
        },

        /**
         * Show a message before the main content in a fbox box.
         */
        showError: function(mssg, _options){
            var options = {
                'klass': 'error'
            };
            options = $.extend(options, _options);

            this.showMessage(mssg, options);
        },

        /**
         * Hide #ajax-messages
         */
        hideMessages: function(){
            var options = {
                'container_selector': '#ajax-messages',
                'message_selector': 'div:not(.sticky)'
            };
            var $container = $(options.container_selector);
            if ($container.length) {
                $container.find(options['message_selector']).each(function() {
                    $(this).fadeOut(function(){
                        $(this).remove();
                    });
                });
            }
        },

        /**
         * Hide the messages boxes after AUTOHIDE_TIME ms
         */
        autoHideMessages: function() {
            var that = this;

            window.setInterval(function(){
                var now = new Date();
                if (now.getTime() > that._timeStartFlashMssg + that.AUTOHIDE_TIME) {
                    AJAX.hideMessages();
                }
            }, that.AUTOHIDE_TIME);
        },

        /**
         * Show a loading cursor on the body of the page.
         */
        showSpinner: function() {
            $('body').addClass('progress');
        },

        /**
         * Remove the spinner.
         */
        hideSpinner: function() {
            $('body').removeClass('progress');
        }
    }
});

/**
 * Disbled prompts like confirm, alert, etc.
 */
var Prompt = Class.$extend({
    __classvars__ : {
        _disabled: 0,

        setDisabled: function(flag) {
            return Prompt().$class._disabled = flag;
        },

        isDisabled: function() {
            return Prompt().$class._disabled;
        },

        /**
         * Do a window.confirm if prompt is not disabled.
         * @param {String} mssg
         */
        confirm: function(mssg) {
            return !Prompt().$class.isDisabled() ?
                window.confirm(mssg) :
                true;
        },

        /**
         * Confirm leaving the current page is prompt is not disabled.
         * @param {Function} fn
         */
        beforeUnload: function(fn) {
            if (!Prompt().$class.isDisabled()) {
                window.onbeforeunload = function(e){
                    return fn();
                };
            }
        }
    }
});

/**
 * Handle query string parameters.
 * (http://adamv.com/dev/javascript/qslicense.txt)
 */
var Querystring = Class.$extend({
    /**
     * Optionally pass a querystring to parse.
     * @param {Dict} qs
     */
    __init__: function(qs) {
        this._qs = qs;
        this._params = {};

        if (this._qs == null) this._qs = location.search.substring(1, location.search.length);
        if (this._qs.length == 0) return;

        // Turn <plus> back to <space>
        // See: http://www.w3.org/TR/REC-html40/interact/forms.html#h-17.13.4.1
        this._qs = this._qs.replace(/\+/g, ' ');
        var args = this._qs.split('&'); // parse out name/value pairs separated via &

        // split out each name=value pair
        for (var i = 0; i < args.length; i++) {
            var pair = args[i].split('=');
            var key = decodeURIComponent(pair[0]);
            var value = (pair.length == 2) ? decodeURIComponent(pair[1]) : key;

            // if the parameter has square brackets, push into a list
            if(key.match(/\[\]/)) {
                this._params[key] ?
                    this._params[key].push(value) :
                    this._params[key] = [value];
            }
            else {
                this._params[key] = value;
            }
        }
    },

    get: function(key, default_) {
        var value = this._params[key];
        return (value != null) ? value : default_;
    },

    getParams: function() {
        return this._params;
    },

    contains: function(key) {
        var value = this._params[key];
        return (value != null);
    },

    add: function(key, value) {
        this._params[key] = value;
    },

    toStr: function(){
        return Querystring().$class.from(this._params);
    },

    __classvars__: {
        from: function(params){
            var urlParts = new Array();
            for (var key in params) {
                urlParts.push(key + '=' + params[key]);
            }
            return '?' + urlParts.join('&');
        }
    }
});

/**
 * Tools functions.
 * Do not extend native objects' prototype to not alter default behavior of loops, etc.
 */
var Tools = {
    Array: Class.$extend({
        __classvars__: {
            /**
             * Count value in array.
             * @param {Array} array
             * @param {Mixed} value
             */
            countValues: function(array, value) {
                var b = {}, i = array.length, j;
                while(i--) {
                    j = b[array[i]];
                    b[array[i]] = j ? j+1 : 1;
                }
                return b[value];
            },

            /**
             * indexOf implementation for lame IE7...
             * @param {Array} array
             * @param {Object} value
             */
            indexOf: function(array, value) {
                if(Array.indexOf) {
                    return array.indexOf(value);
                }

                for(var i=0; i<array.length; i++){
                    if(array[i]==value){
                        return i;
                    }
                }
                return -1;
            },

            /**
             * Join by removing the false value in a boolean context.
             */
            join: function(array, separator){
                var newArray = $.map(array, function(val, i) { return val ? val : null; })
                return newArray.join(separator);
            }
        }
    }),

    Object: Class.$extend({
        __classvars__: {
            size: function(object) {
                var count = 0;
                for (var k in object) {
                    if (object.hasOwnProperty(k)) count++;
                }
                return count;
            },

            keys: function(obj){
                var keys = [];
                for (i in obj) {
                    if (obj.hasOwnProperty(i)) {
                        keys.push(i);
                    }
                }
                return keys;
            }
        }
    }),

    String: Class.$extend({
        __classvars__: {
            /**
             * Replace underscores to camel case strings.
             * @param {String} _string
             */
            underscoresToCamelCase: function(_string) {
                var words = _string.split('_');

                var finalWorlds = [];
                $.each(words, function(index, word) {
                    if(index == 0) {
                        finalWorlds.push(word);
                    }
                    else {
                        word = word.charAt(0).toUpperCase() + word.slice(1);
                        finalWorlds.push(word);
                    }
                });

                return finalWorlds.join('');
            },

            /**
             * Generate a random string.
             */
            random: function() {
                var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz";
                var string_length = 8;
                var randomstring = '';
                for (var i=0; i<string_length; i++) {
                    var rnum = Math.floor(Math.random() * chars.length);
                    randomstring += chars.substring(rnum,rnum+1);
                }
                return randomstring;
            },

            /**
             * Replace patterns in string.
             * ie: r('Hi %s', 'Bob');
             * @param {string} string
             * @param {array} replacements
             */
            replace: function() {
                var string = arguments[0];
                var list = [].slice.call(arguments, 1);

                $.each(list, function(i, v) {
                    string = string.replace(/[\$|%]\w+/, v);
                });
                return string;
            },

            /**
             * Encode the string to UTF8.
             * @param {String} string
             */
            encode_utf8: function(string) {
                return unescape(encodeURIComponent(string));
            },

            /**
             * Decode the UTF8 string.
             * @param {String} string
             */
            decode_utf8: function(string) {
                return decodeURIComponent(escape(string));
            }
        }
    }),

    Math: Class.$extend({
        __classvars__: {
            CHARS: '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split(''),

            /**
             * Return a random uuid.
             * @param {Integer} len
             * @param {Integer} radix
             */
            uuid: function(len, radix) {
                var chars = Tools.Math().$class.CHARS, uuid = [];
                radix = radix || chars.length;

                if (len) {
                    // Compact form
                    for (var i = 0; i < len; i++)
                        uuid[i] = chars[0 | Math.random() * radix];
                }
                else {
                    // rfc4122, version 4 form
                    var r;

                    // rfc4122 requires these characters
                    uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
                    uuid[14] = '4';

                    // Fill in random data.  At i==19 set the high bits of clock sequence as
                    // per rfc4122, sec. 4.1.5
                    for (var i = 0; i < 36; i++) {
                        if (!uuid[i]) {
                            r = 0 | Math.random() * 16;
                            uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r];
                        }
                    }
                }

                return uuid.join('');
            }
        }
    }),

    Format: Class.$extend({
        __classvars__: {
            /**
             * Return the price according to the current currency
             * @param {Float} price
             * @param {Boolean} tax
             */
            currency: function(price, options) {
                var finalOptions = $.extend({
                    'tax': null
                }, options);

                var priceString;

                switch (g_currency) {
                    case 'EUR':
                        priceString = price.toFixed(2) + '&nbsp;€';
                        priceString = priceString.replace(/\./g, ',');
                        break;
                    case 'USD':
                        priceString = '$' + price.toFixed(2);
                        break;
                    case 'GBP':
                        priceString = '£' + price.toFixed(2);
                        break;
                    default:
                        priceString = price.toFixed(2) + '&nbsp;€';
                        priceString = priceString.replace(/\./g, ',');
                        break;
                }

                if(finalOptions['tax'] !== null) {
                    var priceString = finalOptions['tax'] ?
                        Translations._('ttc_amount', priceString) : Translations._('ht_amount', priceString);
                }

                return priceString;
            },

            /**
             * Return the number with thousand separators
             * @param {Float} _number
             */
            thousandSep: function(_number){
                var step = 3;
                var intPart = parseInt(_number) + '';
                var decPart = _number - intPart + '';
                decPart = decPart.substr(1,step);
                var separator = '';
                var result = '';

                switch (g_lang) {
                    case 'en':
                        separator = ',';
                        break;
                    default:
                        separator = ' ';
                        break;
                }

                if (intPart.length/step <= 1) {
                    result = intPart;
                } else {
                    do {
                        thousandIndex = intPart.length-step;
                        thousandDiv = intPart.substr(thousandIndex,step);
                        intPart = intPart.substr(0,thousandIndex);
                        result = separator + thousandDiv + result;
                    } while (intPart.length > step);
                    if (intPart.length > 0) {
                        result = intPart + result;
                    };
                };
                return result + decPart;
            },

            /**
             * Return the size with the unit
             * @param {String} _size
             * @param {Integer} _multiplier
             */
            size: function(_size, _multiplier){
                switch (_multiplier) {
                    case 1: /* o */
                        return _size + ' ' + (g_lang == 'fr' ? 'o' : 'B');
                        break;
                    case 1024: /* Ko */
                        return _size + ' ' + (g_lang == 'fr' ? 'Ko' : 'KB');
                        break;
                    case 1024 ^ 2: /* Mo */
                        return _size + ' ' + (g_lang == 'fr' ? 'Mo' : 'MB');
                        break;
                    case 1024 ^ 3: /* Go */
                        return _size + ' ' + (g_lang == 'fr' ? 'Go' : 'GB');
                        break;
                    case 1024 ^ 4: /* To */
                        return _size + ' ' + (g_lang == 'fr' ? 'To' : 'TB');
                        break;
                    default: /* Mo */
                        return _size + ' ' + (g_lang == 'fr' ? 'Mo' : 'MB');
                        break;
                }
            }
        }
    })
}

/**
 * Shortcuts
 */
var r = Tools.String.replace;

/**
 * Abstract manager to handle easier pages bindings.
 *
 * Just extends your manager from this class like this:
 *   var MyManager = AbstractPageManager.$extend({
 *       _initBindings: function() {
 *           //job
 *       }
 *   });
 *
 *   var myManager = new MyManager({...});
 *
 * @param {Dict} config
 */
var AbstractPageManager = Class.$extend({
    __init__: function(config) {
        this._config = $.extend({
            'container': 'div#body',
            'selector': {
                //'popups': '.popup'
            },
            'translations': {}
        }, config);

        this._parameters = {};
        this._$container = $(this._config.container);

        this._findSelectors();
        this._init();
        this._initBindings();
    },

    /**
     * Set some params into the parameters dict.
     * @param {Object} params
     */
    setParams: function(params) {
        this._parameters = $.extend(this._config.parameters, params);
    },

    /**
     * Retrieve the value of a parameter from its key.
     */
    getParam: function(key) {
        return this._config.parameters[key];
    },

    /**
     * Return the jQuery element matching the main container.
     */
    get$Container: function() {
        return this._config.container ?
            $(this._config.container) : $();
    },

    /**
     * Return the jQuery collection mapping the selector key.
     */
    get$: function(selectorKey, reload) {
        if(reload) {
            this._findSelectors();
        }

        var key = '_$'+selectorKey;
        if(!this[key]) {
            this[key] = $();
        }
        return this[key];
    },

    /**
     * Return the config of the manager.
     */
    getConfig: function(key) {
        return key ? this._config[key] : this._config;
    },

    /**
     * Loop on selectors and save the jQuery collections.
     */
    _findSelectors: function(){
        var that = this;

        $.each(this._config.selector, function(varName, selector){
            varName = '_$' + varName;
            that[varName] = that._$container.find(selector);
        })

        return this;
    },

    /**
     * Execute page bindings.
     */
    _initBindings: function(){
        // to be extended.
    },

    /**
     * Do some optionnal initialization.
     */
    _init: function() {
        // to be extended.
    },

    /**
     * Handle translations.
     */
    _: function() {
        var key = arguments[0];
        var list = [].slice.call(arguments, 1);

        return r(this._config.translations[key] || '-', list);
    },

    /**
     * Return the dev flag
     */
    _if_dev: function() {
        return g_dev;
    }
});

/**
 * Generic translations used in JS scripts.
 */
var Translations = Class.$extend({
    __classvars__: {
        _translations: {},

        /**
         * Save the JSON structure into the object.
         * @param {Object} json
         */
        set: function(json) {
            this._translations = json;
        },

        /**
         * Return the translated string by replacing %s or $var (for example)
         * by arguments list.
         */
        _: function() {
            var key = arguments[0];
            var list = [].slice.call(arguments, 1);

            return r(this._translations[key] || '-', list);
        }
    }
});

/**
 * Static class to save manager instances.
 */
var Manager = Class.$extend({
    __classvars__: {
        _instances: {},

        get: function(instanceName){
            return Manager().$class._instances[instanceName];
        },

        save: function(instanceName, manager){
            Manager().$class._instances[instanceName] = manager;
        },

        list: function(){
            $.each(Manager().$class._instances, function(name, instance){
                console.log(name, instance);
            });
        }
    }
});

/**
 * Default bindings, bubules, styles, etc.
 */
var GandiInit = AbstractPageManager.$extend({
    _initBindings: function() {
        this._ajaxInit();
        this._initBubule();
        this._globalBindings();
        this._globalVars();
        this._setJsClass();
    },

    /**
     * Add default bubule on .tipster elements.
     */
    _initBubule: function() {
        BubuleManager.addBubule({'targetElement': this.get$('genericBubule')});
        BubuleManager.addBubule({'targetElement': this.get$('rightBubule'), 'position': 'right'});
        BubuleManager.addBubule({'targetElement': this.get$('bottomBubule'), 'position': 'bottom'});
    },

    /**
     * Autohide ajax messages,
     * Configure jQuery ajax calls.
     */
    _ajaxInit: function() {
        AJAX.autoHideMessages();

        jQuery.ajaxSetup({
            // don't cache jquery ajax GET by default
            cache: false,
            // jQuery 1.5+ compatibility
            jsonp: null,
            jsonpCallback: null
        });
    },

    _globalVars: function() {
        // TODO: Put everything (g_dev, etc) in a unique global variable.

        // Key codes (can be usefull, and not every page loads jQuery UI, which already defines these constants):
        keyCode = {
            ALT: 18,
            BACKSPACE: 8,
            CAPS_LOCK: 20,
            COMMA: 188,
            COMMAND: 91,
            COMMAND_LEFT: 91, // COMMAND
            COMMAND_RIGHT: 93,
            CONTROL: 17,
            DELETE: 46,
            DOWN: 40,
            END: 35,
            ENTER: 13,
            ESCAPE: 27,
            HOME: 36,
            INSERT: 45,
            LEFT: 37,
            MENU: 93, // COMMAND_RIGHT
            NUMPAD_ADD: 107,
            NUMPAD_DECIMAL: 110,
            NUMPAD_DIVIDE: 111,
            NUMPAD_ENTER: 108,
            NUMPAD_MULTIPLY: 106,
            NUMPAD_SUBTRACT: 109,
            PAGE_DOWN: 34,
            PAGE_UP: 33,
            PERIOD: 190,
            RIGHT: 39,
            SHIFT: 16,
            SPACE: 32,
            TAB: 9,
            UP: 38,
            WINDOWS: 91 // COMMAND
        };
    },

    _globalBindings: function() {
        // reset input on focus/blur
        this.get$('resetFocusEl').focusClearsDefault();
        // stylize tables
        this.get$('fboxTable').stylise();
        // add a nice icon to inputs to delete value
        this.get$('clearableInput').clearableTextField();
    },

    /**
     * Add class to the body tag
     *
     * @access  private
     * @return  void
     */
    _setJsClass: function() {
        this.get$Container().addClass('js');
    }
});

/**
 * Global functions more or less deprecated.
 */

/**
 * For IE8 compatibility (which doesn't implement document.getElementByClassName)
 */
function getElementsByClass(searchClass, node, tag){
    var classElements = new Array();
    if (node == null)
        node = document;
    if (tag == null)
        tag = '*';
    var els = node.getElementsByTagName(tag);
    var elsLen = els.length;
    var pattern = new RegExp("(^|\\s)" + searchClass + "(\\s|$)");
    for (var i = 0, j = 0; i < elsLen; i++) {
        if (pattern.test(els[i].className)) {
            classElements[j] = els[i];
            j++;
        }
    }
    return classElements;
}

/**
 * Submit d'un form quand click sur pager
 * un seul form par "main"
 * @TODO A pluginiser pour jQuery
 */
function attach_pagers_events(sub){
    var divs = $('#main div');

    var pagers = new Array();

    /* Sub par défaut .. */
    if (typeof(sub) == "undefined") {
        sub = function(){
            return _submitForm(this)
        };
    }

    $('#main div .pager a').click(sub);
}

