'use strict';

var _classCallCheck = require('@babel/runtime/helpers/classCallCheck');
var _createClass = require('@babel/runtime/helpers/createClass');
require('core-js/modules/es.array.concat.js');
require('core-js/modules/es.array.find.js');
require('core-js/modules/es.number.is-nan.js');
require('core-js/modules/es.object.to-string.js');

function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }

var _classCallCheck__default = /*#__PURE__*/_interopDefault(_classCallCheck);
var _createClass__default = /*#__PURE__*/_interopDefault(_createClass);

var IdleTimer = /*#__PURE__*/function () {
  function IdleTimer(_ref) {
    var _ref$timeout = _ref.timeout,
      timeout = _ref$timeout === void 0 ? 1800 : _ref$timeout,
      _ref$countdown = _ref.countdown,
      countdown = _ref$countdown === void 0 ? 30 : _ref$countdown,
      _ref$cookieName = _ref.cookieName,
      cookieName = _ref$cookieName === void 0 ? '_user_inactivity_timeout' : _ref$cookieName,
      _ref$cookieDomain = _ref.cookieDomain,
      cookieDomain = _ref$cookieDomain === void 0 ? '' : _ref$cookieDomain,
      _ref$onIdleTimeoutWar = _ref.onIdleTimeoutWarning,
      onIdleTimeoutWarning = _ref$onIdleTimeoutWar === void 0 ? function () {} : _ref$onIdleTimeoutWar,
      _ref$onIdleTimeout = _ref.onIdleTimeout,
      onIdleTimeout = _ref$onIdleTimeout === void 0 ? function () {} : _ref$onIdleTimeout,
      _ref$onRestart = _ref.onRestart,
      onRestart = _ref$onRestart === void 0 ? function () {} : _ref$onRestart,
      _ref$onCookieCleared = _ref.onCookieCleared,
      onCookieCleared = _ref$onCookieCleared === void 0 ? function () {} : _ref$onCookieCleared;
    _classCallCheck__default.default(this, IdleTimer);
    // Initialize constants
    this.COOKIE_CHECK_INTERVAL = 1000; // 1 second
    this.ACTIVITY_DEBOUNCE = 500; // 500 milliseconds
    this.COUNTDOWN_START = countdown;
    this.COOKIE_NAME = cookieName;
    this.COOKIE_DOMAIN = cookieDomain;
    this.TIMEOUT = timeout;

    // Set callbacks
    this.onIdleTimeoutWarning = onIdleTimeoutWarning;
    this.onIdleTimeout = onIdleTimeout;
    this.onRestart = onRestart;
    this.onCookieCleared = onCookieCleared;

    // Bind the user activity event handler to IdleTimer's object (this)
    this.eventHandler = this.debouncedUpdateExpiredTime.bind(this);

    // Start idle user detection
    this.start();
  }
  return _createClass__default.default(IdleTimer, [{
    key: "startIdleUserDetectionInterval",
    value: function startIdleUserDetectionInterval() {
      var _this = this;
      if (this.TIMEOUT === 0) {
        // No reason to do any of this if they have not defined a timeout
        return;
      }
      // Push the cookie forward by this.TIMEOUT
      this.updateUserInactivityTimeoutCookie();
      // Reset the countdown
      this.countdown = this.COUNTDOWN_START;
      // Make sure we don't stack up setInterval threads
      if (this.intervalHandler) {
        clearInterval(this.intervalHandler);
      }
      // Initialize the setInterval thread
      this.intervalHandler = setInterval(function () {
        // Check if userInactivityTimeout is not a number, which indicates that a the cookie might have been deleted in another tab
        var userInactivityTimeoutValue = _this.getUserInactivityTimeoutCookie();
        var cookieClearedInDifferentTab = Number.isNaN(userInactivityTimeoutValue);
        if (cookieClearedInDifferentTab) {
          _this.onCookieCleared();
          _this.cleanUp();
        }
        var now = Date.now();
        // Check if user is idle by comparing the inactivity timeout cookie timestamp with the current time
        if (userInactivityTimeoutValue < now) {
          // Fire onIdleTimeoutWarning during the countdown, and when countdown reaches zero, fire onIdleTimeout.
          if (_this.countdown === 0) {
            _this.onIdleTimeout();
            // End the execution of IdleTimer
            _this.cleanUp();
          } else {
            _this.onIdleTimeoutWarning(_this.countdown);
            // Decrease countdown each time onIdleTimeoutWarning is fired
            _this.countdown = _this.countdown === 0 ? _this.countdown : Math.max(_this.COUNTDOWN_START - parseInt((now - (userInactivityTimeoutValue - _this.COOKIE_CHECK_INTERVAL)) / 1000, 10), 0);
          }
        } else if (_this.countdown < _this.COUNTDOWN_START) {
          // This means that the cookie has been updated by a restart of IdleTimer running in some other tab during the countdown (when onIdleTimeoutWarning was being fired)
          _this.onRestart();
          _this.countdown = _this.COUNTDOWN_START;
        }
      }, this.COOKIE_CHECK_INTERVAL);
    }
  }, {
    key: "getUserInactivityTimeoutCookie",
    value: function getUserInactivityTimeoutCookie() {
      var _this2 = this;
      var cookie = document.cookie.split('; ').find(function (currentCookie) {
        return currentCookie.split('=')[0] === _this2.COOKIE_NAME;
      });
      var cookieValue = cookie === null || cookie === void 0 ? void 0 : cookie.split('=')[1];
      return parseInt(decodeURIComponent(cookieValue), 10);
    }
  }, {
    key: "setUserInactivityTimeoutCookie",
    value: function setUserInactivityTimeoutCookie(timestamp, expires) {
      // Write the inactivity timeout cookie
      document.cookie = "".concat(this.COOKIE_NAME, "=").concat(encodeURIComponent(timestamp), ";expires=").concat(expires, ";path=/;domain=").concat(this.COOKIE_DOMAIN, ";").concat(window.location.protocol === 'https:' ? 'Secure;' : '');
    }
  }, {
    key: "updateUserInactivityTimeoutCookie",
    value: function updateUserInactivityTimeoutCookie() {
      // Cookie will expire in 7 days (this doesn't matter as the cookie is always recreated on user activity and when IdleTimer is restarted)
      var expires = new Date(Date.now() + 6048e5).toUTCString();
      var timestamp = Date.now() + this.TIMEOUT * 1000;
      this.setUserInactivityTimeoutCookie(timestamp, expires);
    }
  }, {
    key: "debouncedUpdateExpiredTime",
    value: function debouncedUpdateExpiredTime() {
      var _this3 = this;
      // Expired time is only updated if inactivity timeout has not been reached
      // Otherwise, the only way to resume inactivity timeout cookie updates is by calling restart()
      var userInactivityTimeoutValue = this.getUserInactivityTimeoutCookie();
      var cookieStillExists = !Number.isNaN(userInactivityTimeoutValue);
      var userIsActive = Date.now() < userInactivityTimeoutValue;
      if (cookieStillExists && userIsActive) {
        if (this.debounceTimeoutHandler) {
          clearTimeout(this.debounceTimeoutHandler);
        }
        this.debounceTimeoutHandler = setTimeout(function () {
          _this3.updateUserInactivityTimeoutCookie();
        }, this.ACTIVITY_DEBOUNCE);
      }
    }
  }, {
    key: "createUserActivityListeners",
    value: function createUserActivityListeners() {
      // Make sure we don't stack up event listeners
      this.cleanUpUserActivityListeners();
      // Listen for mouse and keuboard events
      window.addEventListener('mousemove', this.eventHandler);
      window.addEventListener('mousedown', this.eventHandler);
      window.addEventListener('scroll', this.eventHandler);
      window.addEventListener('keydown', this.eventHandler);
      window.addEventListener('clientTimerEvent', this.eventHandler, true);
      // Listen for mobile (touch) events
      window.addEventListener('touchstart', this.eventHandler);
      window.addEventListener('touchend', this.eventHandler);
      window.addEventListener('touchmove', this.eventHandler);
      window.addEventListener('touchcancel', this.eventHandler);
    }
  }, {
    key: "cleanUpUserActivityListeners",
    value: function cleanUpUserActivityListeners() {
      // Cleanup all listeners
      window.removeEventListener('mousemove', this.eventHandler);
      window.removeEventListener('mousedown', this.eventHandler);
      window.removeEventListener('scroll', this.eventHandler);
      window.removeEventListener('keydown', this.eventHandler);
      window.removeEventListener('clientTimerEvent', this.eventHandler);
      window.removeEventListener('touchstart', this.eventHandler);
      window.removeEventListener('touchend', this.eventHandler);
      window.removeEventListener('touchmove', this.eventHandler);
      window.removeEventListener('touchcancel', this.eventHandler);
    }
  }, {
    key: "start",
    value: function start() {
      // Create the event listeners and start the setInterval that keeps checking for inactivity
      this.createUserActivityListeners();
      this.startIdleUserDetectionInterval();
    }
  }, {
    key: "restart",
    value: function restart() {
      this.start();
    }
  }, {
    key: "cleanUp",
    value: function cleanUp() {
      clearInterval(this.intervalHandler);
      this.cleanUpUserActivityListeners();
      this.onIdleTimeoutWarning = function () {};
    }
  }]);
}();
var IdleTimer$1 = IdleTimer;

module.exports = IdleTimer$1;
