/**
 * @file Dialogs inspired by TES III: Morrowind. Long live House Telvanni.
 * @module dialog
 */

/**
 * The global ID of onscreen dialogs. Starts at 0.
 * @type {number}
 * @memberof module:dialog
 */
window.DIALOG_ID = 0;

/**
 * Creates a dialog and puts it onscreen with various options and callbacks.
 *
 * @function dialog
 * @param {Object} options - Configuration options for the dialog.
 * @param {(string|HTMLElement)} [options.text] - The text or HTML to display in the dialog.
 *                                                Text is auto-converted to HTML.
 * @param {string} [options.title] - The dialog's title.
 * @param {boolean} [options.modal=false] - Whether to open a modal dialog. Implies draggable=false;
 *                                          dialogClass='ui-dialog-modal'. Note that modal dialogs hijack
 *                                          the entire screen and should only be used in specific cases.
 *                                          If IITC is running on mobile, modal will always be true.
 * @param {string} [options.id] - A unique ID for this dialog. If a dialog with this ID is already open,
 *                                it will be automatically closed.
 * @param {Function} [options.closeCallback] - A callback to run on close.
 * @param {Function} [options.collapseCallback] - A callback to run on dialog collapse.
 * @param {Function} [options.expandCallback] - A callback to run on dialog expansion.
 * @param {Function} [options.collapseExpandCallback] - A callback to run on both collapse and expand.
 *                                                      Overrides collapseCallback and expandCallback.
 *                                                      Receives a boolean argument `collapsing`.
 * @param {Function} [options.focusCallback] - A callback to run when the dialog gains focus.
 * @param {Function} [options.blurCallback] - A callback to run when the dialog loses focus.
 * @returns {jQuery} The jQuery object representing the created dialog.
 *
 * @see {@link http://docs.jquery.com/UI/API/1.8/Dialog} for a list of all jQuery UI Dialog options.
 * If you previously applied a class to your dialog after creating it with alert(),
 * dialogClass may be particularly useful.
 */
window.dialog = function(options) {
  // Override for smartphones. Preserve default behavior and create a modal dialog.
  options = options || {};

  // Build an identifier for this dialog
  var id = 'dialog-' + (options.modal ? 'modal' : (options.id ? options.id : 'anon-' + window.DIALOG_ID++));
  var jqID = '#' + id;
  var html = '';

  // Convert text to HTML if necessary
  if(options.text) {
    html = window.convertTextToTableMagic(options.text);
  } else if(options.html) {
    html = options.html;
  } else {
    log.error('window.dialog: warning: no text in dialog');
    html = window.convertTextToTableMagic('');
  }

  // Modal dialogs should not be draggable
  if(options.modal) {
    options.dialogClass = (options.dialogClass ? options.dialogClass + ' ' : '') + 'ui-dialog-modal';
    options.draggable = false;
  }

  // Close out existing dialogs.
  if(window.DIALOGS[id]) {
    try {
      var selector = $(window.DIALOGS[id]);
      selector.dialog('close');
      selector.remove();
    } catch (e) {
      log.error('window.dialog: Tried to close nonexistent dialog ' + id);
    }
  }

  // there seems to be a bug where width/height are set to a fixed value after moving a dialog
  function sizeFix() {
    if(dialog.data('collapsed')) return;

    var options = dialog.dialog('option');
    dialog.dialog('option', 'height', options.height);
    dialog.dialog('option', 'width', options.width);
  }

  // Create the window, appending a div to the body
  $('body').append('<div id="' + id + '"></div>');
  var dialog = $(jqID).dialog($.extend(true, {
    autoOpen: false,
    modal: false,
    draggable: true,
    closeText: '',
    title: '',
    buttons: {
      'OK': function() {
        $(this).dialog('close');
      }
    },
    open: function() {
      var titlebar = $(this).closest('.ui-dialog').find('.ui-dialog-titlebar');
      titlebar.find('.ui-dialog-title')
        .addClass('ui-dialog-title-active')
        .addClass('text-overflow-ellipsis');
      var close = titlebar.find('.ui-dialog-titlebar-close');

      // Title should not show up on mouseover
      close.removeAttr('title').addClass('ui-dialog-titlebar-button');

      // re-center dialog on title dblclick
      // jQuery-UI takes care about initial dialog position, but if content's height grows,
      // then dialog's bottom may go beyond screen (e.g. 'Auto draw' with a bunch of bookmarks in folder).
      // So this is just a nasty workaround for such issue.
      // todo: watch height changes and adapt automatically
      titlebar.dblclick(sizeFix);

      if(!$(this).dialog('option', 'modal')) {
        // Start out with a cloned version of the close button
        var collapse = close.clone();

        // Change it into a collapse button and set the click handler
        collapse.addClass('ui-dialog-titlebar-button-collapse ui-dialog-titlebar-button-collapse-expanded');
        collapse.click($.proxy(function() {
          var collapsed = ($(this).data('collapsed') === true);

          // Toggle collapsed state
          $(this).data('collapsed', !collapsed);

          // Run callbacks if we have them
          if($(this).data('collapseExpandCallback')) {
            $.proxy($(this).data('collapseExpandCallback'), this)(!collapsed);
          } else {
            if(!collapsed && $(this).data('collapseCallback')) {
              $.proxy($(this).data('collapseCallback'), this)();
            } else if (collapsed && $(this).data('expandCallback')) {
              $.proxy($(this).data('expandCallback'), this)();
            }
          }

          // Find the button pane and content dialog in this ui-dialog, and add or remove the 'hidden' class.
          var dialog   = $(this).closest('.ui-dialog');
          var content = dialog.find('.ui-dialog-content');
          var buttonpane = dialog.find('.ui-dialog-buttonpane');
          var button   = dialog.find('.ui-dialog-titlebar-button-collapse');

          // Slide toggle
          $(this).css('height', '');
          $(content).slideToggle({
            duration: window.DIALOG_SLIDE_DURATION,
            complete: function () {
              $(buttonpane).slideToggle({
                duration: window.DIALOG_SLIDE_DURATION,
                complete: sizeFix
              });
            }
          });

          if(collapsed) {
            $(button).removeClass('ui-dialog-titlebar-button-collapse-collapsed');
            $(button).addClass('ui-dialog-titlebar-button-collapse-expanded');
          } else {
            $(button).removeClass('ui-dialog-titlebar-button-collapse-expanded');
            $(button).addClass('ui-dialog-titlebar-button-collapse-collapsed');
          }
        }, this));

        // Put it into the titlebar
        titlebar.prepend(collapse);
        close.addClass('ui-dialog-titlebar-button-close');
      }

      window.DIALOGS[$(this).data('id')] = this;
      window.DIALOG_COUNT++;

      log.log('window.dialog: ' + $(this).data('id') + ' (' + $(this).dialog('option', 'title') + ') opened. ' + window.DIALOG_COUNT + ' remain.');
    },
    close: function() {
      // Run the close callback if we have one
      if($(this).data('closeCallback')) {
        $.proxy($(this).data('closeCallback'), this)();
      }

      // Make sure that we don't keep a dead dialog in focus
      if(window.DIALOG_FOCUS && $(window.DIALOG_FOCUS).data('id') === $(this).data('id')) {
        window.DIALOG_FOCUS = null;
      }

      // Finalize
      delete window.DIALOGS[$(this).data('id')];

      window.DIALOG_COUNT--;
      log.log('window.dialog: ' + $(this).data('id') + ' (' + $(this).dialog('option', 'title') + ') closed. ' + window.DIALOG_COUNT + ' remain.');

      // remove from DOM and destroy
      $(this).dialog('destroy').remove();
    },
    focus: function() {
      if($(this).data('focusCallback')) {
        $.proxy($(this).data('focusCallback'), this)();
      }

      // Blur the window currently in focus unless we're gaining focus
      if(window.DIALOG_FOCUS && $(window.DIALOG_FOCUS).data('id') !== $(this).data('id')) {
        $.proxy(function(event, ui) {
          if($(this).data('blurCallback')) {
            $.proxy($(this).data('blurCallback'), this)();
          }

          $(this).closest('.ui-dialog').find('.ui-dialog-title').removeClass('ui-dialog-title-active').addClass('ui-dialog-title-inactive');
        }, window.DIALOG_FOCUS)();
      }

      // This dialog is now in focus
      window.DIALOG_FOCUS = this;
      $(this).closest('.ui-dialog').find('.ui-dialog-title').removeClass('ui-dialog-title-inactive').addClass('ui-dialog-title-active');
    }
  }, options));

  dialog.on('dialogdragstop dialogresizestop', sizeFix);

  // Set HTML and IDs
  dialog.html(html);
  dialog.data('id', id);
  dialog.data('jqID', jqID);

  // Set callbacks
  dialog.data('closeCallback', options.closeCallback);
  dialog.data('collapseCallback', options.collapseCallback);
  dialog.data('expandCallback', options.expandCallback);
  dialog.data('collapseExpandCallback', options.collapseExpandCallback);
  dialog.data('focusCallback', options.focusCallback);
  dialog.data('blurCallback', options.blurCallback);

  if(options.modal) {
    // ui-modal includes overrides for modal dialogs
    dialog.parent().addClass('ui-modal');
  } else {
    // Enable snapping
    dialog.dialog().parents('.ui-dialog').draggable('option', 'snap', true);
  }

  // Run it
  dialog.dialog('open');

  return dialog;
}

/**
 * Creates an alert dialog with default settings. This function is a simplified wrapper around `window.dialog`.
 * It provides a quick way to create basic alert dialogs with optional HTML content and a close callback.
 *
 * @function alert
 * @param {string} text - The text or HTML content to display in the alert dialog.
 * @param {boolean} [isHTML=false] - Specifies whether the `text` parameter should be treated as HTML.
 *                                   If `true`, the `text` will be inserted as HTML, otherwise as plain text.
 * @param {Function} [closeCallback] - A callback function to be executed when the alert dialog is closed.
 *
 * @returns {jQuery} The jQuery object representing the created alert dialog.
 */
window.alert = function(text, isHTML, closeCallback) {
  var obj = {closeCallback: closeCallback};
  if(isHTML) {
    obj.html = text;
  } else {
    obj.text = text;
  }

  return dialog(obj);
}

window.setupDialogs = function() {
  window.DIALOG_ID = 0;
  window.DIALOGS   = {}
  window.DIALOG_COUNT = 0;
  window.DIALOG_FOCUS = null;
}