"use strict";

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

/**
 * Stores references to the elements (from the given HTML page) which can be translated. Translation
 * of the application content is achieved by calling translate() method on instances of this class.
 *
 * @author smrceant (Antonin Smrcek)
 *
 * @param       {jQuery}    contentPage                     HTML page, <div> container etc. where are elements which can be translated
 * @param                   [additionalIdentificators]      extra identificators (and their callbacks) which are unique,
 *                                                          i.e. they appear only in some part of the user interface and
 *                                                          it would be wasteful to search for them in all cases
 * @param       {Function}  [afterConstructorCallback]      function executed at the end of the constructor, used for initializing special cases, e.g. in Info Dialogs,
 *                                                          it is used for initializing structure "titles" holding title of article in different languages.
 *                                                          Generally, this function is not associated to any particular element (identificator), unlike callbacks
 *                                                          of standard and additional identificators, which always work on some specific identificator and its element.
 * @param       {Function}  [additionalTranslationCallback] function executed after translation callbacks of ALL elements are executed, e.g. used in Info Dialogs for
 *                                                          changing Dialog title; again, not associated with specific element.
 * @constructor
 */
var ContentObject = function (contentPage, additionalIdentificators, afterConstructorCallback, additionalTranslationCallback)
{
  this.currentContentLanguage = null;

  /**
   * Function executed after translation callbacks of ALL elements are executed, e.g. used in Info Dialogs for
   * changing Dialog title; again, not associated with specific element.
   *
   * @type {Function}
   */
  this.additionalTranslationCallback = additionalTranslationCallback;

  /**
   * Function executed at the end of the constructor, used for initializing special cases, e.g. in Info Dialogs,
   * it is used for initializing structure "titles" holding title of article in different languages.
   * Generally, this function is not associated to any particular element (identificator), unlike callbacks
   * of standard and additional identificators, which always work on some specific identificator and its element.
   *
   * @type {Function}
   */
  this.afterConstructionCallback = afterConstructorCallback;

  /**
   * HTML page, <div> container etc. where are elements which can be translated.
   *
   * @type {jQuery}
   */
  this.$contentPage = null;

  /**
   * Key-Value pairs, where keys are strings from ContentObject.StandardIdentificators._enumNames (e.g. "langcaption"),
   * and values are list of elements from the HTML page which contain the key as an attribute (e.g. <div class="someCssClass" langcaption="..."></div>).
   */
  this.$standardContentElems = {};

  /**
   * Unique identificators and their callbacks which define how to translate associated HTML elements.
   */
  this.additionalIdentificators      = null;

  /**
   * Same as this.$standardContentElems.
   */
  this.$additionalContentElems       = null;

  /**
   * List of strings used as keys in this.$additionalContentElems.
   * @type {string[]}
   */
  this.additionalIdentificatorsNames = null;

  this.additionalIdentificators = additionalIdentificators;

  // content page was specified, so initialize right away
  if (Util.isInitialized (contentPage))
  {
    this.init (contentPage);
  }
  // else: deferred initialization which will be launched manually when the content page is known
};

/**
 * Processes the content page, i.e. searches for the identificators (= searches for the HTML elements with these attributes)
 * and applies callbacks. Important: we should refrain from modifying the DOM after calling this method. If we add some element
 * to the DOM after calling init(), the content object won't know about this new element.
 *
 * @param {jQuery} contentPage    HTML container where we will search for the identificators
 */
ContentObject.prototype.init = function (contentPage)
{
  this.$contentPage = contentPage;
	if (! this.$contentPage.is('#onscreenGui')) {
		this.$contentPage.addClass('window-full');
	}

  for (var i = 0; i < ContentObject.StandardIdentificators._enumNames.length; i++)
  {
    // search content page for standard identificators

    // (put brackets around, since all our identificators are attributes)
    this.$standardContentElems[ ContentObject.StandardIdentificators._enumNames[i] ] = contentPage.find ("[" + ContentObject.StandardIdentificators._enumNames[i] + "]");
  }

  /**
   * List of strings used as keys in this.$additionalContentElems.
   * @type {string[]}
   */
  this.additionalIdentificatorsNames = null;

  // search content page for additional identificators (if defined)
  if (Util.isInitialized (this.additionalIdentificators))
  {
    this.$additionalContentElems  = {};

    this.additionalIdentificatorsNames = Object.keys (this.additionalIdentificators);
    for (i = 0; i < this.additionalIdentificatorsNames.length; i++)
    {
      this.$additionalContentElems[ this.additionalIdentificatorsNames[i] ] = contentPage.find ("[" + this.additionalIdentificatorsNames[i] + "]");
    }
  }

  // apply modifiers (if they are specified) on each of the identificator (both standard and additional)
  this.applyCallback("modifier");

  if (Util.isInitialized (this.afterConstructionCallback))
  {
    this.afterConstructionCallback (this);
  }
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// STANDARD IDENTIFICATORS
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/**
 * These identificators are present in every application text (content) page/part of user interface, so they are called
 * standard. The keys are identificator names, values are callbacks.
 * These identificators (their names) occur in the application as attributes (usually as attributes of <div>,
 * <span> or <button> elements). Callbacks are function which define how to translate the text of the element where
 * the identificator was found - these functions are different from each other, so they must be defined individually
 * for each identificator.
 *
 * @readonly
 * @enum {function}
 */
ContentObject.StandardIdentificators =
{
  /**
   *
   * @param {jQuery} contentElement   HTML element with attribute "langcaption"
   */
  langcaption:
  {
    translation: function (contentElement, contentPage)
    {
      //contentElement.text (ContentLibrary.getContentString (contentElement.attr("langcaption")) );
      contentElement.html (ContentLibrary.getContentString (contentElement.attr("langcaption")) );
    }
  },

  /**
   *
   * @param {jQuery} contentElement   HTML element with attribute "title"
   */
  langcaption_title:
  {
    /**
     * Translate the title.
     *
     * @param {jQuery} contentElement   HTML element with the attribute "langcaption_title"
     * @param {jQuery} contentPage
     */
    translation: function (contentElement, contentPage)
    {
      contentElement.tooltipster ("content", ContentLibrary.getContentString (contentElement.attr("langcaption_title")) );
    },

    /**
     * Init cool tooltips on each element which has attribute "langcaption_caption" (e.g. case of close button with image of cross)
     *
     * @param {jQuery} contentElement   HTML element with the attribute "langcaption_title"
     * @param {jQuery} contentPage
     */
    modifier: function (contentElement, contentPage)
    {
      // add tooltip class to each such element (so we have cool looking tooltips)
      contentElement.addClass ("tooltip");

      // initializes tooltipster jQuery plugin on element for cool looking tooltips.
      contentElement.tooltipster(
          {
            theme: "tooltipster-light",
            hideOnClick: true
          });
    }
  },

  /**
   * Show all elements for current language (and hide all elements for other languages).
   *
   * Elements with attribute "langtype" are <div> (or <span>) container with whole text, images and stuff.
   * They are used for presenting information which cannot be easily stored just as a string, e.g. article about
   * some building. What we do is that we make <div> container for each language with text, images and stuff - so we
   * have e.g. two divs <div langtype="EN">blabla stuff in English</div> and <div langtype='CZ">blabla veci v cestine</div>,
   * and then show container for current (active) language, and hide containers for inactive languages (so only one
   * container is shown).
   *
   * @param {jQuery} contentElement   HTML element with attribute "langtype"
   */
  langtype:
  {
    translation: function (contentElement, contentPage)
    {
      var langOfElement = contentElement.attr("langtype");

      if (Preferences.Languages[langOfElement] === Preferences.Languages.getCurrentLanguage())
      {
        contentElement.show();
      }
      else
      {
        contentElement.hide();
      }
    }
  },

  /**
   * Used for specifying title of the window dialogs.
   */
  dialogtitle:
  {
    translation: function (contentElement, contentPage)
    {
      // little clumsy, but whatever - we don't have access to the dialog object (i.e. dialog <div> container),
      // but we have access to the content page, which is dialog wrapper <div>, so we can find the dialog container
      // inside of it (e.g. by searching for windowDialog CSS class)
      contentPage.find(".windowDialog").dialog("option", "title", ContentLibrary.getContentString (contentElement.attr("dialogtitle")));
    }
  }
};

/**
 * Names of the standard identificators as list of strings.
 *
 * @type {String[]}
 */
ContentObject.StandardIdentificators._enumNames = Object.keys (ContentObject.StandardIdentificators); // we don't call Util.getEnumKeys(), since this enum contains functions (which are filtered in getEnumKeys)

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// TRANSLATION
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/**
 * Translates one text content element.
 *
 * @param {string}    callbackType              "modifier" or "translation"
 * @param {Object}    identificatorsDefinition  object with key-value pairs, where key = identificator name, and value = callback which defines how to translate the element
 * @param {jQuery[]}  identificatorsCollection  list of elements (each element contains identificator name in HTML, e.g. if identificator name = "langcaption", then there will be elements such as <div langcaption="...">...</div>
 * @param {string}    identificatorName         name of the identifcator, e.g. "langcaption", "title"
 * @private
 */
ContentObject.prototype._applyCallback = function (callbackType, identificatorsDefinition, identificatorsCollection, identificatorName)
{
  // get elements, e.g. all <title> elements
  var elements = identificatorsCollection[identificatorName];

  // for each element, call its callback
  for (var i = 0; i < elements.length; i++)
  {
    // we have to look into the definition of identificators (= e.g. ContentObject.StandardIdentificators) for callback which is assigned to current identificator,
    // and call it with current element
    if (Util.isInitialized (identificatorsDefinition[identificatorName][callbackType]))
    {
      identificatorsDefinition[identificatorName][callbackType]($(elements[i]), this.$contentPage);
    }
  }
};

/**
 * Applies specified type of callback in elements registered in this object.
 */
ContentObject.prototype.applyCallback = function (callbackType)
{
  // (note: do not call applyCallback("translation"), there is a function translate() for that)

  // translates content associated with standard identificators (e.g. langcaption, title...)
  for (var i = 0; i < ContentObject.StandardIdentificators._enumNames.length; i++)
  {
    this._applyCallback (callbackType, ContentObject.StandardIdentificators, this.$standardContentElems, ContentObject.StandardIdentificators._enumNames[i]);
  }

  // translates additional content (e.g. parent_langcaption for main menu)
  if (Util.isInitialized (this.additionalIdentificatorsNames))
  {
    for (i = 0; i < this.additionalIdentificatorsNames.length; i++)
    {
      this._applyCallback (callbackType, this.additionalIdentificators, this.$additionalContentElems, this.additionalIdentificatorsNames[i]);
    }
  }
};

/**
 * Translates all text content elements registered in this object.
 */
ContentObject.prototype.translate = function()
{
  // the content is already in the current application language - no need to translate it
  if (this.currentContentLanguage === Preferences.Languages.getCurrentLanguage())
  {
    return;
  }

  this.applyCallback("translation");

  if (Util.isInitialized(this.additionalTranslationCallback))
  {
    this.additionalTranslationCallback (this, this);
  }

  // set language of the translated content
  this.currentContentLanguage = Preferences.Languages.getCurrentLanguage();
};
