/**
 * @fileOverview Kapitola 8 – skript příkladu Multimediální přehrávač.
 * V tomto skriptu se nachází komentáře ve formátu dokumentačních bloků
 * nástroje JsDoc Toolkit.
 * Oficiální stránky projektu JsDoc Toolkit jsou k dispozici na adrese
 * http://code.google.com/p/jsdoc-toolkit/.
 * @author Ondřej Baše
 */

/**
 * Element audio pro přehrávání zvukových prostředků.
 * @type {Object}
 */
var hudebniPrehravac = window.document.createElement('audio'),

  /**
   * Element video pro přehrávání video prostředků.
   * @type {Object}
   */
  videoPrehravac,

  /**
   * Obsahuje element audio nebo element video na základě právě přehrávaného
   * prostředku.
   * @type {Object}
   */
  multimedialniPrehravac,

  /**
   * Objekt knihovny jQuery obalující element přehrávače.
   * @type {Object}
   */
  $elementPrehravace,

  /**
   * Výchozí šířka elementu přehrávače podle šablony stylů.
   * @type {Number}
   */
  vychoziSirkaPrehravace,

  /**
   * Minimální šířka elementu přehrávače.
   * @constant
   */
  MINIMALNI_SIRKA_PREHRAVACE = 640,

  /**
   * Maximální šířka elementu přehrávače.
   * @constant
   */
  MAXIMALNI_SIRKA_PREHRAVACE = 1280,

  /**
   * Objekt s možnými typy prostředků.
   * @type {Object}
   */
  TYP_PROSTREDKU = {
    AUDIO: 1,
    VIDEO: 2
  },

  /**
   * Informace o prostředcích. Jako názvy vlastností slouží identifikátory
   * prostředků.
   * @type {Object}
   */
  prostredky = {
    1: {
      nazev: 'Rebirth Drum Test',
      autor: 'Ondřej Baše',
      typ: TYP_PROSTREDKU.AUDIO,
      zdroje: [{
          url: 'prostredky/ondrej-base-rebirth-drum-test.mp3',
          typ: 'audio/mpeg'
        }, {
          url: 'prostredky/ondrej-base-rebirth-drum-test.ogg',
          typ: 'audio/ogg'
        }
      ]
    },
    2: {
      nazev: 'Paprsek 2012',
      autor: 'Ondřej Baše',
      typ: TYP_PROSTREDKU.VIDEO,
      zdroje: [{
          url: 'prostredky/ondrej-base-paprsek-2012.mp4',
          typ: 'video/mp4'
        }, {
          url: 'prostredky/ondrej-base-paprsek-2012.ogv',
          typ: 'video/ogg'
        }
      ]
    }
  },

  /**
   * Předpona identifikátoru prostředku.
   * @constant
   */
  PREDPONA_IDENTIFIKATORU_PROSTREDKU = 'prostredek-',

  /**
   * Adresa URL k obrázku, který by se měl zobrazovat během přehrávání
   * zvukového souboru.
   * @type {String}
   */
  URL_OBRAZKU_PRI_PREHRAVANI_ZVUKU = 'obrazky/zvuk.png',

  /**
   * Objekt knihovny jQuery představující tlačítko pro přehrávání.
   * @type {Object}
   */
  $tlacitkoPrehrat,

  /**
   * Objekt knihovny jQuery reprezentující tlačítko pro pozastavení.
   * @type {Object}
   */
  $tlacitkoPozastavit,

  /**
   * Identifikátor výchozího prostředku.
   * @constant
   */
  IDENTIFIKATOR_VYCHOZIHO_PROSTREDKU = 1,

  /**
   * Objekt knihovny jQuery, jenž obsahuje element, do kterého budeme
   * zobrazovat aktuální čas přehrávaného prostředku.
   * @type {Object}
   */
  $elementProAktualniCas,

  /**
   * Objekt knihovny jQuery obsahující element, do nějž budeme zobrazovat
   * celkový čas přehrávaného prostředku.
   * @type {Object}
   */
  $elementProCelkovyCas,

  /**
   * Objekt knihovny jQuery představující tlačítko pro ztlumení přehrávače.
   * @type {Object}
   */
  $tlacitkoZtlumit,

  /**
   * Objekt knihovny jQuery, který reprezentuje tlačítko pro zesílení
   * přehrávače.
   * @type {Object}
   */
  $tlacitkoZesilit,

  /**
   * Objekt knihovny jQuery, který obsahuje element, jenž bude sloužit jako
   * indikátor průběhu přehrávání a načítání prostředku.
   * @type {Object}
   */
  $indikatorPrubehu,

  /**
   * Objekt knihovny jQuery, jenž obsahuje element ovládacího prvku pro
   * nastavení úrovně hlasitosti.
   * @type {Object}
   */
  $ovladaciPrvekHlasitosti,

  /**
   * Úroveň hlasitosti vyjádřená v procentech (od 0 do 100).
   * @type {Number}
   */
  hlasitost = 80,

  /**
   * Úroveň hlasitosti před ztlumením přehrávače.
   * @type {Number}
   */
  hlasitostPredZtlumenim;

$(inicializujSkript);

/**
 * Inicializuje skript. Tato funkce se volá, když webový prohlížeč načte model
 * DOM. Uvnitř ní především vyhledáváme elementy, svazujeme události
 * s elementy a obsluhujícími funkcemi, a také inicializujeme komponenty
 * knihovny jQuery UI.
 */
function inicializujSkript() {
  videoPrehravac = $('video.prehravac-zobrazovaci-cast')[0];
  var $audioVideo = $([hudebniPrehravac, videoPrehravac]);
  $elementPrehravace = $('.prehravac');
  vychoziSirkaPrehravace = $elementPrehravace.width();
  $tlacitkoPrehrat = $('.prehravac-tlacitko-prehrat');
  $tlacitkoPozastavit = $('.prehravac-tlacitko-pozastavit');
  $elementProAktualniCas = $('.prehravac-aktualni-cas');
  $elementProCelkovyCas = $('.prehravac-celkovy-cas');
  $tlacitkoZtlumit = $('.prehravac-tlacitko-ztlumit');
  $tlacitkoZesilit = $('.prehravac-tlacitko-zesilit');
  $indikatorPrubehu = $('.prehravac-indikator-prubehu');
  $ovladaciPrvekHlasitosti = $('.prehravac-ovladaci-prvek-hlasitosti');

  $('#seznam-motivu').themeswitcher({
    buttonPreText: 'Aktuální motiv vzhledu: ',
    width: 230,
    loadTheme: 'UI darkness'
  });

  $elementPrehravace.resizable({
    aspectRatio: true,
    handles: 'e',
    minWidth: MINIMALNI_SIRKA_PREHRAVACE,
    maxWidth: MAXIMALNI_SIRKA_PREHRAVACE
  });

  $tlacitkoPrehrat
    .button({
      icons: {
        primary: 'ui-icon-play'
      },
      text: false
    })
    .click(prehrajProstredek);

  $tlacitkoPozastavit
    .button({
      icons: {
        primary: 'ui-icon-pause'
      },
      text: false
    })
    .click(pozastavProstredek);

  $tlacitkoZtlumit
    .button({
      icons: {
        primary: 'ui-icon-volume-on'
      },
      text: false
    })
    .click(ztlumPrehravac);

  $tlacitkoZesilit
    .button({
      icons: {
        primary: 'ui-icon-volume-off'
      },
      text: false
    })
    .click(zesilPrehravac);

  $('.prehravac-seznam-prostredku li').click(vyberProstredek);
  $('.prehravac-seznam-prostredku li.' + PREDPONA_IDENTIFIKATORU_PROSTREDKU +
    IDENTIFIKATOR_VYCHOZIHO_PROSTREDKU).each(vyberProstredek);

  $audioVideo.bind('loadedmetadata', zpracujMetadataProstredku);
  $audioVideo.bind('canplay', povolTlacitkoPrehrat);
  $audioVideo.bind('progress', aktualizujIndikatorPrubehuNacitani);
  $audioVideo.bind('timeupdate', zobrazAktualniCas);

  $indikatorPrubehu
    .progressbar()
    .slider({
      range: 'min',
      slide: posunProstredek
    });
  $('.ui-slider-range').addClass('ui-corner-all');

  $ovladaciPrvekHlasitosti
    .slider({
      range: 'min',
      create: nastavHlasitost,
      slide: nastavHlasitost
    });
}

/**
 * Vybere prostředek tak, že zajistí vizuální odlišení jeho položky v seznamu
 * prostředků a potom zahájí načítání tohoto prostředku. Voláme ji v reakci na
 * událost klepnutí na položku prosředku a také při inicializaci skriptu.
 */
function vyberProstredek() {
  var $polozkaProstredku = $(this),
    idProstredku;

  $polozkaProstredku.addClass('ui-state-highlight')
    .siblings().removeClass('ui-state-highlight');

  idProstredku = urciIdProstredku($polozkaProstredku);
  nactiProstredek(idProstredku);
}

/**
 * Určí identifikátor prostředku z jeho položky.
 * @param {Object} $polozka Objekt knihovny jQuery obsahující položku
 * prostředku.
 * @returns {Number} Identifikátor prostředku.
 */
function urciIdProstredku($polozka) {
  var hodnotaAtributuClass = $polozka.attr('class'),
    vysledkyHledani = hodnotaAtributuClass.match(
      new RegExp(PREDPONA_IDENTIFIKATORU_PROSTREDKU + '([0-9]+)'));

  return parseInt(vysledkyHledani[1]);
}

/**
 * Zahájí inicializaci přehrávače podle typu prostředku a načte data
 * prostředku z příslušného zdroje.
 * @param {Number} Identifikátor prostředku.
 */
function nactiProstredek(idProstredku) {
  var prostredek = prostredky[idProstredku];

  inicializujPrehravac(prostredek.typ);

  var pocetZdroju = prostredek.zdroje.length;
  for (var poradiZdroje = 0; poradiZdroje < pocetZdroju; poradiZdroje++) {
    if (multimedialniPrehravac.canPlayType(
      prostredek.zdroje[poradiZdroje].typ)) {
      multimedialniPrehravac.src = prostredek.zdroje[poradiZdroje].url;
      multimedialniPrehravac.load();
    }
  }
}

/**
 * Inicializuje přehrávač na základě typu prostředku.
 * @param {Number} typProstredku Typ prostředku.
 */
function inicializujPrehravac(typProstredku) {
  $tlacitkoPrehrat.button('disable');

  uvedPrehravacDoVychozihoStavu();

  if (typProstredku == TYP_PROSTREDKU.AUDIO) {
    multimedialniPrehravac = hudebniPrehravac;
    videoPrehravac.poster = URL_OBRAZKU_PRI_PREHRAVANI_ZVUKU;
  } else {
    multimedialniPrehravac = videoPrehravac;
  }
}

/**
 * Vrátí přehrávač do výchozího stavu.
 */
function uvedPrehravacDoVychozihoStavu() {
  if (multimedialniPrehravac) {
    multimedialniPrehravac.pause();
    multimedialniPrehravac.src = '';
    videoPrehravac.poster = '';
    zobrazTlacitkoPrehrat();
    zobrazAktualniCas(0);
    zobrazCelkovyCas(0);
  }
}

/**
 * Zobrazí tlačítko pro přehrání prostředku.
 */
function zobrazTlacitkoPrehrat() {
  $tlacitkoPozastavit.hide();
  $tlacitkoPrehrat.show();
}

/**
 * Naformátuje čas pro zobrazení uživateli.
 * @param {Number} pocetSekund Počet sekund k převodu.
 */
function formatujCas(pocetSekund) {
  var datum = new Date(Math.ceil(pocetSekund) * 1000),
    hodiny = datum.getUTCHours(),
    minuty = datum.getUTCMinutes(),
    sekundy = datum.getUTCSeconds();

  return (hodiny == 0 ? '' : hodiny + ':') +
    (minuty < 10 ? '0' : '') + minuty + ':' +
    (sekundy < 10 ? '0' : '') + sekundy;
}

/**
 * Zobrazí aktuální čas přehrávaného prostředku do příslušného elementu. Tuto
 * funkci voláme buď přímo, nebo v reakci na událost timeupdate.
 * @param {Number} [pocetSekund] Počet sekund od začátku přehrávání.
 */
function zobrazAktualniCas(pocetSekund) {
  if (typeof pocetSekund != 'number') {
    pocetSekund = multimedialniPrehravac.currentTime;
  }

  var prehranoProcent = 0;
  if (multimedialniPrehravac.duration) {
    prehranoProcent = (pocetSekund /
      multimedialniPrehravac.duration) * 100;
  }
  $indikatorPrubehu.slider('value', prehranoProcent);

  var formatovanyCas = formatujCas(pocetSekund);
  $elementProAktualniCas.text(formatovanyCas);
}

/**
 * Zobrazí celkový čas prostředku do příslušného elementu.
 * @param {Number} pocetSekund Délka prostředku v sekundách.
 */
function zobrazCelkovyCas(pocetSekund) {
  var formatovanyCas = formatujCas(pocetSekund);
  $elementProCelkovyCas.text(formatovanyCas);
}

/**
 * Reaguje na událost loadedmetadata tak, že zpracuje načtená metadata
 * prostředku.
 */
function zpracujMetadataProstredku() {
  if (multimedialniPrehravac == videoPrehravac) {
    $elementPrehravace.width(
      Math.min(MAXIMALNI_SIRKA_PREHRAVACE,
        Math.max(MINIMALNI_SIRKA_PREHRAVACE, videoPrehravac.videoWidth)));
  } else {
    $elementPrehravace.width(vychoziSirkaPrehravace);
  }
  zobrazCelkovyCas(multimedialniPrehravac.duration);
}

/**
 * Povolí tlačítko pro přehrání prostředku.
 */
function povolTlacitkoPrehrat() {
  $tlacitkoPrehrat.button('enable');
}

/**
 * Začne přehrávat prostředek.
 */
function prehrajProstredek() {
  multimedialniPrehravac.play();
  zobrazTlacitkoPozastavit();
}

/**
 * Zobrazí tlačítko pro pozastavení prostředku.
 */
function zobrazTlacitkoPozastavit() {
  $tlacitkoPrehrat.hide();
  $tlacitkoPozastavit.show();
}

/**
 * Pozastaví přehrávání prostředku.
 */
function pozastavProstredek() {
  multimedialniPrehravac.pause();
  zobrazTlacitkoPrehrat();
}

/**
 * Aktualizuje inditikátor průběhu načítání prostředku.
 */
function aktualizujIndikatorPrubehuNacitani() {
  if (multimedialniPrehravac.buffered.length) {
    var nactenoProcent = (multimedialniPrehravac.buffered.end(0) /
      multimedialniPrehravac.duration) * 100;
    $indikatorPrubehu.progressbar('value', nactenoProcent);
  }
}

/**
 * Nastaví hlasitost přehrávače. Tuto funkci voláme v reakci na událost
 * create nebo v reakci na událost slide ovládacího prvku Slider. Případně
 * můžeme tuto funkci volat přímo a předat jí požadovanou úroveň hlasitosti
 * jako první argument.
 * @param {Object|Number} evNeboHlasitost Objekt události nebo hlasitost.
 * @param {Object} [ui] Objekt ui události create nebo slide pro ovládací
 * prvek Slider.
 */ 
function nastavHlasitost(evNeboHlasitost, ui) {
  if (typeof evNeboHlasitost == 'number') {
    hlasitost = evNeboHlasitost;
  } else if (ui.value != undefined) {
    hlasitost = ui.value;
  }

  $ovladaciPrvekHlasitosti.slider('value', hlasitost);
  var desetinnaHlasitost = hlasitost / 100;
  hudebniPrehravac.volume = desetinnaHlasitost;
  videoPrehravac.volume = desetinnaHlasitost;
}

/**
 * Posune přehrávaný prostředek na příslušnou pozici. Spouští se v reakci na
 * událost slide ovládacího prvku Slider.
 * @param {Object} ev Objekt události.
 * @param {Object} ui Objekt ui pro událost slide ovládacího prvku Slider.
 */
function posunProstredek(ev, ui) {
  if (multimedialniPrehravac.duration) {
    multimedialniPrehravac.currentTime = (ui.value / 100) *
      multimedialniPrehravac.duration;
  }
}

/**
 * Ztlumí přehrávač.
 */
function ztlumPrehravac() {
  $tlacitkoZtlumit.hide();
  $tlacitkoZesilit.show();
  hlasitostPredZtlumenim = hlasitost;
  nastavHlasitost(0);
  $ovladaciPrvekHlasitosti.slider('disable');
}

/**
 * Zesílí přehrávač.
 */
function zesilPrehravac() {
  $tlacitkoZesilit.hide();
  $tlacitkoZtlumit.show();
  nastavHlasitost(hlasitostPredZtlumenim);
  $ovladaciPrvekHlasitosti.slider('enable');
}