/*
 * jquery.ajax-retry
 * https://github.com/johnkpaul/jquery-ajax-retry
 *
 * Copyright (c) 2012 John Paul
 * Licensed under the MIT license.
 */
(function(factory) {
    if (typeof define === 'function' && define.amd) {
        // AMD. Register as an anonymous module.
        define(['jquery'], factory);
    } else if (typeof exports === 'object') {
        // Node/CommonJS
        factory(require('jquery'));
    } else {
        // Browser globals
        factory(jQuery);
    }
})(function($) {

    // enhance all ajax requests with our retry API
    $.ajaxPrefilter(function(options, originalOptions, jqXHR) {
        jqXHR.retry = function(opts) {
            if(opts.timeout) {
                this.timeout = opts.timeout;
            }
            if (opts.statusCodes) {
                this.statusCodes = opts.statusCodes;
            }
            return this.pipe(null, pipeFailRetry(this, opts));
        };
    });

    // generates a fail pipe function that will retry `jqXHR` `times` more times
    function pipeFailRetry(jqXHR, opts) {
        var times = opts.times;
        var timeout = jqXHR.timeout;

        // takes failure data as input, returns a new deferred
        return function(input, status, msg) {
            var ajaxOptions = this;
            var output = new $.Deferred();
            var retryAfter = jqXHR.getResponseHeader('Retry-After');

            // whenever we do make this request, pipe its output to our deferred
            function nextRequest() {
                $.ajax(ajaxOptions)
                    .retry({times: times - 1, timeout: opts.timeout})
                    .pipe(output.resolve, output.reject);
            }

            if (times > 1 && (!jqXHR.statusCodes || $.inArray(input.status, jqXHR.statusCodes) > -1)) {
                // implement Retry-After rfc
                // http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.37
                if (retryAfter) {
                    // it must be a date
                    if (isNaN(retryAfter)) {
                        timeout = new Date(retryAfter).getTime() - $.now();
                        // its a number in seconds
                    } else {
                        timeout = parseInt(retryAfter, 10) * 1000;
                    }
                    // ensure timeout is a positive number
                    if (isNaN(timeout) || timeout < 0) {
                        timeout = jqXHR.timeout;
                    }
                }

                if (timeout !== undefined){
                    setTimeout(nextRequest, timeout);
                } else {
                    nextRequest();
                }
            } else {
                // no times left, reject our deferred with the current arguments
                output.rejectWith(this, arguments);
            }

            return output;
        };
    }

});