
function Ajax() {

    // Constantes liées aux tailles de spinner
    var smallWidth = 4;
    var smallRadius = 5;

    var mediumWidth = 8;
    var mediumRadius = 20;

    var largeWidth = 12;
    var largeRadius = 36;

    // Definitions des differentes tailles de spinner
    var smallSpinOptions = {
        lines: 11, // The number of lines to draw
        length: 0, // The length of each line
        width: smallWidth, // The line thickness
        radius: smallRadius, // The radius of the inner circle
        corners: 1, // Corner roundness (0..1)
        rotate: 0, // The rotation offset
        direction: 1, // 1: clockwise, -1: counterclockwise
        color: '#000', // #rgb or #rrggbb
        speed: 1.0, // Rounds per second
        trail: 60, // Afterglow percentage
        shadow: false, // Whether to render a shadow
        hwaccel: false, // Whether to use hardware acceleration
        className: 'spinner', // The CSS class to assign to the spinner
        zIndex: 2e9, // The z-index (defaults to 2000000000)
        top: 'auto', // Top position relative to parent in px
        left: 'auto' // Left position relative to parent in px
    };

    var mediumSpinOptions = {
        lines: 11, // The number of lines to draw
        length: 0, // The length of each line
        width: mediumWidth, // The line thickness
        radius: mediumRadius, // The radius of the inner circle
        corners: 1, // Corner roundness (0..1)
        rotate: 0, // The rotation offset
        direction: 1, // 1: clockwise, -1: counterclockwise
        color: '#000', // #rgb or #rrggbb
        speed: 1.0, // Rounds per second
        trail: 60, // Afterglow percentage
        shadow: false, // Whether to render a shadow
        hwaccel: false, // Whether to use hardware acceleration
        className: 'spinner', // The CSS class to assign to the spinner
        zIndex: 2e9, // The z-index (defaults to 2000000000)
        top: 'auto', // Top position relative to parent in px
        left: 'auto' // Left position relative to parent in px
    };

    var largeSpinOptions = {
        lines: 11, // The number of lines to draw
        length: 0, // The length of each line
        width: largeWidth, // The line thickness
        radius: largeRadius, // The radius of the inner circle
        corners: 1, // Corner roundness (0..1)
        rotate: 0, // The rotation offset
        direction: 1, // 1: clockwise, -1: counterclockwise
        color: '#000', // #rgb or #rrggbb
        speed: 1.0, // Rounds per second
        trail: 60, // Afterglow percentage
        shadow: false, // Whether to render a shadow
        hwaccel: false, // Whether to use hardware acceleration
        className: 'spinner', // The CSS class to assign to the spinner
        zIndex: 2e9, // The z-index (defaults to 2000000000)
        top: 'auto', // Top position relative to parent in px
        left: 'auto' // Left position relative to parent in px
    };


    /**
     * Initilisation du composant.
     * Création de la fonction JQuery spin
     */
    this.initialize = function() {
        /* Creation de la fonction spin */
        $.fn.spin = function(opts) {
            this.each(function() {
                var $this = $(this),
                        spinner = $this.data('spinner');

                if (spinner)
                    spinner.stop();
                if (opts !== false) {
                    opts = $.extend({
                        color: $this.css('color')
                    }, opts);
                    spinner = new Spinner(opts).spin(this);
                    $this.data('spinner', spinner);
                }
            });
            return this;
        };
    };

    this.createOneventCallback = function(renderIds, usercallback) {
        if (usercallback) {
            return function(data) {
                orion.ajax.onevent(data, renderIds);
                usercallback(data);
            };
        }
        else {
            return function(data) {
                orion.ajax.onevent(data, renderIds);
            };
        }
    };

    /*
     * This is called by the AjaxBehaviorRenderer script to
     * trigger a jsf.ajax.request() call.
     *
     *  @param s the source element or id
     *  @param e event of the calling function
     *  @param n name of the behavior event that has fired
     *  @param ex execute list
     *  @param re render list
     *  @param op options object
     */
    this.ab = function ab(s, e, n, ex, re, op) {
        if (op) {

            if (op.onevent) {
                op.onevent = this.createOneventCallback(re, op.onevent);
            }
            else {
                op.onevent = this.createOneventCallback(re);
            }

            if (op.onerror) {
                var saveCallback = op.onerror;
                op.onerror = function(data) {
                    orion.ajax.onerror();
                    saveCallback(data);
                };
            }
            else {
                op.onerror = function(data) {
                    orion.ajax.onerror();
                };
            }
        }
        else {
            op = {onevent: this.createOneventCallback(re)};
        }
        mojarra.ab(s, e, n, ex, re, op);
    };

    /**
     * Fonction ORION de gestion des appels AJAX.
     */
    this.onevent = function(data, targets) {
        if (data.status === "begin") {
            orion.event.fireBeforeAjax();
            orion.ajax.showSpinNotifications(data, targets);
        } else if (data.status === "complete") {
            orion.ajax.cleanSpinners();
        } else if (data.status === "success") {
            orion.event.fireAfterAjax();
        }
    };

    /**
     * Fonction ORION de gestion des erreurs AJAX
     */
    this.onerror = function() {
        orion.ajax.cleanSpinners();
    };

    /* Fonction de génération du SPINNER */
    this.showSpinNotifications = function(data, targets) {

        var idSelector = data.source.id;
        idSelector = orion.ajax.replaceAll(idSelector, ":", "\\:");
        idSelector = "#" + idSelector;

        var spinnerContainer = orion.ajax.buildSpinnerContainer(idSelector);
        $(spinnerContainer).insertAfter(idSelector);


        if (targets) {
            var targetsTab = targets.split(" ");
            var targetSelector;
            for (var i = 0; i < targetsTab.length; i++) {
                targetSelector = orion.ajax.replaceAll(targetsTab[i], ":", "\\:");
                spinnerContainer = orion.ajax.buildSpinnerContainer("#" + targetSelector);
                $(spinnerContainer).insertAfter("#" + targetSelector);
            }
        }

        $("*[data-o-role='spinner-small']").show().spin(smallSpinOptions);
        $("*[data-o-role='spinner-medium']").show().spin(mediumSpinOptions);
        $("*[data-o-role='spinner-large']").show().spin(largeSpinOptions);
    };

    this.cleanSpinners = function() {
        $("*[data-o-role='spinner-small']").remove();
        $("*[data-o-role='spinner-medium']").remove();
        $("*[data-o-role='spinner-large']").remove();
    };

    /* Fonction de génération XHTML du container des spinners */
    this.buildSpinnerContainer = function(targetSelector) {
        var theSpinnerContainer = "";

        // .position() uses position relative to the offset parent, 
        var pos = $(targetSelector).position();

        if (pos) {
            // .outerWidth() takes into account border and padding.
            var width = $(targetSelector).outerWidth();
            var height = $(targetSelector).outerHeight();

            var topBase = (pos.top + (height / 2)) + "px";
            var leftBase = (pos.left + (width / 2)) + "px";

            theSpinnerContainer = "<div data-o-role='spinner-" + orion.ajax.getSpinnerPreset(width, height) + "' style='display:none; position: absolute; z-index: 200000000;";
            theSpinnerContainer += "top: " + topBase + ";";
            theSpinnerContainer += "left: " + leftBase + ";'></div>";
        }

        return theSpinnerContainer;
    };


    /* Fonction qui determine le preset du spinner à utiliser */
    this.getSpinnerPreset = function(width, height) {
        var spinnerPreset = "small";
        var mediumMaxSize = (mediumWidth * 2) + mediumRadius;
        var largeMaxSize = (largeWidth * 2) + largeRadius;

        var sizeToMatch = Math.min(width, height);
        if (sizeToMatch > largeMaxSize) {
            spinnerPreset = "large";
        } else if (sizeToMatch > mediumMaxSize) {
            spinnerPreset = "medium";
        }

        return spinnerPreset;
    };

    this.replaceAll = function(txt, replace, with_this) {
        return txt.replace(new RegExp(replace, 'g'), with_this);
    };
}

// liste des évènements du composant
orion.event.AFTER_AJAX = "orion.ajax.after";
orion.event.BEFORE_AJAX = "orion.ajax.before";

// Common events        
orion.event.fireAfterAjax = function() {
    orion.event.fireEvent(orion.event.AFTER_AJAX);
};

// Common events        
orion.event.fireBeforeAjax = function() {
    orion.event.fireEvent(orion.event.BEFORE_AJAX);
};

orion.event.listenToAfterAjax = function(handler) {
    $(document).on(orion.event.AFTER_AJAX, handler);
};
orion.event.listenToBeforeAjax = function(handler) {
    $(document).on(orion.event.BEFORE_AJAX, handler);
};
orion.event.listenToAjaxSuccess = function(handler) {
    $(document).on("ajax.success", handler);
};

orion.ajax = new Ajax();

$(document).ready(function() {
    orion.ajax.initialize();
});

