/**
 * @file
 * JavaScript for autologout.
 */

(function ($, Drupal) {

  'use strict';

  /**
   * Attaches the batch behavior for autologout.
   *
   * @type {Drupal~behavior}
   */
  Drupal.behaviors.autologout = {
    attach: function (context, settings) {
      if (context !== document) {
        return;
      }

      var paddingTimer;
      var theDialog;
      var t;
      var localSettings;

      // Activity is a boolean used to detect a user has
      // interacted with the page.
      var activity;

      // Timer to keep track of activity resets.
      var activityResetTimer;

      // Prevent settings being overridden by ajax callbacks by cloning it.
      localSettings = jQuery.extend(true, {}, settings.autologout);

      // Add timer element to prevent detach of all behaviours.
      var timerMarkup = $('<div id="timer"></div>').hide();
      $('body').append(timerMarkup);

      if (localSettings.refresh_only) {
        // On pages where user shouldn't be logged out, don't set the timer.
        t = setTimeout(keepAlive, localSettings.timeout);
      }
      else {
        // Set no activity to start with.
        activity = false;

        // Bind formUpdated events to preventAutoLogout event.
        $('body').bind('formUpdated', function (event) {
          $(event.target).trigger('preventAutologout');
        });

        // Bind formUpdated events to preventAutoLogout event.
        $('body').bind('mousemove', function (event) {
          $(event.target).trigger('preventAutologout');
        });

        // Support for CKEditor.
        if (typeof CKEDITOR !== 'undefined') {
          CKEDITOR.on('instanceCreated', function (e) {
            e.editor.on('contentDom', function () {
              e.editor.document.on('keyup', function (event) {
                // Keyup event in ckeditor should prevent autologout.
                $(e.editor.element.$).trigger('preventAutologout');
              });
            });
          });
        }

        $('body').bind('preventAutologout', function (event) {
          // When the preventAutologout event fires, we set activity to true.
          activity = true;

          // Clear timer if one exists.
          clearTimeout(activityResetTimer);

          // Set a timer that goes off and resets this activity indicator after
          // a minute, otherwise sessions never timeout.
          activityResetTimer = setTimeout(function () {
            activity = false;
          }, 60000);
        });

        // On pages where the user should be logged out, set the timer to popup
        // and log them out.
        t = setTimeout(init, localSettings.timeout);
      }

      function init() {
        var noDialog = settings.autologout.no_dialog;
        if (activity) {
          // The user has been active on the page.
          activity = false;
          refresh();
        }
        else {
          // The user has not been active, ask them if they want to stay logged
          // in and start the logout timer.
          paddingTimer = setTimeout(confirmLogout, localSettings.timeout_padding);
          // While the countdown timer is going, lookup the remaining time. If
          // there is more time remaining (i.e. a user is navigating in another
          // tab), then reset the timer for opening the dialog.
          Drupal.Ajax['autologout.getTimeLeft'].autologoutGetTimeLeft(function (time) {
            if (time > 0) {
              clearTimeout(paddingTimer);
              t = setTimeout(init, time);
            }
            else {
              // Logout user right away without displaying a confirmation dialog.
              if (noDialog) {
                logout();
                return;
              }
              theDialog = dialog();
            }
          });
        }
      }

      function dialog() {
        var buttons = {};
        buttons[Drupal.t('Yes')] = function () {
          $(this).dialog("destroy");
          clearTimeout(paddingTimer);
          refresh();
        };

        buttons[Drupal.t('No')] = function () {
          $(this).dialog("destroy");
          logout();
        };

        return $('<div id="autologout-confirm">' + localSettings.message + '</div>').dialog({
          modal: true,
          closeOnEscape: false,
          width: "auto",
          dialogClass: 'autologout-dialog',
          title: localSettings.title,
          buttons: buttons,
          close: function (event, ui) {
            logout();
          }
        });
      }

      // A user could have used the reset button on the tab/window they're
      // actively using, so we need to double check before actually logging out.
      function confirmLogout() {
        $(theDialog).dialog('destroy');

        Drupal.Ajax['autologout.getTimeLeft'].autologoutGetTimeLeft(function (time) {
          if (time > 0) {
            t = setTimeout(init, time);
          }
          else {
            logout();
          }
        });
      }

      function logout() {
        if (localSettings.use_alt_logout_method) {
          window.location = drupalSettings.path.baseUrl + "autologout_ahah_logout";
        }
        else {
          $.ajax({
            url: drupalSettings.path.baseUrl + "autologout_ahah_logout",
            type: "POST",
            beforeSend: function (xhr) {
              xhr.setRequestHeader('X-Requested-With', {
                toString: function (){
                  return '';
                }
              });
            },
            success: function () {
              window.location = localSettings.redirect_url;
            },
            error: function (XMLHttpRequest, textStatus) {
              if (XMLHttpRequest.status === 403 || XMLHttpRequest.status === 404) {
                window.location = localSettings.redirect_url;
              }
            }
          });
        }
      }

      /**
       * Get the remaining time.
       *
       * Use the Drupal ajax library to handle get time remaining events
       * because if using the JS Timer, the return will update it.
       *
       * @param function callback(time)
       *   The function to run when ajax is successful. The time parameter
       *   is the time remaining for the current user in ms.
       */
      Drupal.Ajax.prototype.autologoutGetTimeLeft = function (callback) {
        var ajax = this;

        if (ajax.ajaxing) {
          return false;
        }
        ajax.options.success = function (response, status) {
          if (typeof response == 'string') {
            response = $.parseJSON(response);
          }
          if (typeof response[0].command === 'string' && response[0].command === 'alert') {
            // In the event of an error, we can assume user has been logged out.
            window.location = localSettings.redirect_url;
          }

          callback(response[1].settings.time);

          response[0].data = '<div id="timer" style="display: none;">' + response[0].data + '</div>';

          // Let Drupal.ajax handle the JSON response.
          return ajax.success(response, status);
        };

        try {
          $.ajax(ajax.options);
        }
        catch (e) {
          ajax.ajaxing = false;
        }
      };

      Drupal.Ajax['autologout.getTimeLeft'] = Drupal.ajax({
        base: null,
        element: document.body,
        url: drupalSettings.path.baseUrl + 'autologout_ajax_get_time_left',
        event: 'autologout.getTimeLeft',
        error: function (XMLHttpRequest, textStatus) {
          // Disable error reporting to the screen.
        }
      });

      /**
       * Handle refresh event.
       *
       * Use the Drupal ajax library to handle refresh events because if using
       * the JS Timer, the return will update it.
       *
       * @param function timerFunction
       *   The function to tell the timer to run after its been restarted.
       */
      Drupal.Ajax.prototype.autologoutRefresh = function (timerfunction) {
        var ajax = this;

        if (ajax.ajaxing) {
          return false;
        }

        ajax.options.success = function (response, status) {
          if (typeof response === 'string') {
            response = $.parseJSON(response);
          }
          if (typeof response[0].command === 'string' && response[0].command === 'alert') {
            // In the event of an error, we can assume the user has been logged out.
            window.location = localSettings.redirect_url;
          }

          t = setTimeout(timerfunction, localSettings.timeout);
          activity = false;

          // Wrap response data in timer markup to prevent detach of all behaviors.
          response[0].data = '<div id="timer" style="display: none;">' + response[0].data + '</div>';

          // Let Drupal.ajax handle the JSON response.
          return ajax.success(response, status);
        };

        try {
          $.ajax(ajax.options);
        }
        catch (e) {
          ajax.ajaxing = false;
        }
      };

      Drupal.Ajax['autologout.refresh'] = Drupal.ajax({
        base: null,
        element: document.body,
        url: drupalSettings.path.baseUrl + 'autologout_ahah_set_last',
        event: 'autologout.refresh',
        error: function (XMLHttpRequest, textStatus) {
          // Disable error reporting to the screen.
        }
      });

      function keepAlive() {
        Drupal.Ajax['autologout.refresh'].autologoutRefresh(keepAlive);
      }

      function refresh() {
        Drupal.Ajax['autologout.refresh'].autologoutRefresh(init);
      }

      // Check if the page was loaded via a back button click.
      var $dirty_bit = $('#autologout-cache-check-bit');
      if ($dirty_bit.length !== 0) {
        if ($dirty_bit.val() === '1') {
          // Page was loaded via back button click, we should refresh the timer.
          refresh();
        }

        $dirty_bit.val('1');
      }
    }
  };

})(jQuery, Drupal);