﻿/* Report AJAX errors
 *
 * Usage:
 * jQuery.ajaxError(handleAjaxError);
 */
function handleAjaxError(event, request, options) {
    if (request.readyState == 4) {
        alert("Le serveur a renvoyé une erreur imprévue. Contactez l'assistance utilisateurs.\n\n" + request.status + " " + request.statusText + "\n" + jQuery.trim(request.responseText));
    }
    else {
        alert("Le serveur ne répond pas. Réessayez dans quelques instants ou contacter l'assistance utilisateurs.");
    }
}

/* Write email through JavaScript to protect us from spammers */
function writeEmailLink(user, domain) {
    var email = user + '@' + domain;
    document.write('<a href="mailto:' + email + '">' + email + '</a>');
}

(function () {
    /*
    Return a copy of the function bound to "object". This means whenever and
    however the returned function is called, "this" will always reference the
    given "object".

    This allows for easy use of object methods in callbacks and other places in
    which the "this" keyword may otherwise not reference the expected scope.

    This function conforms to ECMAScript, Fifht Edition.

    Arguments:
      object: The object that the "this" of the function will refer to.

    Returns:
      The bound function.
    */
    if (!Function.prototype.bind) {
        // XXX need unit test
        Function.prototype.bind = function (object) {
            var method = this;
            if (arguments.length > 1) {
                var boundArgs = Array.prototype.slice.call(arguments, 1);
                return function () {
                    return method.apply(object, boundArgs.concat.apply(boundArgs, arguments));
                };
            }
            else {
                // Fast path if there are no additional arguments
                return function () {
                    return method.apply(object, arguments);
                };
            }
        };
    };

    // TODO: Find a better identifier for these methods?
    jQuery.fn.ajaxForm = function (onSuccess) {
        return this.submit(function () {
            jQuery(this).ajaxSubmit(onSuccess);
            return false;
        });
    };

    jQuery.fn.ajaxButton = function (onSuccess) {
        return this.click(function () {
            jQuery(this.form).ajaxSubmit(onSuccess);
            return false;
        });
    };

    jQuery.fn.ajaxSubmit = function (onSuccess) {
        return this.each(function () {
            var form = jQuery(this);
            form.find(".loading").show();
            form.find(":submit").attr("disabled", "disabled");
            jQuery.ajax({
                type: 'POST',
                url: this.action,
                data: form.serialize(),
                dataType: "json",
                success: function (data) {
                    // TODO: Return errors as HTTP status 422 Unprocessable Entity?
                    if ('error' in data) {
                        form.showError(data);
                    }
                    else {
                        form.clearError();
                        onSuccess(data);
                    }
                },
                complete: function () {
                    form.find(".loading").hide();
                    form.find(":submit").removeAttr("disabled");
                }
            });
        });
    };

    jQuery.fn.showError = function (data) {
        this.clearError();

        var invalidFields = data.invalidFields || [];
        for (var i = 0; i < invalidFields.length; i++)
            this.find(":input[name=" + invalidFields[i] + "]")
                .closest("tr")
                .find("label:first")
                .addClass("error");

        window.scrollTo(0, 0);
        this.find(".errormessage").text(data.error).fadeIn();
    };

    jQuery.fn.clearError = function () {
        return this
            .find(".errormessage").hide().end()
            .find("label").removeClass("error").end();
    };

    /*
    jQuery.cookie(name)

    Returns the value of the named cookie.

    jQuery.cookie(name, value, days)

    Sets the value of the named cookie. The optional days parameter specifies
    the number of days before cookie expiration.
    */
    jQuery.cookie = function (name, value, days) {
        if (value === undefined) {
            return getCookie(name);
        }
        else {
            setCookie(name, value, days);
        }
    };

    /*
    jQuery.removeCookie(name)

    Deletes the named cookie by setting its expiration date in the past.
    */
    jQuery.removeCookie = function (name) {
        setCookie(name, "", -1);
    }

    function setCookie(name, value, days) {
        if (days) {
            var date = new Date();
            date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
            var expires = "; expires=" + date.toUTCString();
        }
        else {
            var expires = "";
        }
        document.cookie = name + "=" + encodeURIComponent(value) + expires + "; path=/";
    }

    function getCookie(name) {
        var cookie,
            cookies = document.cookie.split(';');

        for (var i = 0; i < cookies.length; i ++) {
            cookie = cookies[i].split('=');
            if (jQuery.trim(cookie[0]) == name) {
                return decodeURIComponent(cookie[1]);
            }
        }
        return null;
    }

    jQuery.fn.flash = function () {
        var message = jQuery.cookie(jQuery.fn.flash.cookieName);
        if (message) {
            this.html(message).fadeIn();
            jQuery.removeCookie(jQuery.fn.flash.cookieName);
        }
    }

    jQuery.fn.flash.cookieName = 'flash';

})();
