/*
 * jQuery Idle Timeout 1.2
 * Copyright (c) 2011 Eric Hynds
 *
 * http://www.erichynds.com/jquery/a-new-and-improved-jquery-idle-timeout-plugin/
 *
 * Depends:
 *  - jQuery 1.4.2+
 *  - jQuery Idle Timer (by Paul Irish, http://paulirish.com/2009/jquery-idletimer-plugin/)
 *
 * Dual licensed under the MIT and GPL licenses:
 *   http://www.opensource.org/licenses/mit-license.php
 *   http://www.gnu.org/licenses/gpl.html
 *
 */

(function ($, win) {
  var idleTimeout = {
    init: function (element, resume, options) {
      var self = this,
        elem;

      this.warning = elem = $(element);
      this.resume = $(resume);
      this.options = options;
      this.countdownOpen = false;
      this.failedRequests = options.failedRequests;
      this._startTimer();
      this.title = document.title;

      // expose obj to data cache so peeps can call internal methods
      $.data(elem[0], "idletimeout", this);

      // start the idle timer
      $.idleTimer(options.idleAfter * 1000);

      // once the user becomes idle
      $(document).bind("idle.idleTimer", function () {
        // if the user is idle and a countdown isn't already running
        if ($.data(document, "idleTimer") === "idle" && !self.countdownOpen) {
          self._stopTimer();
          self.countdownOpen = true;
          self._idle();
        }
      });

      // bind continue link
      this.resume.bind("click", function (e) {
        e.preventDefault();

        win.clearInterval(self.countdown); // stop the countdown
        self.countdownOpen = false; // stop countdown
        self._startTimer(); // start up the timer again
        self._keepAlive(false); // ping server
        options.onResume.call(self.warning); // call the resume callback
      });
    },

    _idle: function () {
      var self = this,
        options = this.options,
        warning = this.warning[0],
        counter = options.warningLength;

      // fire the onIdle function
      options.onIdle.call(warning);

      // set inital value in the countdown placeholder
      options.onCountdown.call(warning, counter);

      // create a timer that runs every second
      this.countdown = win.setInterval(function () {
        if (--counter === 0) {
          window.clearInterval(self.countdown);
          options.onTimeout.call(warning);
        } else {
          options.onCountdown.call(warning, counter);
          document.title =
            options.titleMessage.replace("%s", counter) + self.title;
        }
      }, 1000);
    },

    _startTimer: function () {
      var self = this;

      this.timer = win.setTimeout(function () {
        self._keepAlive();
      }, this.options.pollingInterval * 1000);
    },

    _stopTimer: function () {
      // reset the failed requests counter
      this.failedRequests = this.options.failedRequests;
      win.clearTimeout(this.timer);
    },

    _keepAlive: function (recurse) {
      var self = this,
        options = this.options;

      //Reset the title to what it was.
      document.title = self.title;

      // assume a startTimer/keepAlive loop unless told otherwise
      if (typeof recurse === "undefined") {
        recurse = true;
      }

      // if too many requests failed, abort
      if (!this.failedRequests) {
        this._stopTimer();
        options.onAbort.call(this.warning[0]);
        return;
      }

      $.ajax({
        timeout: options.AJAXTimeout,
        url: options.keepAliveURL,
        error: function () {
          self.failedRequests--;
        },
        success: function (response) {
          if ($.trim(response) !== options.serverResponseEquals) {
            self.failedRequests--;
          }
        },
        complete: function () {
          if (recurse) {
            self._startTimer();
          }
        },
      });
    },
  };

  // expose
  $.idleTimeout = function (element, resume, options) {
    idleTimeout.init(element, resume, $.extend($.idleTimeout.options, options));
    return this;
  };

  // options
  $.idleTimeout.options = {
    // number of seconds after user is idle to show the warning
    warningLength: 30,

    // url to call to keep the session alive while the user is active
    keepAliveURL: "",

    // the response from keepAliveURL must equal this text:
    serverResponseEquals: "OK",

    // user is considered idle after this many seconds.  10 minutes default
    idleAfter: 600,

    // a polling request will be sent to the server every X seconds
    pollingInterval: 60,

    // number of failed polling requests until we abort this script
    failedRequests: 5,

    // the $.ajax timeout in MILLISECONDS!
    AJAXTimeout: 250,

    // %s will be replaced by the counter value
    titleMessage: "Warning: %s seconds until log out | ",

    /*
			Callbacks
			"this" refers to the element found by the first selector passed to $.idleTimeout.
		*/
    // callback to fire when the session times out
    onTimeout: $.noop,

    // fires when the user becomes idle
    onIdle: $.noop,

    // fires during each second of warningLength
    onCountdown: $.noop,

    // fires when the user resumes the session
    onResume: $.noop,

    // callback to fire when the script is aborted due to too many failed requests
    onAbort: $.noop,
  };
})(jQuery, window);
