/**
 * @fileoverview Dynamicky seznam filmografie osoby
 * 
 * @author Laki <info@laki.cz>
 * @version 3.0 <10-11-2009>
 */  

/*
 Bloky kodu uzavrene mezi komentari /(star)deb(star)/ slouzi pouze pro ladeni kodu a ve finalnim kodu maji byt automatizovane odstraneny vcetne techto komentaru. 
 */

// tridy FILTER a DECADE

/**
 * Objekt filmografie pro dynamicke razeni a filtrovani filmografie osoby.
 *
 * <p>Nacte HTML kod filmografie a vygeneruje novou dynamickou filmografii.</p>
 * 
 * <p>Struktura vstupniho objektu:</p> 
 * <pre>
 *    id     - string - povinny
 *           - identifikator tabulky filmografie, ktera se ma nacist a nahradit
 *             
 *    sort   - array - volitelne - ve vychozim nastaveni se predpoklada "rok desc"
 *           - dvouprvkove pole popisujici vychozi serazeni vstupni tabulky
 *           - viz {@link filmografie#soft}
 *              
 *    filter - array - volitelne - vychozi nastaveni -> nic neni filtrovano
 *           - pole popisujici vychozi nastaveni filtru
 *           - pocet prvku a jejich poradi musi odpovidat poctu filtru a jejich poradi {@link filmografie#filter}
 *           - tj. napr. filtr TVFILM je na druhe pozici, proto napr. filter[1] = "off" 
 *           - kazdy prvek musi nabyvat hodnoty "on" nebo "off"
 *                 
 *    texts  - object - volitelne
 *           - definice objektu textovych promennych - viz {@link filmografie#texts}
 *           - nejsou-li zadany vsechny potrebne vlastnosti, doplni se objekt o tyto vlastnosti s vychozi nastavenim
 * </pre>    
 * 
 * @example Zakladni priklad - aplikuje filmografii na tabulku s ID="film0" a vychozim serazenim sestupne podle roku.
 *   var p = {
 *    id:     "film0", 
 *    sort:   new Array("rok", "desc") };
 *     
 *   var f0 = new filmografie(p);
 *   
 * @example Rozsirujici priklad - pridava vychozi filtrovani tabulky - zobrazovat jen filmy
 *  var p = {
 *    id:     "film0", 
 *    sort:   new Array("rok", "desc"),
 *    filter: new Array("on", "off", "off", "off", "off")  };
 *  var f0 = new filmografie(p); 
 *    
 * @example Rozsirujici priklad - nastaveni vlastnich textovych promennych - nadpis navigacni radky nastavi na "ABC"
 *  var p = {
 *    id:    "film0", 
 *    sort:  new Array("rok", "desc"),
 *    texts: {sort: "ABC"} };
 *  var f0 = new filmografie(p); 
 *  
 * @class filmografie - dynamicka filmografie osoby
 * @extends cfn
 * @version 1.0
 * @constructor
 * @requires events Udalosti
 * @requires hover Nahled miniatur  
 * @param {object} p Objekt vstupnich parametru
 */
function filmografie(p)
{
  /**
   * Element tabulky filmografie
   * @type object Element   
   * @private      
   */     
  this.el = null;
  
  /**
   * Pole parametru a nastaveni filtru (pole objektu).
   * 
   * Pro kazdy filtr obsahuje jeden zaznam objektu v poli. Vlastnosti kazdeho objektu jsou nasledujici:
   * <pre>
   *    ele - object - element checkboxu fitru
   *    sta - string - stav chechboxu (hodnoty on | off)
   *    txt - string - text nazvu filtru (tj. text checkboxu)
   *    typ - string - typ filtru - zatim muze nabyvat hodnot:
   *                      film | tvfilm | tvserial | dokument | ostatni
   * </pre>
   * 
   * <p>Poznamka: nejprve se pracuje s poli stavu a pri generovani se zmeni na pole objektu hodnot.</p>
   * 
   * @type array of object  
   * @private            
   */     
  this.filter = null;
  
  /**
   * Vlastnost definuje aktualni nastaveni razeni.
   * 
   * <pre>
   * Dvouprvkove pole:
   *   [0] - typ razeni - mozne hodnoty: rok | skore | film
   *   [1] - smer razeni - mozne hodnoty: asc | desc
   * </pre>
   *    
   * @type array   
   * @private
   */
  this.sort = null;
  
  /**
   * Objekt textovych promennych pro filmografii.
   *
   * <p>Kazda textova promenna je definovana jako samostatna vlastnost tohoto objektu typu string nebo pole stringu.</p>
   * <p>Seznam vlastnosti textovych promennych pro tento objekt:</p>
   * <pre>
   *    sort
   *    sortRokASC
   *    sortRokDESC
   *    sortSkoreASC
   *    sortSkoreDESC
   *    sortFilmASC
   *    sortFilmDESC
   *    filter - array [0..5] - indexy odpovidaji vlastnosti {@link filmografie#filter}
   * </pre>
   * 
   * @see Vyznam promennych je popsan ve zdrojaku.
   * @public      
   * @type object
   */     
  this.texts = null;
    
  //nalezeni elementu kam se vlozi filmografie
  if ((!p) || (typeof(p.id) != "string") ) return; 
  this.el = document.getElementById(p.id);
  if (this.el == null) return;
  
  //nalezeni elementu filmografie, jinak konec
  if ((!p) || (typeof(p.src) != "string") ) return; 
  this.src = document.getElementById(p.src);
  this._src = p.src;
  if (this.src == null) return;
  
/*  
  //preklady textu
  if (p.texts)
  {
    this.texts = p.texts;   //spravny format dat zajisti ten, kdo to predava pri inicializaci
  }
  else
  {
    var texts = new Object();
    this.texts = texts;
  }
  this.addText(this.texts, "sort", "Setřídit");
  this.addText(this.texts, "sortRokASC", "Seřadit vzestupně podle roku");
  this.addText(this.texts, "sortRokDESC", "Seřadit sestupně podle roku");
  this.addText(this.texts, "sortSkoreASC", "Seřadit vzestupně podle hodnocení");
  this.addText(this.texts, "sortSkoreDESC", "Seřadit sestupně podle hodnocení");
  this.addText(this.texts, "sortFilmASC", "Seřadit vzestupně podle hodnocení");  
  this.addText(this.texts, "sortFilmDESC", "Seřadit sestupně podle hodnocení");
  this.addText(this.texts, "filter", [     //nazvy filtru
        "Film",
        "TV film",
        "TV seriál",
        "Dokument",
        "Ostatní"]);

  //nastavit výchozí filtr
  if ((p.filter != null) && (p.filter instanceof Array) && (p.filter.length == 5) )
  {
    this.filter = p.filter;
  }
  else
  {
    this.filter = new Array("on", "on", "on", "on", "on");
  }
  
  //nastavit výchozí řazení
  if ( (p.sort != null) && (p.sort instanceof Array) && (p.length == 2) )
  {
    this.sort = p.sort;
  }
  else
  {
    this.sort = new Array("rok", "desc");
  }
  */

//  this.hover = new hoverBox();




  /**
   * Datove pole nactene struktury filmografie.
   * 
   * Pro kazdou skupinu obsahuje pole jeden zaznam - objekt s vlastnostmi:
   * <pre>
   *   skupina - string          - nazev skupiny filmografie 
   *   data    - array of object - data skupiny filmografie
   *   o       - html tr object  - objekt radku tabulky filmografie s definici
   *                               skupiny
   *   sort    - string          - typ serazeni, nabyva hodnot:
   *                                rok | skore | film   
   *   sortdir - string          - smer razeni, nabyva hodnot:
   *                                asc | desc
   *   show    - boolean         - priznak zobrazeni filmografie      
   * </pre>
   * kazda skupina ma pole datovych objektu pro kazdy zaznam ve filmografii
   * s temito atributy:   
   * <pre>
   *   rok      - string  - cislo roku
   *   skore    - string  - textova hodnota skore (napr. "86,2%")
   *   skoreval - number  - ciselna hodnota skore  
   *   film     - string  - nazev filmu
   *   url      - string  - url filmu
   *   cb       - boolean - priznak cernobileho filmu
   *   metraz   - string  - typ metraze filmu, nabyva hodnot:
   *                         kratko | stredo | dlouho   
   *   atribut  - string  - atribut filmu, nabyva hodnot:
    *                        film | tvfilm | tvserial | tvporad |
   *                         dokument | divadlo | famu | videofilm   
   *   o        - html tr object - radek tabulky se zaznamem
   * </pre>
   * 
   * @type array of object  
   * @private            
   */  
  this.data = new Array();


  this.load();   //nacte obsah tabulky filmografie z html dokumentu
  
  //nacist sablony
  this.t = new templateObject();
  this.t.add("fgdata");
  
  this.updateTable();  //prida ovladaci prvky do tabulky
  this.addControl();   //prida ovladaci prvky nad tabulku
  

/*  vkladani textovych promennych sablonou
  x = "Hi!";
  this.t.get("fg_texts").process();
  this.x = x; */

//  this.create();    //vygeneruje novy obsah
}

// filmografie je rozsirenim objektu cfn
filmografie.prototype = new cfn;

filmografie.prototype.load = function()
{
  this.data = new Array();  //vycistit pole
 
  var r = cssQuery("tr", this.src); //vsechny radky tabulky
  var skupina = "";
  
  for (i=0; i<r.length; i++)
  {
    skupina = this.getText(cssQuery("th:nth-child(4)", r[i])[0]);
    if (skupina != "")
    { //zalozit skupiny filmografie a nastavit vychozi razeni
      var s = { skupina: skupina, data: [], o: r[i], sort: "rok", sortdir: "desc", show: true };
      this.data.push(s);
      continue;
    }
    
    
    var d = {};   //data o filmu
    
    d.rok = this.getText(cssQuery("td.rok", r[i])[0]);
    
    d.skore = this.getText(cssQuery("td.skore span", r[i])[0]);
    
    //prevede skore na ciselnou hodnotu pro razeni podle skore
    if (d.skore == "?")
    {
      d.skoreval = -1;
    }
    else
    {
      d.skoreval = parseFloat(d.skore.substring(0, d.skore.length-1).replace(/,/, "."));
    }
    
    d.film = this.getText(cssQuery("td.film a", r[i])[0]);
    d.url = cssQuery("td.film a", r[i])[0].getAttribute("href");
    
    //atribut cernobily
    if (this.hasClass(r[i], "cb"))
    {
      d.cb = true;
    }
    else
    {
      d.cb = false;
    }
    
    //metraz
    if (this.hasClass(r[i], "kratkometrazni"))
    {
      d.metraz = "kratko";
    }
    else if (this.hasClass(r[i], "stredometrazni"))
    {
      d.metraz = "stredo";
    }
    else
    {
      d.metraz = "dlouho";
    }
    
    //atribut
    if (this.hasClass(r[i], "tvfilm"))
    {
      d.atribut = "tvfilm";
    }
    else if (this.hasClass(r[i], "tvserial"))
    {
      d.atribut = "tvserial";
    }
    else if (this.hasClass(r[i], "tvporad"))
    {
      d.atribut = "tvporad";
    }
    else if (this.hasClass(r[i], "dokument"))
    {
      d.atribut = "dokument";
    }
    else if (this.hasClass(r[i], "divadlo"))
    {
      d.atribut = "divadlo";
    }
    else if (this.hasClass(r[i], "famu"))
    {
      d.atribut = "famu";
    }
    else if (this.hasClass(r[i], "videofilm"))
    {
      d.atribut = "videofilm";
    }
    else
    {
      d.atribut = "film";
    }

    //ulozit ukazatel na objekt radku/zaznamu
    d.o = r[i];
    
    this.data[this.data.length-1].data.push(d);
  }
/*  
  this.deb(this.data);
  for (i=0;i<this.data.length; i++)
  {
    this.deb(this.data[i].skupina);
    this.deb(this.data[i].data);
  }
*/
}

function scrollToElement(theElement)
{
  var selectedPosX = 0;
  var selectedPosY = 0;
              
  while(theElement != null)
  {
    selectedPosX += theElement.offsetLeft;
    selectedPosY += theElement.offsetTop;
    theElement = theElement.offsetParent;
  }
                        		      
  window.scrollTo(selectedPosX, selectedPosY);
}


filmografie.prototype.updateTable = function()
{
  for (ii=0;ii<this.data.length; ii++)
  {
    //prida zarazky pro rychly vyber skupin
    this.data[ii].o.setAttribute("id", this._src+ii);
    
    //pridat ovladaci prvky razeni podle roku
    cssQuery("th.rok", this.data[ii].o)[0].innerHTML = this.t.get("fg_head_rok").process();
    
    //pridat ovladaci prvky razeni podle skore
    cssQuery("th.skore", this.data[ii].o)[0].innerHTML = this.t.get("fg_head_skore").process();
    
    //pridat ovladaci prvky razeni podle filmu a vyber
    var o = new Object(); 
    o.funkce = this.data[ii].skupina;
    o.pole = [];
    
    var last = 0;
    for (j=0; j<this.data[ii].data.length; j++)
    {
      var l = parseInt(parseInt(this.data[ii].data[j].rok)/10)*10;
      if (last != l)
      {
        last = l;
        o.pole[l] = (l.toString()) + "-" + ((l+9).toString());
      }
      this.addClass(this.data[ii].data[j].o, this._src+"_"+l);
    }
    o.pole[0] = "vše";
    
    cssQuery("th.film", this.data[ii].o)[0].innerHTML = this.t.get("fg_head_film").process(o);
    
    //pridat ovladaci prvky do metraze - sbalit filmografii
    cssQuery("th.metraz", this.data[ii].o)[0].innerHTML = this.t.get("fg_head_metraz").process();
    events.addEventListener(cssQuery("th.metraz a", this.data[ii].o)[0], "click", this.showhide, this);
    
    //pridat ovladaci prvky pro vyber desetileti
    events.addEventListener(cssQuery("th.film select", this.data[ii].o)[0], "change", this.decadeDriver, this);
  }
}

// sbali/rozbali filmografii
filmografie.prototype.showhide = function(e)
{
  if (!e) var e = window.event;
  
  //najit nadrazeny radek s definici hlavicky
  var element = events.eventSource(e);
  while (element.tagName.toUpperCase() != "TR")
  {
    element = element.parentNode;
  }
  
  //najit zdrojovy element v datech
  for (index=0; index<this.data.length; index++)
  {
    if (this.data[index].o == element) break;
  }

  this.data[index].show = !this.data[index].show;
  
  //zobrazit/schovat radky filmografie
  for (i=0; i<this.data[index].data.length; i++)
  {
    if (this.data[index].show)
    { //zobrazit
      //this.data[index].data[i].o.style.display = "block";
      this.data[index].data[i].o.style.display = "table-row";
    }
    else
    { //schovat    
      this.data[index].data[i].o.style.display = "none";
    }
  }
  //upravit ovladaci prvek
  element = cssQuery("th.metraz a", element)[0];
  if (this.data[index].show)
  { //zmenit na schovat
    this.removeClass(element, "show");
    this.addClass(element, "hide");
    element.setAttribute("title", "Sbalit filmografii");
  }
  else
  { //zmenit na zobrazit    
    this.removeClass(element, "hide");
    this.addClass(element, "show");
    element.setAttribute("title", "Rozbalit filmografii");
  }
}



// prida ovladani tabulky
filmografie.prototype.addControl = function()
{
  //vygeneruje zakladni kostru vkladaneho bloku
  this.el.innerHTML = this.t.get("fg_skeleton").process();

//-----

  // pridat radek rychleho vyberu filmografie
  var o = new Object();
  o.pole = [];
  o.id = this._src+"_chb_ceny";
   
  for (j=0; j<this.data.length; j++)
  {
    o.pole[j] = this.data[j].skupina;
  }
  cssQuery("div:nth-child(1)", this.el)[0].innerHTML = this.t.get("fg_top").process(o);
  
  new checkbox( {id: o.id, disabled: true} );   //vypne checkbox Zobrazovat ceny
  
  //pridat driver pro vyber skupiny filmografie
  events.addEventListener(cssQuery("#fg_top select")[0], "change", this.jumpDriver, this);
  
//---------
  
  // pridat radek filtru
  var o = new Object();
  o.id = this._src;
  cssQuery("div:nth-child(2)", this.el)[0].innerHTML = this.t.get("fg_filters").process(o);
  
  // zjistit dostupne atributy
  var a = { //objekt atributu
    film:      false,
    tvfilm:    false,
    tvserial:  false,
    tvporad:   false,
    dokument:  false,
    divadlo:   false,
    famu:      false,
    videofilm: false };
  
  var m = { //objekt metraze
    kratko: false,
    stredo: false,
    dlouho: false };
    
  var cb = false;   //cernobily
  
  for (j=0; j<this.data.length; j++)
  {
    for (jj=0; jj<this.data[j].data.length; jj++)
    { //projdi vsechny zaznamy filmografie
      a[this.data[j].data[jj].atribut] = true; // existujici atributy nastav na true
      m[this.data[j].data[jj].metraz] = true;  // existujici metraze nastav na true
      if (this.data[j].data[jj].cb) cb = true; // pripadne existujici cernobily film
    }
  }
  //inicializuj checkboxy
  for (atr in a)
  {
    if (a[atr])
    { //existujici atribut ve filmografii
      new checkbox( { id: (o.id+"_chb_"+atr), onchange: events.getEvent(this.filterDriver, this) } );
    }
    else
    { //nevyskytujici se atribut ve filmografii
      new checkbox( { id: (o.id+"_chb_"+atr), disabled: true } );
    }
  }
 
//---------
  
  //prida radky ovladani metraze a cernobily
  var o = new Object();
  o.id = this._src;
  cssQuery("div:nth-child(3)", this.el)[0].innerHTML = this.t.get("fg_metraz").process(o);
  
  //inicializuj checkboxy
  for (metr in m)
  {
    if (m[metr])
    { //existujici metraz ve filmografii
      new checkbox( { id: (o.id+"_chb_"+metr), onchange: events.getEvent(this.metrazDriver, this) } );
    }
    else
    { //nevyskytujici se metraz ve filmografii
      new checkbox( { id: (o.id+"_chb_"+metr), disabled: true } );
    }
  }
  
//---------

  //cernobily
  if (cb)
  { //existuji cernobile filmy
    new checkbox( { id: (o.id+"_chb_cb"), onchange: events.getEvent(this.cbDriver, this) } );
  }
  else
  { //neexistuji cernobile filmy
    new checkbox( { id: (o.id+"_chb_cb"), disabled: true } );
  }
}


// ovladac filtru
filmografie.prototype.filterDriver = function()
{
  //###zpusob jak se dostat skrz zasobnik k parametrum predchozi volane funkce
  //##zkusit vymysled jinej events.getEvent
  ch = arguments.callee.caller.arguments[0];  //objekt checkboxu
  t = ch.el.getAttribute("id");   //idcko nejak jako filmografie125_chb_tvserial
  t = t.substring(t.lastIndexOf("_")+1, t.length);  // a uz jen tv_serial

  for (j=0; j<this.data.length; j++)
  {
    for (jj=0; jj<this.data[j].data.length; jj++)
    {
      if (this.data[j].data[jj].atribut == t)
      {
        if (ch.value)
        { //zobrazit zasedivele zaznamy
          this.removeClass(this.data[j].data[jj].o, "filter");
        }
        else
        { //zasedivet zaznamy
          this.addClass(this.data[j].data[jj].o, "filter");
        }
      }
    }
  }
}


// ovladac metraze
filmografie.prototype.metrazDriver = function()
{
  //###zpusob jak se dostat skrz zasobnik k parametrum predchozi volane funkce
  //##zkusit vymysled jinej events.getEvent
  ch = arguments.callee.caller.arguments[0];  //objekt checkboxu
  t = ch.el.getAttribute("id");   //idcko nejak jako filmografie125_chb_kratko
  t = t.substring(t.lastIndexOf("_")+1, t.length);  // a uz jen kratko

  for (j=0; j<this.data.length; j++)
  {
    for (jj=0; jj<this.data[j].data.length; jj++)
    {
      if (this.data[j].data[jj].metraz == t)
      {
        if (ch.value)
        { //zobrazit zasedivele zaznamy
          this.removeClass(this.data[j].data[jj].o, "filter");
        }
        else
        { //zasedivet zaznamy
          this.addClass(this.data[j].data[jj].o, "filter");
        }
      }
    }
  }
}

// ovladac cernobily
filmografie.prototype.cbDriver = function(ooo)
{
  //###zpusob jak se dostat skrz zasobnik k parametrum predchozi volane funkce
  //##zkusit vymysled jinej events.getEvent
  ch = arguments.callee.caller.arguments[0];  //objekt checkboxu
this.deb(arguments.callee.value);
  for (j=0; j<this.data.length; j++)
  {
    for (jj=0; jj<this.data[j].data.length; jj++)
    {
      if (this.data[j].data[jj].cb)
      {
        if (ch.value)
        { //zobrazit zasedivele zaznamy
          this.removeClass(this.data[j].data[jj].o, "filter");
        }
        else
        { //zasedivet zaznamy
          this.addClass(this.data[j].data[jj].o, "filter");
        }
      }
    }
  }
}


// ovladac jumpu
filmografie.prototype.jumpDriver = function(e)
{
  if (!e) var e = window.event;
  
  index = events.eventSource(e).value;  //zjisti hodnotu vybrane skupiny
  
  scrollToElement(this.data[index].o);  //odskroluj
}


// ovladac filtru
filmografie.prototype.decadeDriver = function(e)
{
  if (!e) var e = window.event;
  
  var v = events.eventSource(e).value.toString();  //vybrana hodnota
  
  //najit nadrazeny radek s definici hlavicky
  var element = events.eventSource(e);
  while (element.tagName.toUpperCase() != "TR")
  {
    element = element.parentNode;
  }
  
  for (index=0; index<this.data.length; index++)
  {
    if (this.data[index].o == element) break;
  }

  for (j=0; j<this.data[index].data.length; j++)
  {
    if (v == "0")
    { //vsechno - odstranit veskere oznaceni
      this.removeClass(this.data[index].data[j].o, "decade");
    }
    else
    { //odstranit pripadne oznaceni dekady a oznacit novou
      if (this.hasClass(this.data[index].data[j].o, "decade"))
      {
        this.removeClass(this.data[index].data[j].o, "decade");
      }
      if (this.hasClass(this.data[index].data[j].o, this._src+"_"+v))
      {
        this.addClass(this.data[index].data[j].o, "decade");
      }
    }
  }

  //###zpusob jak se dostat skrz zasobnik k parametrum predchozi volane funkce
  //##zkusit vymysled jinej events.getEvent
  /*ch = arguments.callee.caller.arguments[0];  //objekt checkboxu
  t = ch.el.getAttribute("id");   //idcko nejak jako filmografie125_chb_tvserial
  t = t.substring(t.lastIndexOf("_")+1, t.length);  // a uz jen tv_serial

  for (j=0; j<this.data.length; j++)
  {
    for (jj=0; jj<this.data[j].data.length; jj++)
    {
      if (this.data[j].data[jj].atribut == t)
      {
        if (ch.value)
        { //zobrazit zasedivele zaznamy
          this.removeClass(this.data[j].data[jj].o, "filter");
        }
        else
        { //zasedivet zaznamy
          this.addClass(this.data[j].data[jj].o, "filter");
        }
      }
    }
  } */
}











































//vytvori novou tabulku
filmografie.prototype.create = function()
{
  this.createShortcut();
  this.createFilter();
 
  var code = "";
  code = '<table id="filmografie" class="filmografie3">';
 
  //this.el.innerHTML += this.t.get("fg_table").process();
 
  for (ii=0;ii<this.data.length;ii++)
  {
    code += this.createHead(this.data[ii]);
    code += this.writeData(this.data[ii].data);
  }
  
  code += "</table>";
  
  this.el.innerHTML += code;
}

filmografie.prototype.createHead = function(d)
{
  var o = new Object();
  o.funkce = d.skupina.toUpperCase();   //##udelat to stylem
  
  
  return(this.t.get("fg_head").process(o));
}

filmografie.prototype.writeData = function(d)
{
  var c = "";
  for (iii=0; iii<d.length; iii++)
  {
    var o = new Object;
    o.rok = d[iii].rok;
    o.inc = iii+1;
    o.skore = d[iii].skore;
    if (o.skore == "") o.skore = "?";
    o.url = d[iii].url;
    o.film = d[iii].film;
    
    c += this.t.get("fg_data").process(o);
  }
  return c;
}


filmografie.prototype.createShortcut = function()
{
  if (this.data.length > 1)
  {  //shortcut vyber resit jen kdyz jich je vic
    var o = new Object();
    o.pole = [];
    
    for (i=0;i<this.data.length;i++)
    {
      o.pole[i] = this.data[i].skupina;
    }
    this.el.innerHTML += this.t.get("fg_top").process(o);

//do this, stejne tak fg_shortcut
    var chb_ceny = new checkbox( {id: "fg_chb_ceny", defaultvalue: false} );
    
    events.addEventListener(document.getElementById("fg_shortcut"), "change", this.shortcut, this);
  }
}

filmografie.prototype.shortcut = function()
{
  v = document.getElementById("fg_shortcut").selectedIndex;
  alert(v);
}

filmografie.prototype.createFilter = function()
{
  if (this.data.length > 1)
  {  //shortcut vyber resit jen kdyz jich je vic
    var o = new Object();
    o.pole = [];
    
    this.el.innerHTML += this.t.get("fg_filters").process(o);
  }
}

/*

  for (k in this.data)
  {
    this.deb(this.data[k].data);
  }

*/































  
/**
 * Metoda obsluhuje checkboxy (meni stavy on a off). Metoda je navazana na udalost "click" checkboxu. 
 * @private
 * @param {object event} e 
 */  
filmografie.prototype.checkbox = function(e)
{
  var element = events.eventSource(e);
  
  //najit element ve filtech
  for (var i=0; i<this.filter.length; i++)
  {
    if (element == this.filter[i].ele)
    {
      break;
    }
  }
  
  this.removeClass(element, this.filter[i].sta);
  
  if (this.filter[i].sta == "on")
  {
    this.filter[i].sta = "off";
    this.addFilterTable(this.filter[i].typ);
  }
  else
  {
    this.filter[i].sta = "on";
    this.removeFilterTable(this.filter[i].typ);
  }
  
  this.addClass(element, this.filter[i].sta);
}
  
/**
 * Metoda setridi obsah tabulky.
 * 
 * <p>Po serazani necha pregenerovat tabulku, zmeni hodnotu razeni a vola prekresleni ikon razeni.</p> 
 * <p>Pro razeni se pouziva Bubblesort.</p>  
 *
 * @private 
 * @param {string} typ Typ razeni - mozne hodnoty rok | skore | film
 * @param {string} smer Smer razeni - mozne hodnoty asc | desc
 */    
filmografie.prototype.sortFilmografie = function(typ, smer)
{
  
  /**
   * Funkce pro porovnani dvou prvku
   * 
   * @param {string} a1
   * @param {string} a2 
   * @param {string} smer Smer razeni - asc | desc
   * @return {boolean} Vysledek porovnani 
   * @type boolean                  
   */     
  function compare(a1, a2, smer)
  { //bubble sort - porovnava
    return (smer == "desc") ? a1 > a2 : a1 < a2;
  }
  
  /**
   * Funkce, ktera vraci hodnotu pro porovnani.
   * 
   * @param {int}    i    Index zaznamu (radek tabulky)
   * @param {string} typ  Typ data, podle kterych se provadi razeni
   * @param {array}  data Datova struktura this.data
   * @return {string} Textova hodnota pro porovnani 
   * @type string
   */     
  function get(i, typ, data)
  { //bubble sort - vraci polozku pro porovnani
    switch (typ)
    {
      case "rok":
        return data[1][i].rok;
        break;
        
       case "skore":
        var s = data[1][i].skore;
        if (s.indexOf(",") == -1)
        {
          return parseInt(s)*10;
        }
        else
        {
          s = s.split(",");
          return parseInt(s[0] + s[1]);
        }
        break;
        
      case "film":
        return data[1][i].film_name;
        break;
    }      
  }
  
  /**
   * Procedura prohodi dva prvky v datovem poli.
   *     
   * Zameni polozky pole s indexem a1 za a2.
   * 
   * @param {int}   a1   Index prvni polozky
   * @param {int}   a2   Index druhe polozky
   * @param {array} data Datova struktura this.data            
   */     
  function exchange(a1, a2, data)
  { //bubble sort -> vymeni polozky
    var temp = data[1][a1];
    data[1][a1] = data[1][a2];
    data[1][a2] = temp;
  }
  
  //seradit vsechny profese samostatne
  for (var profese=0; profese<this.data.length; profese++)
  {
    // bubble sort
    var N = this.data[profese][1].length;
    for (var j=N-1; j>0; j--)
    {
      for (var i=0; i<j; i++)
      {
        if (compare(get(i+1, typ, this.data[profese]), get(i, typ, this.data[profese]), smer)) exchange(i+1, i, this.data[profese]);
      }
    }
  }

  //pregenerovat tabulku
  this.removeTable();
  this.generateTable();
  this.setFilter();
  
  //nastavit ikonu aktualniho razeni
  this.unsetSortIcon();
  this.sort[0] = typ;
  this.sort[1] = smer;
  this.setSortIcon();
}
  
// obsluzne metody pro udalosti razeni
/**
 * Metoda obsluhy udalosti razeni - podle roku a vzestupne.
 * @private 
 */ 
filmografie.prototype.sortRokASC = function()
{
  this.sortFilmografie("rok", "asc");
}
/**
 * Metoda obsluhy udalosti razeni - podle roku a sestupne.
 * @private 
 */
filmografie.prototype.sortRokDESC = function()
{
  this.sortFilmografie("rok", "desc");
}
/**
 * Metoda obsluhy udalosti razeni - podle skore a vzestupne.
 * @private 
 */
filmografie.prototype.sortSkoreASC = function()
{
  this.sortFilmografie("skore", "asc");
}
/**
 * Metoda obsluhy udalosti razeni - podle skore a sestupne.
 * @private 
 */
filmografie.prototype.sortSkoreDESC = function()
{
  this.sortFilmografie("skore", "desc");
}
/**
 * Metoda obsluhy udalosti razeni - podle nazvu filmu a vzestupne.
 * @private 
 */
filmografie.prototype.sortFilmASC = function()
{
  this.sortFilmografie("film", "asc");
}
/**
 * Metoda obsluhy udalosti razeni - podle nazvu filmu a sestupne.
 * @private 
 */
filmografie.prototype.sortFilmDESC = function()
{
  this.sortFilmografie("film", "desc");
}
  
/**
 * Metoda vytvori novou tabulku filmografie.
 *  
 * Doplni vlastnost {@link filmografie#sort}, odstrani vychozi tabulku, vygeneruje hlavicku nove tabulky a vygeneruje novy obsah tabulky.
 * <p>Poznamka: Vola se jen pri inicializaci objetku.</p> 
 * 
 * @private  
 */  
filmografie.prototype.create_old = function()
{    
  //rozsirit filter
  for (var i=0; i<this.filter.length; i++)
  {
    this.filter[i] = {
      ele: null,
      sta: this.filter[i],
      txt: this.texts.filter[i] };
    switch (i)
    {
      case 0:
        this.filter[i].typ = "film"; 
        break;
      case 1:
        this.filter[i].typ = "tvfilm"; 
        break;
      case 2:
        this.filter[i].typ = "tvserial"; 
        break;
      case 3:
        this.filter[i].typ = "dokument"; 
        break;
      case 4:
        this.filter[i].typ = "ostatni"; 
        break;
    };
  }

  this.removeTable(); //odstranit obsah tabulky
  
  this.createHead();  //vygenerovat navigaci
  
  this.setSortIcon();
  
  this.generateTable();   //vygenerovat novou tabulku
  
  this.setFilter();    
}
  
/**
 * Metoda vytvori hlavicku nove tabulky s ovladacimi prvky.
 * 
 * <p>Poznamka: Vola se pouze pri inicializaci, pak uz se jen modifikuje obsah.</p>  
 * 
 * @private 
 */ 
filmografie.prototype.createHeadold = function()
{
  //definice promennych jen pro dokumentaci, jinak to dela this.ele
  /**
   * Element THEAD tabulky  
   * @private
   */     
  this.elH = null;
  /**
   * Element TR radku THEAD tabulky   
   * @private
   */     
  this.elHH = null;
  /**
   * Element odkazu pro razeni podle roku vzestupne
   * @private
   */
  this.elSortRokASC = null;
  /**
   * Element odkazu pro razeni podle roku sestupne
   * @private
   */
  this.elSortRokDESC = null;
  /**
   * Element odkazu pro razeni podle skore vzestupne
   * @private
   */
  this.elSortSkoreASC = null;
  /**
   * Element odkazu pro razeni podle skore sestupne
   * @private
   */
  this.elSortSkoreDESC = null
  /**
   * Element odkazu pro razeni podle nazvu filmu vzestupne
   * @private
   */
  this.elSortFilmASC = null;
  /**
   * Element odkazu pro razeni podle nazvu filmu sestupne
   * @private
   */
  this.elSortFilmDESC = null
  

  //element zahlavi
  var p = {
    el: "thead", 
    ins: this.el, 
    ass: "this.elH"};
  this.ele(p);

  //radek navigace
  var p = {
    el: "tr",
    ass: "this.elHH" };
  var row = this.ele(p);
  
  //sloupec LABEL
  var p = {
    el: "th",
    atr: [ ["class", "label"] ],
    ins: this.elHH,
    txt: this.texts.sort };
  this.ele(p);
  
  //sloupec ROK
  var p = {
    el: "th",
    atr: [ ["class", "rok"] ] };
  var element = this.ele(p);
  
  var p = {
    el: "a",
    atr: [ ["title", this.texts.sortRokASC], ["class", "up"] ],
    ass: "this.elSortRokASC" };
  this.ele(p);
  this.ins(this.elSortRokASC, element);
  events.addEventListener(this.elSortRokASC, "click", this.sortRokASC, this);
  
  var p = {
    el: "a",
    atr: [ ["title", this.texts.sortRokDESC], ["class", "down"] ],
    ass: "this.elSortRokDESC" };
  this.ele(p);
  this.ins(this.elSortRokDESC, element);
  events.addEventListener(this.elSortRokDESC, "click", this.sortRokDESC, this);

  this.ins(element, this.elHH);

  //sloupec NUMBER
  var p = {
    el: "th",
    atr: [ ["class", "number"] ],
    txt: " ",
    ins: this.elHH };
  this.ele(p);
  
  //sloupec SKORE
  var p = {
    el: "th",
    atr: [ ["class", "skore"] ] };
  var element = this.ele(p);
  
  var p = {
    el: "a",
    atr: [ ["title", this.texts.sortSkoreASC], ["class", "up"] ],
    ass: "this.elSortSkoreASC" };
  this.ele(p);
  this.ins(this.elSortSkoreASC, element);
  events.addEventListener(this.elSortSkoreASC, "click", this.sortSkoreASC, this);
  
  var p = {
    el: "a",
    atr: [ ["title", this.texts.sortSkoreDESC], ["class", "down"] ],
    ass: "this.elSortSkoreDESC" };
  this.ele(p);
  this.ins(this.elSortSkoreDESC, element);
  events.addEventListener(this.elSortSkoreDESC, "click", this.sortSkoreDESC, this);

  this.ins(element, this.elHH);
  
  //sloupec FILM
  var p = {
    el: "th",
    atr: [ ["class", "film"] ] };
  var element = this.ele(p);
  
  var p = {
    el: "a",
    atr: [ ["title", this.texts.sortFilmASC], ["class", "up"] ],
    ass: "this.elSortFilmASC" };
  this.ele(p);
  this.ins(this.elSortFilmASC, element);
  events.addEventListener(this.elSortFilmASC, "click", this.sortFilmASC, this);
  
  var p = {
    el: "a",
    atr: [ ["title", this.texts.sortFilmDESC], ["class", "down"] ],
    ass: "this.elSortFilmDESC" };
  this.ele(p);
  this.ins(this.elSortFilmDESC, element);
  events.addEventListener(this.elSortFilmDESC, "click", this.sortFilmDESC, this);
  
  var p = {
    el: "span",
    atr: [ ["class", "filtr"] ] };
  var element2 = this.ele(p);
  
  //vygenerovat checkboxy filtru
  for (var i=0; i<this.filter.length; i++)
  {
    var p = {
      el: "span",
      atr: [ ["class", "checkbox"] ],
      ass: "this.filter["+i+"].ele",
      txt: this.filter[i].txt };
    this.ele(p);
    this.addClass(this.filter[i].ele, this.filter[i].sta);
    this.ins(this.filter[i].ele, element2);
    
    events.addEventListener(this.filter[i].ele, "click", this.checkbox, this);
  }
  this.ins(element2, element);
  
  this.ins(element, this.elHH);
  
  this.ins(row, this.elH);
}

/**
 * Metoda projde radky tabulky na nastavi filter radkum, ktere maji byt filtrovany.
 * 
 * @private 
 */  
filmografie.prototype.setFilter = function()
{
  //nasadit filter
  for (var i=0; i<this.filter.length; i++)
  {
    if (this.filter[i].sta == "off")
    {
      this.addFilterTable(this.filter[i].typ);
    }
  }
}


/**
 * Metoda nacte data z puvodni tabulky vygenerovane php skriptem do datove struktury.
 * 
 * <p>Vola se jen pri inicializaci.</p>  
 *
 * @private 
 */  
filmografie.prototype.loadTableold = function()
{
  /**
   * Pole datove struktury. Obsahuje strukturu a obsah cele tabulky. Jeden prvek pole pro kazdy radek pole.
   *
   * <p>Struktura:</p>   
   * <pre>
   * [] - array - pole udaju o profesi (radek tabulky)
   *     [0] - string - nazev profese
   *     [1] - object - objekt s daty z jednotlivych radku
   *       typ:        string  - typ filtru radku - film | tvfilm | tvserial | dokument | ostatni
   *       rok:        string  - rok vyrobeni filmu
   *       skore:      string  - skore filmu (format "28,5%"" nebo "100%")
   *       film_link:  string  - URL odkazu filmu
   *       film_alt:   string  - popis odkazu filmu (obsah atributu alt odkazu filmu)
   *       film_name:  string  - nazev filmu (odkazu)
   *       role:       boolean - true - role definovana, false - role nedefinovana
   *       role_name:  string  - je-li role definovana, nese text role
   *       row:        object  - element vygenerovaneho radku pro dalsi praci
   * </pre>
   *            
   * @type array
   * @private   
   */           
  this.data = new Array();  //nese informace z tabulky
  
  var typ = "ostatni";   //vychozi typ zaznamu, pokud neni definovany

  var tr = this.el.getElementsByTagName("tr");
  for (var i=0; i<tr.length; i++)
  {    
    var td = tr.item(i).getElementsByTagName("td");
    
    //ignorovat oddelujici radek
    if (this.getClass(td.item(0)) == "divider")
    {
      continue;
    }
    
    //zjisti typ zaznamu
    if (this.getClass(tr[i]) != "")
    {
      typ = this.getClass(tr[i]);
    }
    else
    {
      typ = "ostatni";
    }
    
    //prohledej popisky
    if (td.item(0).hasChildNodes())
    {
      var e = td.item(0).childNodes;
    
      if (e[0].nodeType == 3)
      { //radek obsahuje popisek, udelej novou skupinu
        this.data.push([e[0].nodeValue, new Array()]);
      }
    }

    var a = td[4].getElementsByTagName("a");        //element odkazu filmu
    var span = td[4].getElementsByTagName("span");  //element role, je-li definovana
    //ulozit data z radku
    this.data[this.data.length-1][1].push({
      typ:        typ,
      rok:        td[1].childNodes[0].nodeValue,
      skore:      td[3].childNodes[0].childNodes[0].nodeValue,
      film_link:  a[0].href,
      film_alt:   a[0].alt,
      film_name:  a[0].childNodes[0].nodeValue,
      role:       (span.length == 1) ? true : false,
      role_name:  (span.length == 1) ? span[0].childNodes[0].nodeValue : ""
    });
    
  } 
}
  
/**
 * Metoda prida vsem radkum tabulky, ktere maji hodnotu filtru FILTER priznak filtrace.
 *
 * @param {string} filter Nazev filtru - viz {@link filmografie#filter}.txt
 * @private 
 */   
filmografie.prototype.addFilterTable = function(filter)
{
  for (var i=0; i<this.data.length; i++)
  { //projit vsechny skupiny filmografie
          
    for (var j=0; j<this.data[i][1].length; j++)
    { //projit jednotlive radky skupiny      
      if (this.data[i][1][j].typ == filter)
      {
        this.addClass(this.data[i][1][j].row, "filter");        
      }
    }
  }
}
  
/**
 * Metoda odstranuje filtry. Neni-li zadan parametr, odstrani vsechny nastavene filtry, jinak odstranuje jen filtr zadany v parametru.
 *  
 * @param {string} filter Nazev filtru - viz {@link filmografie#filter}.txt
 * @private
 */ 
filmografie.prototype.removeFilterTable = function(filter)
{
  for (var i=0; i<this.data.length; i++)
  { //projit vsechny skupiny filmografie
          
    for (var j=0; j<this.data[i][1].length; j++)
    { //projit jednotlive radky skupiny      
    
      if (filter == null)
      {
        this.removeClass(this.data[i][1][j].row, "filter");
      }
      else
      {
        if (this.data[i][1][j].typ == filter)
        {
          this.removeClass(this.data[i][1][j].row, "filter");
        }
      }
      
    }
  }
}
  
  
/**
 * Metoda vygeneruje tabulku podle aktualnich udaju a prirazuje udalost HOVER (miniatura). 
 * 
 * @requires hover.startBox 
 * @private
 */  
filmografie.prototype.generateTable = function()
{
  var label = "";     //nese popis skupiny

  for (var i=0; i<this.data.length; i++)
  { //projit vsechny skupiny filmografie
    
    label = this.data[i][0];
    
    for (var j=0; j<this.data[i][1].length; j++)
    { //projit jednotlive radky skupiny

      //radek tabulky
      var p = { el: "tr" };
      var row = this.ele(p);
      
      //sloupec LABEL
      if (label != "")
      {
        //udelat oddelovaci radek
        var p = {
          el: "td",
          atr: [ ["colspan", "5"], ["class", "divider"] ]
        }
        var element = this.ele(p);
        this.ins(element, row);
        this.ins(row, this.el.getElementsByTagName("tbody")[0]);
        
        //vygenerovat novy radek
        var p = { el: "tr" };
        var row = this.ele(p);
      
        //vygenerovat bunku s nazvem pozice
        var p = {
          el: "td",
          atr: [ ["class", "label"] ],
          txt: label };
          
        label = "";
      }
      else
      { //generovat bunku bez nazvu pozice
        var p = {
          el: "td",
          atr: [ ["class", "label"] ] };
      }
      var element = this.ele(p);
      this.ins(element, row);
      
      //sloupec ROK
      var p = {
        el: "td",
        atr: [ ["class", "rok"] ],
        txt: this.data[i][1][j].rok };
      var element = this.ele(p);
      this.ins(element, row);
      
      //sloupec NUMBER
      var p = {
        el: "td",
        atr: [ ["class", "number"] ],
        txt: (j+1)+"." };
      var element = this.ele(p);
      this.ins(element, row);
      
      //sloupec SKORE
      var p = {
        el: "td",
        atr: [ ["class", "skore"] ] };
      var element = this.ele(p);
      var p = {
        el: "span",
        txt: this.data[i][1][j].skore };
      var span = this.ele(p);
      this.ins(span, element);
      this.ins(element, row);
      
      //sloupec FILM
      var p = {
        el: "td",
        atr: [ ["class", "film"] ] };
      var element = this.ele(p);
              
      var p = {
        el: "a",
        atr: [ ["href", this.data[i][1][j].film_link], ["alt", this.data[i][1][j].film_alt] ],
        txt: this.data[i][1][j].film_name };
      var a = this.ele(p);
      this.ins(a, element);
      
      events.addEventListener(a, "mouseover", this.hover.startBox, this.hover);
      
      //najit text ikony
      var ikonatxt = "";
      for (var k=0; k<this.filter.length; k++)
      {
        if (this.filter[k].typ == this.data[i][1][j].typ)
        {
          ikonatxt = this.filter[k].txt;
        }
      }
      var p = {
        el: "div",
        atr: [ ["class", "icon"], ["title", ikonatxt] ] };
      var ikona = this.ele(p);
      this.ins(ikona, a);
    
      
      if (this.data[i][1][j].role)
      { //jeste pridat roli
        var p = {
          el: "span",
          atr: [ ["class", "role"] ],
          txt: this.data[i][1][j].role_name };
        var span = this.ele(p);
        this.ins(span, element);
        
        this.addClass(element, "role");
      }
      
      this.ins(element, row);
              
      
      //pridat radku typ
      this.addClass(row, this.data[i][1][j].typ);
      
      //vlozit radek
      this.ins(row, this.el.getElementsByTagName("tbody")[0]);
      
      this.data[i][1][j].row = row;
    }
  }
}
  

/**
 * Metoda odstrani vsechny radky tabulky, ale zanecha navigacni radek (THEAD).
 *
 * @private 
 */  
filmografie.prototype.removeTable = function()
{
  var element = this.el.getElementsByTagName("tbody")[0];
  
  //zrusit vsechny radky tabulky TBODY
  while (element.getElementsByTagName("tr").length > 0)
  {
    element.getElementsByTagName("tr")[0].parentNode.removeChild(element.getElementsByTagName("tr")[0]);
  }
}
  
/**
 * Metoda nastavi aktivni ikonu aktualniho razeni.
 *
 * @private 
 */  
filmografie.prototype.setSortIcon = function()
{
  switch (this.sort[0].toLowerCase())
  {
    case "rok":
      if (this.sort[1].toLowerCase() == "asc")
      {
        this.addClass(this.elSortRokASC, "selected"); 
      }
      else
      {
        this.addClass(this.elSortRokDESC, "selected");
      } 
      break;
      
    case "skore":
      if (this.sort[1].toLowerCase() == "asc")
      {
        this.addClass(this.elSortSkoreASC, "selected"); 
      }
      else
      {
        this.addClass(this.elSortSkoreDESC, "selected");
      }
      break;
      
    case "film":
      if (this.sort[1].toLowerCase() == "asc")
      {
        this.addClass(this.elSortFilmASC, "selected"); 
      }
      else
      {
        this.addClass(this.elSortFilmDESC, "selected");
      }
      break;
  }
}
  
/**
 * Metoda zrusi aktivitu ikonu aktualniho razeni.
 *
 * @private 
 */  
filmografie.prototype.unsetSortIcon = function()
{
  switch (this.sort[0].toLowerCase())
  {
    case "rok":
      if (this.sort[1].toLowerCase() == "asc")
      {
        this.removeClass(this.elSortRokASC, "selected"); 
      }
      else
      {
        this.removeClass(this.elSortRokDESC, "selected");
      } 
      break;
      
    case "skore":
      if (this.sort[1].toLowerCase() == "asc")
      {
        this.removeClass(this.elSortSkoreASC, "selected"); 
      }
      else
      {
        this.removeClass(this.elSortSkoreDESC, "selected");
      }
      break;
      
    case "film":
      if (this.sort[1].toLowerCase() == "asc")
      {
        this.removeClass(this.elSortFilmASC, "selected"); 
      }
      else
      {
        this.removeClass(this.elSortFilmDESC, "selected");
      }
      break;
  }
}
  




















/**
 * Objekt pro vlastni checkbox.
 * 
 * <p>Struktura vstupniho objektu:</p> 
 * <pre>
 *    element       - HTMLSpanElement - povinny, pokud neni definovana vlastnost id
 *                  - objekt html elementu span definujiciho checkbox
 *                  - v tomto pripade se nekontroluje nastaveni tridu checkbox u elementu 
 *    id            - string - povinny, pokud neni definovana vlastnost element
 *                  - identifikator kodu vastniho checkboxu (SPAN s tridou)
 *    disabled      - boolean - nepovinny
 *                  - priznak zneplatneni checkboxu pri inicializaci (true)  
 *    chbclass      - string - nepovinny
 *                  - trida definujici checkbox
 *    on            - string - nepovinny
 *                  - trida definujici zaskrtnuty checkbox
 *    off           - string - nepovinny
 *                  - trida definujici odskrtnuty checkbox
 *    disabledclass - string - nepovinny
 *                  - trida definujici zneplatneny checkbox  
 *    defaultvalue  - boolean - nepovinny
 *                  - vychozi hodnota checkboxu
 *    onclick       - function - nepovinny
 *                  - uzivatelska funkce volana po kliku na checkbox
 *    onchange      - function - nepovinny
 *                  - uzivatelska funkce volana po zmene hodnoty checkboxu    
 * </pre>
 * 
 * @example Typicke pouziti s ID
 *  var chb0 = new checkbox( {id:"chb0"} );
 *  // &lt;span id="chb0" class="checkbox on"&gt;Typicke&lt;/span&gt;
 *  // &lt;span id="chb0" class="checkbox"&gt;Minimalni&lt;/span&gt;
 *  
 * @example Typicke pouziti s odkazem na element
 *  var chb = new checkbox( {element:document.getElementById("chb")} ); 
 *  
 * @example Pouziti s jinymi tridami
 *  var chb1 = new checkbox( {id:"chb1", chbclass:"zaskrtitko", on:"zaskrtnuto", off:"odskrtnuto", disabledclass:"sede"} );
 *  // &lt;span id="chb1" class="zaskrtitko zaskrtnuto"&gt;Zaskrtnuty checkbox&lt;/span&gt;
 *  
 * @example Pri inicializaci nastaveno na vzdy true
 *  var chb2 = new checkbox( {id:"chb2", defaultvalue:true} );
 *  //  &lt;span id="chb2" class="checkbox off"&gt;Presto po inicializaci zaskrtnuto&lt;/span&gt;
 *
 * @example Pri inicializaci zneplatneno
 *  var chb2 = new checkbox( {id:"chb2", disabled:true} );
 *  //  &lt;span id="chb2" class="checkbox off"&gt;Po inicializaci zneplatneno&lt;/span&gt;
 *     
 * @example S vlastni obsluhou pri zmene hodnoty
 *  function fnct(obj)
 *  {
 *     alert("Hi " + obj.value); 
 *  }
 *  var chb3 = new checkbox( {id:"chb3", onchange: fnct} );   
 *  
 * @example S vlastni obsluhou checkboxu (hodnotu lze zmenit jen trikrat)
 *  var i = 0;
 *  function fnct(obj)
 *  {
 *    i = i + 1;
 *    if (i > 3) return false;
 *    alert(i + ". zmena"); 
 *  }
 *  var chb4 = new checkbox( {id:"chb4", onclick: fnct} ); 
 *   
 * @class checkbox - obsluha vlastniho checkboxu
 * @extends cfn
 * @version 2.0
 * @constructor
 * @requires events Udalosti  
 * @param {object} p Objekt vstupnich parametru
 */
function checkbox(p)
{
  /*deb*/
  /**
   * Priznak vypisovani debug informaci. Je-li hodnota true, vypisuji se debug informace objektu.
   * @type boolean
   * @private      
   */     
  this.debug = false;
  /*deb*/
  
  /**
   * Priznak, zda byl objekt jiz plne inicializovan -> zda lze tedy volat externi udalosti
   * @type boolean
   * @private      
   */     
  this.inicialize = false;
  
  /**
   * Element checkboxu
   * @type object HTMLSpanElement
   * @private
   */     
  this.el = null;
  
  /**
   * Hodnota checkboxu.
   *  - true -> zaskrtnuto
   *  - false -> odskrtnuto 
   * @type boolean
   * @public      
   */     
  this.value = false;
  
  //nalezeni elementu checkboxu
  if ((p) && (typeof(p.element) == "object") && (p.element instanceof HTMLSpanElement) )
  {
    this.el = p.element;
  }
  else
  {
    //nalezeni elementu checkboxu podle ID, jinak konec
    if ((!p) || (typeof(p.id) != "string") ) return; 
    this.el = document.getElementById(p.id);
    if (this.el == null) return;
    if (this.el.tagName.toUpperCase() != "SPAN") return;
  }

  /**
   * Trida definujici checkbox.<br />
   * <i>Lze nastavit jine hodnoty pri inicializaci objektu vlastnosti chbclass vstupniho objektu.</i><br />
   * Vychozi hodnota: "checkbox"
   * @type string
   * @private
   */
  this._chbClass = "checkbox";
  if ( (p.chbclass != null) && (typeof(p.chbclass) == "string") && (p.chbclass != "") )
  {
    this._chbClass = p.chbclass;
  }
  
  if (! this.hasClass(this.el, this._chbClass) ) return;    //element checkboxu neni checkbox...
  
  /**
   * Trida definujici zaskrtnuty checkbox.<br />
   * <i>Lze nastavit jine hodnoty pri inicializaci objektu vlastnosti on vstupniho objektu.</i><br />
   * Vychozi hodnota: "on"
   * @type string
   * @private
   */
  this._on = "on";
  if ( (p.on != null) && (typeof(p.on) == "string") && (p.on != "") )
  {
    this._on = p.on;
  }
  
  /**
   * Trida definujici odskrtnuty checkbox.<br />
   * <i>Lze nastavit jine hodnoty pri inicializaci objektu vlastnosti off vstupniho objektu.</i><br />
   * Vychozi hodnota: "off"
   * @type string
   * @private
   */    
  this._off = "off";
  if ( (p.off != null) && (typeof(p.off) == "string") && (p.off != "") )
  {
    this._off = p.off;
  }
  
  /**
   * Trida definujici nepristupny checkbox.<br />
   * <i>Lze nastavit jine hodnoty pri inicializaci objektu vlastnosti disabledClass vstupniho objektu.</i><br />
   * Vychozi hodnota: "disabled"
   * @type string
   * @private
   */    
  this._disabled = "disabled";
  if ( (p.disabledclass != null) && (typeof(p.disabledclass) == "string") && (p.disabledclass != "") )
  {
    this._disabled = p.disabledclass;
  }

  /**
   * Hodnota (boolean) definujici vychozi hodnotu checkboxu nezavisle na hodnote nastavene tridou v kodu.<br />
   * <i>Lze nastavit jine hodnoty pri inicializaci objektu vlastnosti defaultvalue vstupniho objektu.</i><br />
   * Vychozi hodnota: null - pouzit hodnotu z kodu (pokud tam zadna neni => false)
   * @type mixed
   * @private
   */
  this._defaultValue = null;
  if ( (p.defaultvalue != null) && (typeof(p.defaultvalue) == "boolean") )
  {
    this._defaultValue = p.defaultvalue;
  }

  /**
   * Uzivatelska funkce, ktera se vola po kliknuti na checkbox. Vola se jeste pred provedenim zmeny hodnoty checkboxu.<br />
   * <i>Lze ji nastavit inicializaci objektu vlastnosti onclick vstupniho objektu.</i><br />   
   * Vychozi hodnota: null -> zadna funkce<br />
   * Tato funkce se vola z obluzne funkce udalosti a pokud jiz nema dojit ke zmene stavu checkboxu a jeho prekresleni, musi uzivatelska funkce vratit hodnotu 'false'.
   * <br />   
   * <b>Ponamka:</b> Uzivatelske funkci se predava jeden parametr - ukazatel na instanci objektu checkbox, ve ktere byla vygenerovana udalost.      
   * @type function
   * @private
   */
  this._onClick = null;
  if ( (p.onclick != null) && (typeof(p.onclick) == "function") )
  {
    this._onClick = p.onclick;
  }

  /**
   * Uzivatelska funkce, ktera se vola po zmene hodnoty objektu checkboxu.<br />
   * <i>Lze ji nastavit inicializaci objektu vlastnosti onchange vstupniho objektu.</i><br />
   * Vychozi hodnota: null -> zadna funkce.
   * <br />   
   * <b>Ponamka:</b> Uzivatelske funkci se predava jeden parametr - ukazatel na instanci objektu checkbox, ve ktere byla vygenerovana udalost.   
   * @type function
   * @private
   */
  this._onChange = null;
  if ( (p.onchange != null) && (typeof(p.onchange) == "function") )
  {
    this._onChange = p.onchange;
  }
  
  
  //pokud je nastavena default hodnota, ignorovat nastaveni z kodu a nastavit tuto hodnotu
  if (this._defaultValue != null)
  {
    this.value = this._defaultValue;  //nastavit vychozi hodnotu
    
    this.removeClass(this.el, this._on);  //zrusit pripadne nastaveni v html kodu
    this.removeClass(this.el, this._off);
    
    this.setValue();  //zobrazit sravny stav
    
    /*deb*/
    this.deb("'" + p.id + "' - init default value:" + this.value.toString())
    /*deb*/
  }
  else
  {
    if (this.hasClass(this.el, this._on))
    {
      this.value = true;
    }
    else
    {
      //hodnota uz je nastavena na false
      this.setValue();  //priradit spravne tridy
    }
    
    /*deb*/
    this.deb("'" + p.id + "' - init value:" + this.value.toString());
    /*deb*/
  }
      
  events.addEventListener(this.el, "click", this.change, this);  //zavesit udalost
  
  /**
   * Hodnota (boolean) definujici pristupnost checkboxu.<br />
   * <i>Lze nastavit jine hodnoty pri inicializaci objektu vlastnosti disabled vstupniho objektu.</i><br />
   * Vychozi hodnota: false
   * @type boolean
   * @public
   */
  this.disabled = null;
  if ( (p.disabled != null) && (typeof(p.disabled) == "boolean") )
  {
    this.disabled = p.disabled;
  }
  if (this.disabled == null)
  { //pokud neni disabled definovan ve vstupni objektu, zkus zjistit, zda prvek nema nastavenou tridu
    if (this.hasClass(this.el, this._disabled))
    {
      this.disabled = true;
    }
    else
    {
      this.disabled = false;
    }
  }
  if (this.disabled == true) this.disable();  //je-li checkbox disabled, nastav ho tak
  
  this.inicialize = true;   //objekt je jiz inicializovan
}

//checkbox je rozsirenim objektu cfn
checkbox.prototype = new cfn;

/*deb*/
/**
 * Redefinice metody deb pro vypisovani debug zprav.
 *
 * @param {mixed} text Obsah poslany do debug okna 
 * @private
 */    
checkbox.prototype.deb = function(text)
{
  if (this.debug)
  {
    //volej predka s prefixem
    cfn.prototype.deb.call(this, text, "checkbox-> ");
  } 
}
/*deb*/


/**
 * Metoda je volana pri kliknuti na objekt checkboxu a meni stav checkboxu.
 * <br /><br />
 * Pred zmenou hodnoty a prekresleni muze volat uzivatelskou funkci.  
 *
 * @param {object event} e Udalostni objekt, ktery predava jadro obsluznym funkcim (ev. se ziskava jinak) 
 * @private
 * @see checkbox#_onClick
 */
checkbox.prototype.change = function(e)
{  
  if (!e) var e = window.event;

  ret = null;   //navratova hodnota uzivatelske funkce

  if (this.disabled == false)
  {
    if (this.inicialize)
    { //externi funkce volat jen v pripade plne inicializace objektu
      if (this._onClick != null) ret = this._onClick.call(null, this);
    }
    if (ret == false)
    {
      //nic nedelat, uzivatelska funkce to zakazala
    }
    else
    {
      this.value = !this.value;   //inverze hodnoty
    
      this.setValue();    //zobraz hodnotu
    }
  }
    
  //zrusit dalsi probublavani udalosti
  e.cancelBubble = true;
  if (e.stopPropagation) e.stopPropagation();
}

/**
 * Metoda nastavi hodnotu checkboxu.
 * <br /><br />
 * Po zmene hodnoty muze volat externi funkci.
 * <br /><br />
 * Pokud neni zadana hodnota status, nastavi aktualni hdonotu checkboxu definovanou v objektu ({@link checkbox#value}).  
 *   
 * @param {boolean} status Pozadovana hodnota nastaveni checkboxu - true->zaskrtnout/false->odskrtnout 
 * @public
 * @see checkbox#onChange  
 */
checkbox.prototype.setValue = function(status)
{
  if (status == null) status = this.value;
  
  if (status)
  { //zaskrtni zaskrtitko
    this.removeClass(this.el, this._off); //zrus pripadnou tridu OFF
    this.addClass(this.el, this._on);     //nastav tridu ON
  }
  else
  { //odskrtni zaskrtitko
    this.removeClass(this.el, this._on); //zrus pripadnou tridu ON
    this.addClass(this.el, this._off);   //nastav tridu OFF
  }
  
  /*deb*/
  this.deb("set " + status.toString());
  /*deb*/
  
  if (this.inicialize)
  { //externi funkce volat jen v pripade plne inicializace objektu
    var ret = [this, "1", "2"];
    if (this._onChange != null) this._onChange.apply(null, ret);
    //if (this._onChange != null) this._onChange.call();
  }
}

/**
 * Metoda nastavi checkbox jako neplatny.  
 * 
 * @public
 * @see checkbox#enable
 */
checkbox.prototype.disable = function()
{
  this.removeClass(this.el, this._off); //zrus pripadnou tridu OFF
  this.removeClass(this.el, this._on); //zrus pripadnou tridu ON
  this.addClass(this.el, this._disabled);   //nastav tridu DISABLED
  
  this.disabled = true;
}

/**
 * Metoda nastavi checkbox jako platny a obnovi hodnotu pred zneplatnenim.  
 * 
 * @public
 * @see checkbox#disable
 */
checkbox.prototype.enable = function()
{
  this.removeClass(this.el, this._disabled); //zrus tridu DISABLED
  
  if (this.value)
  {
    this.addClass(this.el, this._on);     //nastav tridu ON
  }
  else
  {
    this.addClass(this.el, this._off);   //nastav tridu OFF
  }
  
  this.disabled = false;
}
