"use strict";

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/**
 * Represents general window dialog, used for displaying various kind of information (e.g. information about objects).
 * The window is realized as a jQuery Dialog widget, content is loaded dynamically.
 *
 * When the contentObject is not supplied, the initialization is deferred and must be invoked manually later by calling
 * init() with contentObject as parameter. This happens e.g. when the content object callbacks need to work with the
 * instance of this class - at the time of creating the instance, we don't have access to the instance pointer, so
 * we have to create the instance first and then call init.
 *
 * @author smrceant (Antonin Smrcek)
 *
 * @param {string}        id                                  name of the id attribute which will be on the dialog's <div> container
 * @param {string}        title                               content string identificator which will be used as the dialog title (title can be specified either this way or inside the contentPage as <div dialogtitle="...">)
 * @param {number}        dialogWidthPercent                  width of the dialog in percentage of the window
 * @param {Object}        buttonSettings                      which buttons shall be created (contains keys: CONTINUE_BUTTON and LANGSWITCH_BUTTON)
 * @param {string}        cssClasses                          list of CSS classes delimetered by space (e.g. "first second") applied to the dialog's container
 * @param {boolean}       openAfterInit                       TRUE if dialog shall be opened when its initialization is finished
 * @param {*}             contentCreationAdditionalCallback   function which will be executed in the init()
 *                                                            (used e.g. for initializing elements via JavaScript)
 * @param {string|jQuery} contentPage                         HTML filename with content of the window dialog or jQuery object with the content (i.e. some container)
 * @param {ContentObject} [contentObject]                     information about how to process the content (from contentPage file, which usually has some kind of special structure)
 * @constructor
 */
var WindowDialog = function (id, title, dialogWidthPercent, buttonSettings, cssClasses, openAfterInit, contentCreationAdditionalCallback, contentPage, contentObject)
{
  /**
   * Name of the id attribute which will be on the dialog's <div> container.
   *
   * @type {string}
   */
  this.id = id;

  /**
   * Width of the dialog in percentage of the (browser) window.
   *
   * @type {number}
   */
  this.dialogWidthPercent = dialogWidthPercent;

  /**
   * Which buttons shall be created (contains keys: CONTINUE_BUTTON and LANGSWITCH_BUTTON).
   *
   * @type {Object}
   */
  this.buttonSettings = buttonSettings;

  /**
   * List of CSS classes delimetered by space (e.g. "first second") applied to the dialog's container.
   *
   * @type {string}
   */
  this.cssClasses = cssClasses;

  /**
   * TRUE if dialog shall be opened when its initialization is finished.
   *
   * @type {boolean}
   */
  this.openAfterInit = openAfterInit;

  /**
   * Function which will be executed in the init().
   * Used e.g. for initializing elements via JavaScript.
   * @type {*}
   */
  this.contentCreationAdditionalCallback = contentCreationAdditionalCallback;

  /**
   * HTML filename with content of the window dialog.
   *
   * @type {string}
   */
  this.contentPage = contentPage;

  /**
   * Information about how to process the content.
   *
   * @type {ContentObject}
   */
  this.contentObject = contentObject;


  /**
   * <div> container representing entire jQuery UI Dialog widget, used for displaying the object info.
   *
   * @type {jQuery}
   */
  this.$dialogWrapper = null;

  /**
   * Container where the jQuery UI Dialog widget writes title, i.e. this element is used for displaying window title.
   * Probably should not be used for changing dialog title - use rather method of the dialog widget.
   *
   * @type {jQuery}
   */
  this.$dialogTitleElement = null;

  // prepend dialog title (with the specified content string identificator) to the contentPage object, if specified
  if (Util.isInitialized (title))
  {
    contentPage.prepend('<div dialogtitle="'+title+'"></div>');
  }

  // if content object was supplied, we can init the dialog right away
  if (Util.isInitialized (contentObject))
  {
    this.init (contentObject);
  }
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/**
 * Currently opened window dialog.
 *
 * @type {WindowDialog}
 */
WindowDialog.currentlyOpenedDialog = null;

/**
 * Hides currently opened dialog, if any.
 */
WindowDialog.hideCurrentlyOpenedDialog = function()
{
  if (WindowDialog.currentlyOpenedDialog)
  {
    WindowDialog.currentlyOpenedDialog.close();
  }
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// INITIALIZATION
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/**
 * Initializes jQuery UI Dialog widget for the window displaying and processes window content
 * using content object callbacks.
 *
 * @param {ContentObject} contentObject
 */
WindowDialog.prototype.init = function (contentObject)
{
  var _this = this;

  this.contentObject = contentObject;

  // we need to update perfect scrollbar when the translation is performed, and we will use additional translation callback mechanism for that
  var additionalTranslationCallback = this.contentObject.additionalTranslationCallback; // save currently defined callback from the content object

  // now we redefine the callback so we can update the scrollbar along too
  this.contentObject.additionalTranslationCallback = function()
  {
    // perform saved defined callback and update that damn scrollbar

    if (Util.isInitialized(additionalTranslationCallback))
    {
      additionalTranslationCallback(_this.contentObject); // do not forget to pass reference to the contentObject, it is important argument for the additional translation callback
    }
  };

  /**
   * Resize callback for the dialog widget, which is triggered on the window resize (not on
   * dialog resize - resizing the dialog is not allowed). This makes the dialog responsive, i.e. it correctly changes
   * its dimensions when the window size changes.
   *
   * @type {function(this:WindowDialog)}
   * @private
   */
  var _resizeCallback = function ()
  {
		this.$dialog.removeAttr('style');
  }.bind(this);

  this.$dialog = $("<div id='"+this.id+"' class='windowDialog "+(Util.isInitialized (this.cssClasses) ? this.cssClasses : "")+"'></div>");

  var initDialog = function()
  {
    this.$dialog.dialog({
      closeOnEscape: true,
      autoOpen: false, // important! must be false, otherwise it would open right away, before the HTML is fully loaded into the dialog (=> problem, since we need to find correct <divs> within the HTML)
      draggable: false,
      resizable: false,
      modal: false,
      buttons: [],

      close: function()
      {
        // our special resize callback for dialog is not needed when the dialog is closed
        window.removeEventListener("optimizedResize", _resizeCallback);

        appMain.unfreezeApplication();
      },

      open: function()
      {
        // important: in order for our dialog to be responsive, we need to register our special resize callback upon opening the dialog
        window.addEventListener("optimizedResize", _resizeCallback);

        appMain.freezeApplication();

        _this.contentObject.translate();
      }
    });
  }.bind (this);

  /**
   * Called when the dialog content is ready in the DOM (i.e. is loaded when the content is externally loaded from the file).
   *
   * @param {boolean} openDialog    TRUE if dialog should be opened right away
   */
  var dialogContentReadyCallback = function (openDialog)
  {
    initDialog();

    //////////////////////////////////////////////////////////////////////////////
    // PREPERATION OF: CONTENT OBJECT INITIALIZATION, PERFECT SCROLLBAR
    //////////////////////////////////////////////////////////////////////////////

    // now we just prepare the code in the function (in the form of asset job), but
    // we DO NOT START the job (i.e. execute the code) yet, because additional callback for content creation may
    // load some files and change the DOM, so we need to wait for it to finish and THEN execute

    var initJob = assetLoader.makeDummyJob("window dialog " + _this.id + " init job", false, function()
    {
      ///////////////////////////////////////////
      // BUTTON CREATION
      ///////////////////////////////////////////

      // init dialog wrapper variable so we can work with it (but do not forget to update it when we make some changes to the DOM!)
      _this.$dialogWrapper = _this.$dialog.parent();
      _this.$dialogWrapper.attr("id", _this.id + "Wrapper");
			_this.$dialogWrapper.removeAttr('style');
			if (Util.isInitialized (_this.cssClasses)) {
				var classes = _this.cssClasses.split(' ');
				for(var i = 0; i < classes.length; i ++) {
					_this.$dialogWrapper.addClass(classes[i] + '-wrapper');
				}
			}

      // replace the default close button with our custom close button
      Gui.replaceElementWithCloseCrossButton(_this.$dialogWrapper.find(".ui-dialog-titlebar button"), function ()
      {
        _this.close();
      });

      //////////////////////////////////////////////////////////////////////////////
      // CONTENT OBJECT INITIALIZATION, PERFECT SCROLLBAR
      //////////////////////////////////////////////////////////////////////////////

      // now, when the DOM manipulation is completed, we can initialize the content object; we shall not modify DOM any further!

      _this.$dialogWrapper = _this.$dialog.parent(); // get the most recent version of the dialog wrapper DOM element
      _this.contentObject.init (_this.$dialogWrapper);

      if (gui.mainMenu) {
          gui.mainMenu.initTransformLinksToTabs (_this.$dialog, function() {
            _this.close();
          });
      }

      _this.$dialogTitleElement = _this.$dialogWrapper.find(".ui-dialog-title");
      _this.$dialogTitleElement.addClass("unselectable");

      // open the dialog when the HTML is fully loaded
      if (openDialog)
      {
        _this.openDialog();
      }

    });

    //////////////////////////////////////////////////////////////////////////////
    // ADDITIONAL CALLBACK FOR CONTENT CREATION
    //////////////////////////////////////////////////////////////////////////////

    if (Util.isInitialized (_this.contentCreationAdditionalCallback))
    {
      // pass reference to the job which contains prepared init code
      _this.contentCreationAdditionalCallback (_this, initJob); // arguments: function (dialog, dialogInitJob)
    }

    // now we can start the earlier prepared code; it will automatically wait for the additional content callback
    initJob.startJob();
  };

  // the content page is in fact an URL to a file
  if (typeof this.contentPage === "string")
  {
    this.$dialog.load (this.contentPage, function(){
      dialogContentReadyCallback (_this.openAfterInit);
    });
  }
  // the content page is an (jQuery) element, just insert it into the skeleton of the dialog
  else
  {
    this.$dialog.append (this.contentPage);

    dialogContentReadyCallback (_this.openAfterInit); // append() is synchronous, so we can call it right after it and be sure everything is ready for the callback execution
  }
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// WINDOW OPENING/CLOSING
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/**
 * Opens the dialog.
 */
WindowDialog.prototype.openDialog = function()
{
  if (!this.$dialog.dialog("isOpen"))
  {
    this.$dialog.dialog("open");
  }

  gui.showModalBehind (true);

	this.$dialogWrapper.addClass('window-open');

  WindowDialog.currentlyOpenedDialog = this;
};

/**
 * Closes the dialog.
 */
WindowDialog.prototype.close = function()
{
  if (this.$dialog.dialog("isOpen"))
  {
    this.$dialog.dialog("close");
  }

  gui.showModalBehind (false);

	this.$dialogWrapper.removeClass('window-open');

  WindowDialog.currentlyOpenedDialog = null;
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// GETTERS
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/**
 *
 * @returns {jQuery}
 */
WindowDialog.prototype.getDialogWrapper = function()
{
  return this.$dialogWrapper;
};

/**
 *
 * @returns {jQuery}
 */
WindowDialog.prototype.getDialog = function()
{
  return this.$dialog;
};
