/**
 * Odešle ajaxový požadavek odpovědnému skriptu. Tato funkce jen simuluje,
 * jak by asi vypadalo odeslání požadavku skriptu na straně serveru, ale
 * vzhledem k tomu, že žádný takový skript nemáme, tak používáme skript
 * na straně klienta.
 * Ve skutečné aplikaci byste s největší pravděpodobností nechali tvorbu
 * takového skriptu, a případně i této funkce, na programátorech
 * (pokud jimi nejste sami).
 * @param {String} typ Typ ajaxového požadavku.
 * @param {Object} data Data ajaxového požadavku.
 * @param {function} odpovedPrisla Funkce, která se má zavolat po přijetí
 *   odpovědi.
 * @param {Object} $stavovyElement Objekt knihovny jQuery, jenž obsahuje
 *   element pro zobrazení stavu.
 * @param {bool} synchronne Pokud má hodnotu true, odešle se synchronní
 *   požadavek.
 */
function odesliAjaxovyPozadavek(typ, data, odpovedPrisla, $stavovyElement, synchronne) {
  /* Vzhledem k tomu, že asynchronní požadavky by u naší simulace způsobovaly
  problémy, vynutíme si vždy synchronní. */
  synchronne = true;

  /* Tento příkaz nepatří do odesílání skutečného ajaxového požadavku, ale je
  součástí naší simulace. */
  odesliAjaxovyPozadavek.pozadavek = {
    typ: typ,
    data: data
  }

  // Odesíláme ajaxový požadavek.
  $.ajax({
    url: 'js/zpracuj-ajax.js',
    dataType: 'script',
    async: synchronne ? false : true,

	/**
	 * Tato obsluhující funkce se volá před odesláním ajaxového požadavku.
	 * Vyprázdníme v ní stavový element a vložíme do něj indikátor průběhu
	 * zpracování ajaxového požadavku.
	 */
    beforeSend: function() {
      $stavovyElement
        .empty()
        .append('<span class="indikator-prubehu"></span>');
	},

	/**
	 * Tato obsluhující funkce se volá při úspěšném přijetí odpovědi na
	 * odeslaný ajaxový požadavek. Voláme v ní funkci odpovedPrisla()
	 * a předáváme jí danou odpověď.
	 */
    success: function() {
      odpovedPrisla(odesliAjaxovyPozadavek.odpoved);
    },

	/**
	 * Tato obsluhující funkce se volá, když dojde při zpracování ajaxového
	 * požadavku k chybě. Reagujeme tak, že zobrazíme chybovou zprávu.
	 */
    error: function() {
      $stavovyElement.append('<span class="ui-state-error">' +
	    'Při zpracování ajaxového požadavku došlo k chybě.</span>');
    },

	/**
	 * Tato obsluhující funkce se volá, jakmile ajaxový požadavek skončí,
	 * a to bez ohledu na to, zda úspěšně, nebo neúspěšně. Odstraníme
	 * v ní indikátor pruběhu zpracování ajaxového požadavku.
	 */
	complete: function() {
      $stavovyElement.children('.indikator-prubehu').remove();
	}
  });

  /* Pro skript jazyka PHP by tělo této funkce vypadalo kupříkladu přibližně
  takto:

  $.ajax({
    url: 'cesta-ke-skriptu/skript-pro-ajax.php',
    data: {
      typ: typ,
      data: data
    },
    async: synchronne ? false : true,
    beforeSend: function() {
      $stavovyElement
        .empty()
        .append('<span class="indikator-prubehu"></span>');
    },
    success: odpovedPrisla,
    error: function() {
      $stavovyElement.append('<span class="ui-state-error">' +
        'Při zpracování ajaxového požadavku došlo k chybě.</span>');
    },
    complete: function() {
      $stavovyElement.children('.indikator-prubehu').remove();
    }
  });
  */
}

/**
 * Přidá stavový element za aktuální formulářové pole.
 */
function pridejStavovyElement() {
  $('<div class="stav"></div>').insertAfter(this);
}

/**
 * Vyhledá stavový element pro dané formulářové pole.
 * @param {Object} $pole Objekt knihovny jQuery obsahující formulářové pole.
 * @returns {Object} Objekt knihovny jQuery obsahující stavový element.
 */
function hledejStavovyElement($pole) {
  return $pole.next('.stav');
}

/**
 * Načte popis školení a zobrazí jej do elementu s identifikátorem
 * popis-skoleni.
 */
function nactiPopisSkoleni() {
  var $pole = $(this);
  odesliAjaxovyPozadavek(
    'nactiSkoleni',
    {
      vybraneSkoleni: $pole.find(':selected').attr('value')
    },
    function(odpoved) {
      if (odpoved.popisSkoleni) {
        $('#popis-skoleni').text(odpoved.popisSkoleni);
      } else {
        $('#popis-skoleni').html('<span class="ui-state-error">' +
          odpoved.chybovaZprava + '</span>');
	  }
    },
    hledejStavovyElement($pole)
  );
}

/**
 * Ověří platnost hodnoty aktuálního formulářového pole. V případě, že je
 * hodnota neplatná, zobrazí chybovou zprávu.
 * @param {bool|Object} synchronne Pokud má hodnotu true, provede se validace
 *   synchronně. Pokud se spouští jako obsluhující funkce, a ne přímo, tak
 *   tento parametr obsahuje objekt události.
 */
function validujHodnotuPole(synchronne) {
  var $pole = $(this);
  odesliAjaxovyPozadavek(
    'validuj',
    {
      id: $pole.attr('id'),
	  hodnota: $pole.attr('value')
    },
    function(odpoved) {
      var $stavovyElement = hledejStavovyElement($pole);
      $stavovyElement.empty();
      if (!odpoved.hodnotaJePlatna) {
        $stavovyElement.append('<span class="ui-state-error">' +
          odpoved.chybovaZprava + '</span>');
      } else {
        $stavovyElement.append('<span class="validni"></span>');
      }
    },
    hledejStavovyElement($pole),
    synchronne == true ? true : false
  );
}

/**
 * Ověří platnost hodnot všech formulářových polí. Pokud se ve formuláři
 * nachází nějaká chyba, vrátí hodnotu false, jinak vrátí hodnotu true.
 * @returns {bool} True, pokud validace proběhla v pořádku; jinak false.
 */
function validujHodnotyVsechPoli() {
  /* Musíme provést požadavky synchronně, protože u asynchronních požadavků
  by se provedl příkaz return v této funkci ještě před vrácením všech
  odpovědí. */
  $(':input:visible:not(:submit)')
    .each(function() {
	  validujHodnotuPole.call(this, true);
	});

  if ($('#rezervace-skoleni .ui-state-error').length) {
    return false;
  } else {
    window.alert('Vše je v pořádku. Ve skutečné aplikaci by se nyní odeslal ' +
	  'formulář na server. Na straně serveru bychom opět provedli validaci. ' +
	  'Kdyby bylo vše v pořádku, uložili bychom novou rezervaci do databáze.');
    return true;
  }
}