/**
 * @fileoverview Pomocný nástroj Hint pro knihovnu jQuery UI.
 *
 * Tento nástroj aplikujeme na textové pole, aby zobrazoval kontextovou
 * nápovědu. Text nápovědy zobrazujeme přímo do daného elementu, ale jen za
 * předpokladu, že tento element není zaměřený a je prázdný.
 *
 * Pro studium tvorby vlastních zásuvných modulů můžete použít oficiální
 * dokumentaci na adrese http://jqueryui.com/demos/widget/ a zde uvedené
 * související zdroje.
 *
 ********************
 * Možnosti nastavení
 ********************
 * Možnost nastavení text
 * ----------------------
 * Definuje text nápovědy. Hodnotou false říkáme, že chceme použít atribut
 * title daného elementu.
 * Typ hodnoty: Textový řetezec nebo hodnota false.
 * Výchozí hodnota: false.
 *
 ********
 * Metody
 ********
 * Metoda destroy
 * --------------
 * Kompletně odstraní funkčnost nástroje Hint.
 * Volání: .hint('destroy')
 *
 * Metoda option
 * --------------
 * Jestliže nezadáme hodnotu, vrátí aktuální hodnotu příslušné možnosti
 * nastavení. V opačném případě přidělí této možnosti uvedenou hodnotu.
 * Volání: .hint('option', nazevMoznostiNastaveni, [hodnota])
 *
 * Metoda option
 * --------------
 * Nastaví více možností nastavení současně. Této metodě předáváme objekt
 * s názvy možností nastavení a jejich hodnotami.
 * Volání: .hint('option', moznostiNastaveni)
 *
 * Metoda text
 * -----------
 * Nastavuje nebo zjišťuje text nápovědy (hodnotu možnosti nastavení text).
 * Volání: .hint('text', [textNápovědy])
 *
 **********
 * Události
 **********
 * Událost create
 * --------------
 * Tato událost se spouští při inicializaci nástroje Hint.
 * Typ události: hintcreate
 *
 * @author Ondřej Baše
 */

/**
 * Anonymní jmenný prostor pro nástroj Hint. Zabraňuje kolizím aliasu $
 * knihovny jQuery s ostatními javascriptovými knihovnami.
 * @param Object $ Objekt jQuery.
 * @namespace
 */
(function($) {

/**
 * Pomocný nástroj Hint je součástí jmenného prostoru myutils.
 */
$.widget('myutils.hint', {
  /**
   * Možnosti nastavení nástroje Hint.
   * @type Object
   */
  options: {
    text: false
  },

  /**
   * Indikuje, jestli se zobrazuje text nápovědy (soukromá vlastnost).
   * @type Boolean
   * @default false
   */
  _hintTextIsShown: false,

  /**
   * Přípona třídy elementu se zobrazenou nápovědou.
   * @constant
   * @type String
   * @default 'hint-is-shown'
   */
  _HINT_TEXT_IS_SHOWN_CLASS_SUFFIX: '-hint-is-shown',

  /**
   * Původní hodnota atributu autocomplete daného elementu.
   * @type string
   */
  _originalAutocomplete: null,

  /**
   * Inicializuje novou instanci nástroje Hint (soukromá metoda).
   */
  _create: function() {
    // Zobrazujeme text nápovědy.
    this._showHintText();

	// Metoda proxy() knihovny jQuery nastavuje kontext funkce. Tato metoda
	// vrací funkci s novým kontextem. Popis najdete na adrese
	// http://api.jquery.com/jQuery.proxy/.
	this._showHintTextCallback = $.proxy(this._showHintText, this);
	this._hideHintTextCallback = $.proxy(this._hideHintText, this);

    this.element
      // Přidělíme elementu třídu nástroje Hint.
      .addClass(this.widgetBaseClass)
      // Při zaměření elementu chceme skrýt text nápovědy.
      .focus(this._hideHintTextCallback)
	  // Při ztrátě zaměření elementu chceme zobrazit text nápovědy.
      .blur(this._showHintTextCallback);
  },

  /**
   * Zobrazí text nápovědy, ale jen za předpokladu, že jsme ho definovali
   * a daný element je prázdný nebo obsahuje už text nápovědy (soukromá
   * metoda).
   */
  _showHintText: function() {
    if (this.element.val() == '' || this._hintTextIsShown) {
      // Daný element nemá vlastní hodnotu nebo se zobrazuje nápověda, takže
	  // můžeme zobrazit nápovědu.

      if (!this._hintTextIsShown) {
        // Poznačíme si původní hodnotu atributu autocomplete, je-li nějaká.
        this._originalAutocomplete = this.element.attr('autocomplete');
      }

      if (this.options.text != false) {
        // Zobrazíme hodnotu možnosti nastavení text.
        this.element.val(this.options.text);
        this._hintTextIsShown = true;
      } else {
        // Pokud má daný element hodnotu atributu title, tak ji zobrazíme.
        var title = this.element.attr('title');
        if (title) {
          this.element.val(title);
          this._hintTextIsShown = true;
        } else {
          // Jinak nápovědu nezobrazíme.
          this._hintTextIsShown = false;
        }
      }
    } else {
      // Jinak nápovědu nezobrazíme.
	  this._hintTextIsShown = false;
    }

    if (this._hintTextIsShown) {
      // Pokud se zobrazuje nápověda, neměl by být nastavený atribut
      // autocomplete.
      this.element.attr('autocomplete', 'off');
      // Přidělíme třídu elementu se zobrazenou nápovědou.
      this.element.addClass(this.widgetBaseClass +
        this._HINT_TEXT_IS_SHOWN_CLASS_SUFFIX);
    }
  },

  /**
   * Metoda _showHintText() s kontextem instance nástroje Hint, a ne aktuálním
   * elementem (soukromá metoda).
   * @type Function
   */
  _showHintTextCallback: null,

  /**
   * Skryje text nápovědy, ale jen tehdy, když se zobrazuje (soukromá metoda).
   */
  _hideHintText: function() {
    if (this._hintTextIsShown) {
      // Nastavíme elementu prázdnou hodnotu.
      this.element.val('');

	  // Nastavíme danému elementu původní hodnotu atributu autocomplete.
      if (this._originalAutocomplete) {
        this.element.attr('autocomplete', this._originalAutocomplete);
      } else {
        this.element.removeAttr('autocomplete');
      }

      // Odstraníme elementu třídu pro zobrazenou nápovědu.
      this.element.removeClass(this.widgetBaseClass +
        this._HINT_TEXT_IS_SHOWN_CLASS_SUFFIX);

      this._hintTextIsShown = false;
    }
  },

  /**
   * Metoda _hideHintText() s kontextem instance nástroje Hint, a ne aktuálním
   * elementem (soukromá metoda).
   * @type Function
   */
  _showHintTextCallback: null,

  /**
   * Nastavuje dané možnosti nastavení hodnotu (soukromá metoda).
   * @param string key Název možnosti nastavení.
   * @param mixed value Hodnota možnosti nastavení.
   */
  _setOption: function(key, value) {
    // Použijeme standardní metodu knihovny jQuery UI.
    $.Widget.prototype._setOption.call(this, key, value);

	// Pokud upravujeme text, zajistíme okamžitou aktualizaci nápovědy.
    if (key == 'text') {
       this._showHintText();
    }
  },

  /**
   * Nastavuje nebo zjišťuje text nápovědy (hodnotu možnosti nastavení text).
   * @param mixed [value] Nastavovaná hodnota.
   */
  text: function(value) {
    if (value != undefined) {
      this._setOption('text', value);
    } else {
      return this.options.text;
    }
  },

  /**
   * Kompletně odstraní funkčnost nástroje Hint.
   */
  destroy: function() {
    this._hideHintText(this.widgetBaseClass);
    this.element
      .removeClass()
      .unbind('focus', this._hideHintTextCallback)
      .unbind('blur', this._showHintTextCallback);
  }
});

})(jQuery);