/**
 * @fileoverview Zakladni objekty, metody a funkce pro projekt CFN/Kinobox
 * 
 * <ul> 
 *  <li>matersky objekt CFN</li>
 *  <li>rozsireni objektu OBJECT</li>
 *  <li>objekt events pro zpracovani udalosti</li>
 *  <li>objekt cfn_WINDOW pro hlasky jako nahrada window.open</li>
 *  <li>objekt browserDetect a clensky objekt plugins pro detekci prohlizece a schopnosti prohlizece</li>
 *  <li>objekt menu pro dynamickou hlavni navigaci</li>   
 *  <li>pracovni procedury a funkce</li> 
 * </ul>   
 * 
 * @author Oranges.s.r.o. & Laki <info@laki.cz>
 * @version 2.5 <15-09-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. 
 */
 
if (typeof autoinit == "undefined")
{
/**
 * Autoinit - objekt pro automatickou inicilaizaci objektu.
 *
 * <p>Automaticky inicializuje objekty. Definice de deje pomoci plneni pole autoinit.module.</p>
 * 
 * <p>Urceno pro pripadne prepsani autoinicializace podle potreb v kodu bez zasahu do knihoven.</p>
 * 
 * <p>Pokud se hned po vytvorni modulu vola metoda load, bude proveden pokus o inicializaci. Pokud se to nepovede, druhy pokus se provede v udalosti onload dokumentu.</p>
 * 
 * <p>Vsechny jeste neinicializovane moduly budou inicializovany v udalosti onload dokumentu</p>
 * 
 * <p>zapis zaznamu:</p>
 * <pre>
 *   autoinit.module["browserDetect"] = {variable: "browser", params: ["x1"]};
 *   kde:
 *      browserDetect
 *        - nazev inicializovaneho objektu
 *      variable 
 *        - globalni promenna inicializovaneho objektu
 *        - povinne 
 *      params 
 *        - pole parametru konstruktoru pri inicializaci
 *        - volitelne 
 *   pri inicializaci bude prevedeno na nasledujici kod:
 *      browser = new browserDetect(x1);       
 * </pre>         
 * 
 * @class autoinit - autoinicializace objektu
 * @version 1.0
 * @constructor
 */
  var autoinit = {module: []};
}

/**
 * Metoda pro inicializi objektu. Pokud se to nepovede, dalsi pokus se provede po nacteni dokumentu (udalost onload).
 *
 * @param {string} moduleName Nazev modulu, ktery se ma inicializovat (=hodnota objektu v poli module).
 * @memberOf autoinit
 */ 
autoinit.load = function(moduleName)
{
  for (var key in this.module)
  {
    if (key == moduleName)
    {
      var param = "";
      if (typeof this.module[key].params == "array")
      {
        for (var i=0; i<this.module[key].params.length; i++)
        {
          param += this.module[key].params[i];
          if (i < this.module[key].params.length-1) param += ", "; 
        }
      }
      try
      {
        eval(this.module[key].variable+" = new "+moduleName+"("+param+");");
        
        this.module[key].init = true;
      }
      catch (e)
      {
        //chyba, objet nelze inicializovat
      } 
    }
  }
}

/**
 * Metoda, ktera inicializuje zbyvajici moduly. Vola se po nacteni dokumentu.
 *
 * @memberOf autoinit 
 */ 
autoinit.onload = function()
{
  for (var key in this.module)
  {
    if ( (typeof this.module[key].init == "boolean") && (this.module[key].init == true) ) continue;
    this.load(key);
  }
}


/**
 * Matersky objekt projektu CFN. Obsahuje zakladni metody pro manipulaci s DOM, debug.
 *
 * <p>Vsechny vykonne objekty projektu jsou potomky tohoto objektu:</p>
 * 
 * @example
 *  novy = function() {}                //konstruktor objektu novy
 *  novy.prototype = new.cfn;           //rozsireni o cfn
 *  novy.prototype.fnct = function();   //prirazeni nove funkce objektu novy
 *  
 * @class cfn - zakladni podpurne metody - vzdy dostupne
 * @extends Object
 * @version 1.0  
 * @constructor 
 */ 
function cfn()
{ 
  /**
   * Objekt okna DEBUG  
   * @type object window  
   */            
  this._debug = null; 
 
  /**
   * Parametry okna DEBUG. Pokud je treba upravit okno DEBUG, predefinuje se tato vlastnost.
   * @see window.open      
   * @type string
   * @constant   
   */ 
  this._debugParams = "width=650, height=350, top=0, left=0, scrollbars=1, location=0";     
}


/**
 * Metoda pro vytvareni DOM elementu, volitelne vcetne podrizeneho DOM text node tohoto noveho elementu.
 * 
 * <p>Struktura vstupniho objektu, povinna je jen vlastnost "el":</p>
 * <pre>  
 *    el    - string - nazev HTML elementu, ktery se ma vytvorit
 *    atr   - array  - pole atributu vytvareneho elementu
 *                   - kazdy prvek pole je dvouprvkove vnorene pole:
 *                       - [0] - nazev atributu
 *                       - [1] - hodnota atributu
 *                   - napr. [ ["title", "titulek"], ["class", "trida1 trida2"], ["href", "file1.html"] ]  
 *    txt   - string - vytvorenemu elementu vlozi textnode s textem txt
 *    cls   - string - definice tridy (pouziva prime prirazeni className oproti atr, ktere pouziva setAttribute)
 *    ins   - node   - objekt Node, kam se vlozi vytvoreny element metodou appendChild
 *    ass   - string - teto promenne priradi vytvoreny element (funkci eval)
 *    doc   - object - object document. Pokud je zadan, generuje se element v tomto kontextu dokumentu (pro praci s dokumentem v jinem okne nebo framu) 
 * </pre>
 *
 * @example <p>Vytvoreni elementu odkazu vcetne prirazeni tridy a stylu:</p> 
 *  var p = {
 *    el: "a",
 *    atr: [ ["class", "trida"], ["href", "#"], ["title", "popisek"], ["style", "color:red;"] ],
 *    txt: "Odkaz" };
 *  var element = this.ele(p);
 *   
 *  this.ins(element, document.body, true);   //vlozi element na zacatek dokumentu 
 *
 * @example <p>Vytvoreni elementu a jeho prime vlozeni na konec dokumentu:</p> 
 *  var p = { el: "div", txt: "Obsah", ins: document.body };
 *  this.ele(p);
 *  
 * @example <p>Vytvoreni elementu a jeho prime prirazeni</p>
 *  this.ele({ el: "span", ass: "this.elSpan" });
 *  this.elSpan.style.color = "red";  //rovnou s tim mohu pracovat       
 *  
 * @example <p>Vytvoreni prvku v novem okne</p>
 *  var w = window.open("", "okno", "width=300,height=100");
 *  this.ele({ el: "h1", txt: "Nadpis", ins: w.document.body, doc: w.document });
 * 
 * @member cfn 
 * @param {object} p Objekt s pozadovanymi parametry
 * @return {object Element} vygenerovany DOM element, jinak null
 * @type object Element 
 * 
 */ 
cfn.prototype.ele = function(p)
{    
  if (p.doc == null)
  {
    p.doc = document;
  }
  
  //vytvori element
  var element = p.doc.createElement(p.el);
  
  //nastavi atributy elementu
  if (p.atr)
  {
    for (var i=0; i<p.atr.length; i++)
    {
      if (document.all)
      {
        //IE musi mit nektere nazvy atributu v jinem formatu, nektere vubec neumi...jen vyber potrebneho, problemu je vice
        switch (p.atr[i][0])
        {
          case "style":
            element.style.cssText = p.atr[i][1];
            continue;
            break;
          case "class":
            element.className = p.atr[i][1];
            continue;
            break;
          case "accesskey":
            p.atr[i][0] = "accessKey"; break;
          case "cellpadding":
            p.atr[i][0] = "cellPadding"; break;
          case "cellspacing":
            p.atr[i][0] = "cellSpacing"; break;
          case "colspan":
            p.atr[i][0] = "colSpan"; break;
          case "rowspan":
            p.atr[i][0] = "rowSpan"; break;
          default:
            break;
        }
      }
      element.setAttribute(p.atr[i][0], p.atr[i][1]);
    }
  }
  
  //prida textnode
  if (p.txt)
  {
    element.appendChild(p.doc.createTextNode(p.txt));
  }
  
  //prida tridu
  if (p.cls)
  {
    element.className(p.cls);
  }
  
  //vlozi vytvoreny element do node nebo jej vrati
  if (p.ins)
  {
    p.ins.appendChild(element); 
  }
  
  //priradi element promenne
  if (p.ass)
  {
    eval(p.ass + " = element;");
    //p.ass = element;
  }
  
  return element;
}


/**
 * Metoda prida element do specifikovaneho node.
 * 
 * <p>Volitelny parametr referent specifikuje referenta, pred ktery se ma provest vlozeni. <i>Referent</i> musi byt node, ktery je potomkem node <i>parent</i>.</p>
 * <p>Je-li <i>referent</i></p> 
 * <ul>
 * <li>roven NULL, false nebo neni zadan, vlozi se element za vsechny existujici prvky perentu.</li>
 * <li>roven true, vlozi se element jako prvni prvek parentu.</li>
 * <li>potomek parent, vlozi se element pred tento prvek</li>   
 * </ul>   
 * 
 * @member cfn 
 * @see cfn#ele 
 * @param {object Node}  element  Node, ktery se ma vlozit
 * @param {object Node}  parent   Node, kam se to ma vlozit
 * @param {mixed}        referent Referencni objekt nebo specifikace vlozeni  
 */ 
cfn.prototype.ins = function(element, parent, referent)
{
  // volitelnost parametru
  if (typeof(referent) == "undefined") referent = null;
  
  if (referent == true)
  { //vkladat na zacatek
    if (parent.firstChild)
    { //jen pokud obsahuje nejake podrizene node
      referent = parent.firstChild;
    }
    else
    {
      referent = null;
    }
  }

  parent.insertBefore(element, referent); //vlozit
}


/**
 * Metoda vytvori DEBUG okno.
 * 
 * <p><i>Poznamka</i>:<br>
 * Navazuje metodu {@link cfn#debugKill} na udalost <i>unload</i>.</p>
 * <p>Privatni metoda. Pokud je pozadavek na jine debug okno, metodu predefinovat.</p>   
 * 
 * @member cfn
 * @private 
 * @requires events
 * @see cfn#debugKill 
 */
cfn.prototype.debugCreate = function()
{
  if (this._debug == null)
  {
    this._debug = window.open("", "debug", this._debugParams);
    this._debug.document.write("<html><head><title>DEBUG</title><style>div{border:1px solid black;background-color:#eee;margin:0;font-family:monospace;font-size:8pt;} pre.data{display:inline-block;margin:0px 4px 4px 84px;} span.time{display:inline-block;width:68px;text-align:right;padding:2px 4px 0 0;float:left;font-size:7pt;color:#aaa;}</style></head><body></body></html>");
    events.addEventListener(window, "unload", this.debugKill, this);
  }
}

/**
 * Metoda zavre DEBUG okno.
 * 
 * <p>Pokud je DEBUG okno otevreno, automaticky se provadi pri udalosti <i>unload</i> hlavniho okna.</p>  
 * 
 * @member cfn
 * @see cfn#debugCreate 
 */
cfn.prototype.debugKill = function(e)
{
  if (this._debug != null)
  {
    this._debug.close();
  }
}


/**
 * Metoda vypise DEBUG zpravu. Pokud neni jeste DEBUG okno, vytvori je.
 * 
 * <ul> 
 * <li>Je-li pozadovano vypsani pole, je vypsana cela struktura pole a hodnoty jednotlivych prvku</li>
 * <li>Je-li pozadovano vypsani objektu, vypisuji se nazvy vsech metod a vlastnosti (vcetne typu). Pouze prvni uroven.</li>
 * <li>Jinak je vstup preveden na string a vypise se hodnota.</li>
 * <li>Je-li definovan text <i>prefix</i>, pak bude pred vygenerovanou zpravu vypsan tento prefix.</li> 
 * </ul>
 *
 * @example
 *  this.deb("zprava");
 *  this.deb(this);
 *  this.deb(["a", "b", [1, 3, 5], "d"]);
 *  this.deb("abc", "Modul-> ");    //vypise "Modul-> abc"      
 *  
 * @param {mixed}  text   Obsah, ktery se ma vypsat do DEBUG konzole
 * @param {string} prefix Prefix vypisovany pred zpravu, volitelne
 * @since 2.4 parametr prefix 
 * @member cfn
 */
cfn.prototype.deb = function(text, prefix)
{
  /**
   * Funkce generuje text, ktery se vypise do konzole podle typu dat
   * 
   * name cfn#deb-write   
   * memberOf cfn#deb
   * @function   
   * @param {mixed} obj Obsah, ktery se ma zpracovat
   * @param {string} offset Odsazeni
   * @return {string} zformatovany text
   * @type string
   * @version 1.3   
   */          
  function write(obj, offset)
  {
   // if (this._debug == null) return;    //neotevrene debug okno
    
  
    if (offset == null) offset = "";
    offset += " ";
    
    if (obj instanceof Array)
    {
      var tmp = "array";
      for (var i=0; i<obj.length; i++)
      {
        tmp += "\r\n" + offset + "[" + i + "] = " + write(obj[i], offset);
      }
      return tmp;
    }
    //if (obj instanceof Object)
    if (typeof(obj) == "object")
    {
      var tmp = "object";
      for (i in obj)
      {
        switch (typeof(obj[i]))
        {
          case "function":
            tmp += "\r\n" + offset + "{function} " + i;
            break;
          case "object":
            tmp += "\r\n" + offset + "{object} " + i;
            break;
          case "array":
            tmp += "\r\n" + offset + "{array} " + i;
            break;
          default:  
            tmp += "\r\n" + offset + "{" + typeof(obj[i]) + "} [" + i + "] = " + obj[i];
        }    
      }
      return tmp;
    }
    return obj.toString();
  }

  //otestovat existenci otevreneho debug okna
  //je to dost kostrbate, ale reseni ounload na okne debug dela problemy s hlasenim bezpecnostnich hrozeb
  try
  {
    if (this._debug.document == null)
    { 
      this._debug = null; //Mozilla
    } 
  }
  catch (err)
  {
    this._debug = null;   //IE
  }

  this.debugCreate();   // vytvorit DEBUG okno, je-li treba

  text = write(text);   // vygenerovat text pro vypsani do konzole
  
  if (typeof(prefix) == "string") text = prefix + text; //pokud je definovan prefix, vypis ho napred
  
  try
  {
    var d = new Date();
      
    var p = {
      el: "div",
      doc: this._debug.document};
    var message = this.ele(p);
    
    // casove razitko
    var p = {
      el: "span",
      atr: [ ["class", "time"] ],
      txt: d.getHours() + ":" + d.getMinutes() + ":" + d.getSeconds() + ":" + d.getMilliseconds() + " ",
      doc: this._debug.document };
    this.ins(this.ele(p), message);
    
    // vypsani zpravy
    var p = {
      el: "pre", 
      atr: [ ["class", "data"] ],
      txt: text, 
      doc: this._debug.document };
    this.ins(this.ele(p), message);
  
    this.ins(message, this._debug.document.body, true);   //vlozit do dokumentu
  }
  catch (err)
  {
    //chyba zapisu do debug okna
  }
}


/**
 * Metoda nastavi text elementu
 * 
 * @example
 *  this.changeText(document.getElementById("prvek"), "text"); 
 *  
 * @member cfn
 * @param {object} element Element, kteremu se prirazuje text
 * @param {string} txt     Text
 */   
cfn.prototype.changeText = function(element, txt)
{
  var innertext = (document.getElementsByTagName("body")[0].innerText != undefined) ? true : false;
  if (!innertext)
  {
    element.textContent = txt;
  }
  else
  {
    element.innerText = txt;
  }
}

/**
 * Metoda vraci text elementu.
 *
 * @since 2.5 
 * <p>
 * <i>Upozorneni:</i></br>
 * Pokud ma objekt hodnotu null, vraci prazdny text! Zabranuje tak problemum s kontrolou existence vstupniho objektu.
 * </p>  
 * 
 * @example
 *  this.getText(document.getElementById("prvek")); 
 *  
 * @member cfn
 * @param {object} element Element, ze ktereho se vraci text
 * @return {string} Text elementu
 * @type string 
 */   
cfn.prototype.getText = function(element)
{
  if (element == null) return "";
  
  var innertext = (document.getElementsByTagName("body")[0].innerText != undefined) ? true : false;
  if (!innertext)
  {
    return element.textContent;
  }
  else
  {
    return element.innerText;
  }
}


/**
 * Metoda zjisti vypocitanou relativni pozici prvku na strance
 *
 * @example
 *  el.style.top = this.getPos(document.getElementById("id"))[0] + 10 + "px"; 
 *  
 * @member cfn
 * @param {object Element} obj Element, jehoz pozici zadame
 * @return {array} Pole souradnic [x, y]
 * @type array   
 */ 
cfn.prototype.getPos = function(obj)
{
  var curleft = curtop = 0;
  if (obj.offsetParent)
  {
    do
    {
      curleft += obj.offsetLeft;
      curtop += obj.offsetTop;
    }
    while (obj = obj.offsetParent);

    return [curleft,curtop];
  }
}


/**
 * Metoda, ktera prida textovou promennou.
 * 
 * Existuje-li jiz textova promenna, ponecha stavajici  
 *
 * @example
 *  this.addText(this.texts, "sort", "Setřídit"); 
 *  
 * @member cfn
 * @param {object} obj   Objekt textovych promennych
 * @param {string} text  Nazev textove promenne (priradi vlastnost tohoto nazvu objektu obj)
 * @param {mixed}  value Hodnota textove promenne (string nebo pole stringu)   
 */     
cfn.prototype.addText = function(obj, text, value)
{
  eval("if (!obj." + text + ") obj." + text + " = value;");
}


/**
 * Metoda prida elementu definici tridy, pokud ji jeste nema pridelenu
 *
 * @example
 *  this.addClass(document.getElementById("id"), "trida2"); 
 * 
 * @member cfn
 * @see cfn#removeClass
 * @see cfn#getClass
 * @see cfn#hasClass 
 * @param {object Element} element   Objekt elementu
 * @param {string}         className Nazev tridy   
 */    
cfn.prototype.addClass = function(element, className)
{
  var classes = (element.className) ? element.className : null;
  
  classes = (classes == null) ? [] : classes.split(" ");
    
  for (var i=0; i<classes.length; i++)
  {      
    if (classes[i].toLowerCase() == className.toLowerCase()) return;    //styl je jiz pritomen
  }
  classes.push(className);  //pridat tridu  
  element.className = classes.join(" "); 
}


/**
 * Metoda odebere elementu definici tridy, pokud ji ma pridelenou
 *
 * @example
 *  this.removeClass(document.getElementById("id"), "trida2");
 *
 * @member cfn
 * @see cfn#addClass
 * @see cfn#getClass
 * @see cfn#hasClass 
 * @param {object Element} element   Objekt elementu
 * @param {string}         className Nazev tridy   
 */     
cfn.prototype.removeClass = function(element, className)
{
  var classes = element.className;
  
  if (classes == null) return;
  
  classes = classes.split(" ");
  
  for (var i=0; i<classes.length; i++)
  {
    if (classes[i].toLowerCase() == className.toLowerCase()) classes.splice(i, 1);  //odstrani tridu
  }  
  element.className = classes.join(" ");
}

/**
 * Metoda vrati prirazene styly elementu
 *
 * Neni-li zadny styl definovan, vraci prazdny retezec. 
 * Vraci styly tak jak jsou definovane! Pokud jich je vic, je treba je parsovat.
 *  
 * @example
 *  this.deb("trida prvku ID: " + this.getClass(document.getElementById("id")); 
 * 
 * @member cfn
 * @see cfn#addClass
 * @see cfn#removeClass
 * * @see cfn#hasClass 
 * @param {object Element} element   Objekt elementu   
 */    
cfn.prototype.getClass = function(element)
{ 
  return element.className;
}

/**
 * Metoda vrati priznak prirazeni stylu elementu
 *  
 * @example
 *  if (this.hasClass(document.getElementById("id"), "trida")) alert("ma ji!"); 
 * 
 * @member cfn
 * @see cfn#addClass
 * @see cfn#removeClass
 * @see cfn#getClass   
 * @param {object Element} element   Objekt elementu   
 */
cfn.prototype.hasClass = function(element, className)
{
  var classes = (element.className) ? element.className : null;
  
  classes = (classes == null) ? [] : classes.split(" ");
  
  for (var i=0; i<classes.length; i++)
  {
    if (classes[i].toLowerCase() == className.toLowerCase()) return true;    //styl je nalezen
  }
  return false; 
}


/**
 * Rozsireni zakladniho objektu Object o metodu pro klonovani. Klonuje celou strukturu.
 * 
 * <p>Klonuje jen metody a vlastnosti, ktere nejsou read-only (Pozor na bezpecnosti opatreni IE!)</p>
 * 
 * @example
 *  var a = new Date();
 *  var b = a.clone();  //identicky objekt, zmenou nejake vlastnosti nebude dotcena tato vlastnost objektu a 
 * 
 * @addon Object 
 */
/*
 * Nelze pouzivat soucasne se scriptaculous a prototype v prohlizecich zalozenych na Firefox 2.5
Object.prototype.clone = function()
{
  var newObj = (this instanceof Array) ? [] : {};

  for (i in this)
  {
    if (i == 'clone') continue;
    if (typeof this[i] == "object" && this[i])
    {
      try
      {
        newObj[i] = this[i].clone();
      }
      catch(err)
      {
      }
    } 
    else
    {
      try
      {
        newObj[i] = this[i];
      }
      catch(err)
      {
      }
    }
  }
  return newObj;
};
*/

/******************************************************************************
 *  GLOBALNI PROMENNE A FUNKCE
 ******************************************************************************/ 

/**
 * Funkce pro klonovani objektu Image. Klonuje jen prime instance Image - nelze tedy pouzit na potomky objektu Image.
 *
 * <p>Nahrada Object.clone() pro klonovani objektu Image pro IE. Bezpecnostni model neumoznuje prototypovani.</p>
 * <p>Upraveny kod z http://my.opera.com/GreyWyvern/blog/show.dml/1725165, doplnen o osetreni readonly vlastnosti a metod</p> 
 *
 * @see Object#clone 
 * @param {object Image} obj instance objektu Image, ktery ma byt klonovan
 * @return {object Image} instance objektu Image, klon obj
 * @type object Image  
 */    
function cloneImage(obj)
{
  var newObj = new Image();

  for (i in obj)
  {
    if (typeof obj[i] == "object")
    {
      try
      {
        newObj[i] = obj[i].clone();
      }
      catch(err)
      {
        y = "";
      }
    } 
    else 
    {
      try
      {
        newObj[i] = obj[i];
      }
      catch(err)
      {
      }
    }
  }

  return newObj;
}

/**
 * Funkce pro serializaci XML DOM objektu do retezce.
 *
 * Pokud nelze objekt serializovat, vraci prazdny retezec. 
 * 
 * @param {object Node} node instance objektu Node, ktery ma byt serializovan
 * @return {string} serializovany objekt
 * @type string
 */
XMLserialize = function(node)
{
  if (typeof XMLSerializer != "undefined")
  { //Mozzila, Safari, Chrome, Opera
    return (new XMLSerializer()).serializeToString(node) ;
  }
  else 
  {
    if (node.xml) 
    { //IE
      return node.xml;
    }
    else
    { //neco jineho
      return "";  
    }
  }
};


/**
 * Definice objektu DOMParser a metody parseFromString pro IE, kde neexistuje.  
 */  
if (typeof(DOMParser) == 'undefined')
{ //IE
  DOMParser = function() {}
  
  /**
   * Metoda DOMParser.parseFromString emulujici stejnou metodu pro IE, kde neexistuje.
   * 
   * XML ve stringu predpoklada kodovani UTF-8.      
   *
   * @param {string} str string XML urceny k parsovani
   * @param {string} contentType Content type parsovaneho XML
   * @return {object Node} vysledek parsovani
   * @type node        
   */        
  DOMParser.prototype.parseFromString = function(str, contentType)
  {
    if(typeof(ActiveXObject) != 'undefined')
    {
      var xmldata = new ActiveXObject('MSXML.DomDocument');
      xmldata.async = false;
      xmldata.loadXML(str);
      return xmldata;
    }
    else
    { //pokud neni dostupna komponenta MSXML.DomDocument, lze emulovat pomoci AJAX
      if (typeof(XMLHttpRequest) != 'undefined')
      {
        var xmldata = new XMLHttpRequest;
        if (!contentType)
        {
          contentType = 'application/xml';
        }
        xmldata.open('GET', 'data:' + contentType + ';charset=utf-8,' + encodeURIComponent(str), false);
        if (xmldata.overrideMimeType)
        {
          xmldata.overrideMimeType(contentType);
        }
        xmldata.send(null);
        
        return xmldata.responseXML;
      }
    }
  }
}

/**
 * Funkce TRIM. Nahrada za nemoznost prototypovat objekt String -> kompatibilita s knihovnou Prototype.
 *
 * Kod je optimalizovan pro dlouhe stringy a nejvyssi rychlost zpracovani ve vsech prohlizecich:
 *    http://blog.stevenlevithan.com/archives/faster-trim-javascript
 * 
 * @param {string} str zdrojovy string
 * @return {string} string zbaveny bilych mezer na zacatku a konci zdrojoveho stringu
 * @type string
 */
function trim(str)
{
  str = str.replace(/^\s+/, '');
	for (var i = str.length - 1; i >= 0; i--)
  {
    if (/\S/.test(str.charAt(i)))
    {
      str = str.substring(0, i + 1);
      break;
		}
	}
	return str;
}


// konstanty
/**
 * Umisteni obrazku pro skripty.
 *
 * @constant
 * @type string  
 */
var _imageDirectory = "/image/scripts/"; 

/*****************************************************************************
 *   Objekt plugins
 ******************************************************************************/ 

/**
 * Objekt plugins pro detekci instalovanych a dostupnych pluginu.
 *
 * <p>Detekuje dostupnost pluginu v prohlizeci a pristomnost a pouzitelnost jazyka Java.</p>
 * 
 * <p>Tento objekt je automaticky inicializovany a dostupny jako instance "plugins" pri inicializaci objektu {@link browserDetect}. Bezne s tim tedy bude pracovano pres instanci "browser.plugins". Konstruktor pouze inicializuje pracovni promenne.</p>
 *
 * <p><i>Poznamka</i>:<br>
 * Testuje pouze pritomnost Javy. Verzi Java Runtime Environment(JRE) nedetekuje, protoze na nekterych prohlizecich toto neni mozne (IE apod. nebo nelze zjistit presne) a musi se to delat vlozenim specialniho Appletu, ze ktereho se teprve po inicializaci precte verze. To je uz nad ramec potreb pro projekt CFN/Kinobox.<br>
 * Doporuceny kod v pripade potreby zjisteni verze JRE: <a href="http://www.builtfromsource.com/2007/06/26/detecting-plugins-in-internet-explorer-and-a-few-hints-for-all-the-others/#java-runtime-environment">http://www.builtfromsource.com/2007/06/26/detecting-plugins-in-internet-explorer-and-a-few-hints-for-all-the-others/#java-runtime-environment</a></p>
 *  
 * @class plugins - detekce pluginu prohlizece - vzdy dostupne
 * @version 1.0  
 * @constructor 
 */
function plugins()
{
  //pridat definicnimu poli testovacich objektu vlastnosti version s vychozi hodnotou
  for (var i=0; i<this.PLUGINS.length; i++)
  {
    this.PLUGINS[i].version = null;
  }
}

/**
 * Vyhleda a vraci definici testovaciho objektu.
 * 
 * @private
 * @param {string} name Nazev definicniho objektu 
 * @return {object} definicni objekt z pole {@link plugins#PLUGINS}
 * @type object
 */  
plugins.prototype.getPluginType = function(name)
{
  for (var i=0; i<this.PLUGINS.length; i++)
  {
    if (name.toLowerCase() == this.PLUGINS[i].plugin.toLowerCase()) return this.PLUGINS[i];
  }
  return null;
}

/**
 * Testuje pritomnost pluginu.
 * 
 * Pokud jiz test probehl, lze najit vysledek v definicnim objektu ve vlastnosti version. Pokud jeste teste neprobehl, nebo je nastaven parametr reload na hodnotu true, pak se provede test a tato vlastnost se nastavi a vrati.   
 *
 * @private 
 * @param {string}  name   Nazev testovaneho pluginu, viz {@link plugins#PLUGINS}.name  
 * @param {boolean} reload Nepovinny. Pokud je true, bude vzdy testovat, jinak vraci predchozi vysledek testu, byl-li jiz proveden.
 * @return {boolean} priznak pritomnosti pluginu
 * @type boolean 
 */
plugins.prototype.isPluginInstalled = function(name, reload)
{
  var o = this.getPluginType(name);
  if (o == null) return false;  //nelze zjistit, neexistuje definice prohledavani

  if ((o.version == null) || (reload == true))
  {
    var version = this.searchPlugin(o);   //detekuje plugin a vraci jeho verzi

    if (version == null)  //detekce neprobehla v poradku
    {
      o.version = null;
      return false;
    }
    else
    {
      o.version = version;  //uloz verzi
      return true;
    }
  }
  else
  {
    return true;
  }
}

/**
 * Vraci verzi pluginu.
 * 
 * <p>Pokud jiz test probehl, vraci predchozi vysledek. Pokud jeste teste neprobehl, nebo je nastaven parametr reload na hodnotu true, pak se provede novy test pluginu.</p>
 * <p>Pokud je vysledkem hodnota null, nelze tento plugin detekovat (tj. chybi definice detekce v poli {@link plugins#PLUGINS}).</p> 
 * <p>Vraci plnou textovou prezentaci verze, ktera byla detekovana. Napr. 10.0.2.5, 1.2 r3 ci 2.1beta. Oddeleni subverzi je vzdy prevedeno na tecku.</p>
 * <p>Tip: pokud staci zjistit jen hlavni verzi a prvni subverzi, staci vracenou verzi prohnat funci parseFloat().</p>
 *
 * @private 
 * @param {string}  name   Nazev testovaneho pluginu, viz {@link plugins#PLUGINS}.plugin
 * @param {boolean} reload Nepovinny. Pokud je true, bude vzdy testovat, jinak vraci predchozi vysledek testu, byl-li jiz proveden.
 * @return {string} plna verze pluginu, pokud ji nelze zjistiti, vraci "n/a"
 * @type boolean 
 */
plugins.prototype.verPlugin = function(name, reload)
{
  var o = this.getPluginType(name);
  if (o == null) return null;  //nelze zjistit, neexistuje definice prohledavani
  
  if ((o.version == null) || (reload == true))
  {
    this.isPluginInstalled(name, true);
  }
  
  return o.version;
}

/**
 * Hleda existenci pluginu v prohlizeci.
 * 
 * Pokud je definovana funkce pro vyhledani verze pluginu, vyhledaji ji, jinak vraci "n/a" - nespecifikovana verze.
 * 
 * <p><i>Poznamka</i>:<br> 
 * Prohlizece IE nevraceji kolekci nainstalovanych pluginu a je nutne se pokusit je inicializovat jako ActiveX objekty. To muze mit za nasledek nektere hlaseni a detekce trva delsi dobu.</p>
 * 
 * @private
 * @param {object} o Definicni objekt hledani pluginu {@link plugins#PLUGINS}.plugin
 * @return {string} verze pluginu
 * @type string   
 */   
plugins.prototype.searchPlugin = function(o)
{
  if (navigator.plugins && (navigator.plugins.length > 0))
  { //non IE
    for(var i=0; i<navigator.plugins.length; ++i)
    {
      var plugin = navigator.plugins[i];
      if (plugin.name.indexOf(o.name) != -1)
      { //plugin nalezen, zkus detekovat verzi
        if (typeof(o.getVersion) == "function") 
        {
          try
          {
            var version = o.getVersion(plugin);
            if ((typeof(version) == "string") && version != "") return version;
          }
          catch (e) { }
        }
        
        return "n/a"; //neni definovan zpusob detekce verze nebo nebyla vracena verze, vrat neznamou verzi
      }
    }
    return null;
  }
  else
  { //IE
    //pokud neni progID pole, prevest na pole
    if (o.progID.constructor == Array)
    {
      var progID = o.progID;
    }
    else
    {
      var progID = [o.progID];
    }
  
    var control = null;
    for (var i=0; i<progID.length; i++)
    { //projit vsechny eventualni progID, ktere program pouziva/pouzival
      try
      {
        control = new ActiveXObject(progID[i]);
      }
      catch (e) { } //objekt se nepodarilo iniciovat -> neni nainstalovan nebo nefunguje
      if (control);
      { //objekt se povedlo iniciovat, zjisti verzi a vrat ji
        if (typeof(o.getVersionActiveX) == "function")
        {
          try
          {
            var _version = o.getVersionActiveX(control);
            if ((typeof(_version) == "string") && _version != "") return _version;
          }
          catch (e) {}
        }
        
        return "n/a"; //neni definovan zpusob detekce verze, vrat verzi neznamou verzi
      }
    }
  }
  return null;
}

/**
 * Testuje vsechny definovane pluginy v poli {@link plugins#PLUGINS} a vraci pole objektu s vysledky testu.
 * Pokud byl jiz plugin testovan, vraci vzdy vysledek predchoziho testu, aby se usetril potrebny cas. 
 * 
 * <pre>
 * Vracene pole obsahuje jeden zaznam pro kazdy definovany plugin. Kazdy tento 
 * zaznam obsahuje pole teto struktury:
 *    plugin    {string} Nazev pluginu (identicky s plugins.PLUGINS.plugin)
 *    installed {string} Priznak, zda je plugin instalovan
 *    version   {string} Verze pluginu, pokud ji lze indentifikovat
 * </pre>
 *     
 * <p><i>Poznamka</i>:<br>
 * Detekce vsech pluginu v prohlizecich Internet Explorer muze trvat dost dlouhou dobu kvuli pokusu o inicializaci mnoha ActiveX objektu!</p>   
 *
 * @private
 * @return {array of object} Pole s informacemi o instalovanych pluginech
 * @type array of object 
 */  
plugins.prototype.getPlugins = function()
{
  var a = new Array;
  
  for (var i=0; i<this.PLUGINS.length; i++)
  {
    a.push( {
      plugin: this.PLUGINS[i].plugin,
      installed: this.isPluginInstalled(this.PLUGINS[i].plugin), 
      version: this.verPlugin(this.PLUGINS[i].plugin)
       });
  }

  return a;
}

/**
 * Metoda pro test pritomnosti Java Runtime Environment (JRE).
 *  
 * @public
 * @return {boolean} priznak pritomnosti JRE  
 * @type boolean     
 */
plugins.prototype.isJava = function()
{
  return navigator.javaEnabled();
}

/**
 * Pole definicnich objektu pro testovani pluginu.
 *
 * <pre> 
 * Kazdy prvek pole je jeden definicni objekt s udaji pro hledani jednoho pluginu.
 * Struktura je nasledujici:
 *    plugin             - Nazev pluginu (tim se definuje v kodu)
 *    name               - Hledany string v nazvu pluginu (pro nonIE)
 *    progID             - Nazev nebo pole nazvu programoveho/programovych ID ActiveX prvku pluginu (pro IE)
 *    getVersion:        - Funkce pro zjisteni verze pluginu (pro nonIE)
 *                       - vstupni parametr je objekt plugin, clen kolekce navigator.plugins
 *                       - funkce musi vracet string zjistene verze
 *                       - volitelne, jinak vraci verzi "n/a"
 *    getVersionActiveX  - Funkce pro zjisteni verze pluginu (pro IE)
 *                       - vstupni parametr je inicializovana instance ActiveX objektu
 *                       - funkce musi vracet string zjistene verze 
 *                       - volitelne, jinak vraci verzi "n/a"
 * </pre>
 * 
 * @private 
 * @type array of objects
 */
plugins.prototype.PLUGINS = [
  {
    plugin: "Adobe Acrobat Reader",
    name: "Adobe Acrobat",
    progID: ["PDF.PdfCtrl", "AcroPDF.PDF"],
    getVersionActiveX: function(o){return o.GetVersions().split(",")[0].split("=")[1];}
  },
  {
    plugin: "QuickTime Player",
    name: "QuickTime",
    progID: ["QuickTimeCheckObject.QuickTimeCheck", "QuickTimeCheckObject.QuickTimeCheck.1", "QuickTime.QuickTime"],
    getVersionActiveX: function(o){var v=o.QuickTimeVersion.toString(16); return v.substring(0,1)+"."+v.substring(1,2)+"."+v.substring(2,3);},
    getVersion: function(o){return o.name.replace(/^[^\d]*/,"");}
  },
  {
    plugin: "Flash Player",
    name: "Shockwave Flash",
    progID: ["ShockwaveFlash.ShockwaveFlash"],
    getVersionActiveX: function(o){return o.GetVariable("$version").substring(4).replace(/,/g, ".");},
    getVersion: function(o){return o.description.replace("Shockwave Flash ", "");}
  },
  {
    plugin: "Real Player",
    name: "RealPlayer Version Plugin",
    progID: ["RealPlayer", "rmocx.RealPlayer G2 Control", "RealPlayer.RealPlayer(tm) ActiveX Control (32-bit)", "RealVideo.RealVideo(tm) ActiveX Control (32-bit)"],
    getVersionActiveX: function(o){return o.GetVersionInfo();},
    getVersion: function(o){return o.description;}
  },
  {
    plugin: "Shockwave Player",
    name: "Shockwave for Director",
    progID: "SWCtl.SWCtl",
    getVersionActiveX: function(o){return o.ShockwaveVersion("");},
    getVersion: function(o){return o.description.replace(/^[^\d]*/,"");}
  },
  {
    plugin: "Windows Media Player",
    name: "Windows Media Player",
    progID: "WMPlayer.OCX",
    getVersionActiveX: function(o){return o.versionInfo;}
  },
  {
    plugin: "Silverlight",
    name: "Silverlight Plug-In",
    progID: "AgControl.AgControl",
    getVersionActiveX: function(o){if (o.IsVersionSupported("3.0")) return "3.0"; if (o.IsVersionSupported("2.0")) return "2.0"; if (o.IsVersionSupported("1.0")) return "1.0";},
    getVersion: function(o){return o.description;}
  },
  {
    plugin: "VLC",
    name: "VLC Multimedia Plug-in",
    progID: "VideoLAN.VLCPlugin.2",
    getVersionActiveX: function(o){var r=new RegExp(/[\d.]*/); return r.exec(o.versionInfo)[0];},
    getVersion: function(o){var r=new RegExp(/[\d.]*/); return r.exec(o.description.replace(/Version /, ""))[0];}
  },
  {
    plugin: "Adobe SVG Viewer",
    name: "SVG Viewer",
    progID: "Adobe.SVGCtl",
    getVersionActiveX: function(o){return o.getSVGViewerVersion().replace(/Adobe; /, "");} 
  },
  {
    plugin: "DivX Web Player",
    name: "DivX Web Player",
    progID: "npdivx.DivXBrowserPlugin",
    getVersionActiveX: function(o){return o.getVersion()},
    getVersion: function(o){return o.description.replace(/^[^\d]*/,"")}
  },
  {
    plugin: "Windows Presentation Foundation",
    name: "Windows Presentation Foundation",
    progID: "Environment.CodeGroupCreator1"
  }
];


/*
  definice verejnych metod pro detekci pritomnosti pluginu
    - kazdy plugin definovany v poli plugins. PLUGINS by melo mit vlastni verejnou detekcni metodu
*/

/**#@+
 * @public
 * @param {boolean} reload Nepovinny. Pokud je true, bude vzdy testovat, jinak vraci predchozi vysledek testu, byl-li jiz proveden.
 * @return {boolean} priznak pritomnosti pluginu
 * @see plugins#isPluginInstalled   
 * @type boolean     
 */
/** Test pritomnosti pluginu Adobe Acrobat Reader. */
plugins.prototype.isAdobeAcrobatReader = function(reload)
{
  return this.isPluginInstalled("Adobe Acrobat Reader", reload);
}
/** Test pritomnosti pluginu QuickTime Player. */
plugins.prototype.isQuickTime = function(reload)
{
  return this.isPluginInstalled("QuickTime Player", reload);
}
/** Test pritomnosti pluginu Flash Player. */
plugins.prototype.isFlash = function(reload)
{
  return this.isPluginInstalled("Flash Player", reload);
}
/** Test pritomnosti pluginu Real Player. */
plugins.prototype.isRealPlayer = function(reload)
{
  return this.isPluginInstalled("Real Player", reload);
}
/** Test pritomnosti pluginu Shockwave Player. */
plugins.prototype.isShockwave = function(reload)
{
  return this.isPluginInstalled("Shockwave Player", reload);
}
/** Test pritomnosti pluginu Windows Media Player. */
plugins.prototype.isWMP = function(reload)
{
  return this.isPluginInstalled("Windows Media Player", reload);
}
/** Test pritomnosti pluginu Silverligh. */
plugins.prototype.isSilverlight = function(reload)
{
  return this.isPluginInstalled("Silverlight", reload);
}
/** Test pritomnosti pluginu VLC Media Player. */
plugins.prototype.isVLC = function(reload)
{
  return this.isPluginInstalled("VLC", reload);
}
/** Test pritomnosti pluginu Adobe SVG Player. */
plugins.prototype.isSVGViewer = function(reload)
{
  return this.isPluginInstalled("Adobe SVG Viewer", reload);
}
/** Test pritomnosti pluginu DivX Web Player. */
plugins.prototype.isDivXPlayer = function(reload)
{
  return this.isPluginInstalled("DivX Web Player", reload);
}
/** Test pritomnosti podpory WPF. */
plugins.prototype.isWPF = function(reload)
{
  return this.isPluginInstalled("Windows Presentation Foundation", reload);
}
/**#@-*/


/*
  definice verejnych metod pro detekci verze pluginu
    - kazdy plugin definovany v poli plugins. PLUGINS by melo mit vlastni verejnou detekcni metodu
*/

/**#@+
 * @public
 * @param {boolean} reload Nepovinny. Pokud je true, bude vzdy testovat, jinak vraci predchozi vysledek testu, byl-li jiz proveden.
 * @see plugins#verPlugin 
 * @return {string} Verze pluginu  
 * @type string
 */
/** Metoda pro zjisteni verze pluginu Adobe Acrobat Reader. */
plugins.prototype.verAdobeAcrobatReader = function(reload)
{
  return this.verPlugin("Adobe Acrobat Reader", reload);
}
/** Metoda pro zjisteni verze pluginu QuickTime Player. */
plugins.prototype.verQuickTime = function(reload)
{
  return this.verPlugin("QuickTime Player", reload);
}
/** Metoda pro zjisteni verze pluginu Flash Player. */
plugins.prototype.verFlash = function(reload)
{
  return this.verPlugin("Flash Player", reload);
}
/** Metoda pro zjisteni verze pluginu Real Player. */
plugins.prototype.verRealPlayer = function(reload)
{
  return this.verPlugin("Real Player", reload);
}
/** Metoda pro zjisteni verze pluginu Shockwave Player. */
plugins.prototype.verShockwave = function(reload)
{
  return this.verPlugin("Shockwave Player", reload);
}
/** Metoda pro zjisteni verze pluginu Windows Media Player. */
plugins.prototype.verWMP = function(reload)
{
  return this.verPlugin("Windows Media Player", reload);
}
/** Metoda pro zjisteni verze pluginu Silverligh. */
plugins.prototype.verSilverlight = function(reload)
{
  return this.verPlugin("Silverlight", reload);
}
/** Metoda pro zjisteni verze pluginu VLC Media Player. */
plugins.prototype.verVLC = function(reload)
{
  return this.verPlugin("VLC", reload);
}
/** Metoda pro zjisteni verze pluginu Adobe SVG Viewer. */
plugins.prototype.verSVGViewer = function(reload)
{
  return this.verPlugin("Adobe SVG Viewer", reload);
}
/** Metoda pro zjisteni verze pluginu DivX Web Player. */
plugins.prototype.verDivXPlayer = function(reload)
{
  return this.verPlugin("DivX Web Player", reload);
}
/** Metoda pro zjisteni verze pluginu pro WPF. */
plugins.prototype.verWPF = function(reload)
{
  return this.verPlugin("Windows Presentation Foundation", reload);
}
/**#@-*/


/******************************************************************************
 *   Objekt BROWSERDETECT
 ******************************************************************************/ 

/**
 * Objekt browserDetect pro detekci prohlizece.
 *
 * <p>Detekuje nazev a verzi prohlizece, definuje testovaci vlastnosti pro soucasne
 * nejpouzivanejsi prohlizece a nastavuje nektere pracovni vlastnosti zavisle
 * na verzi prohlizece.</p>
 * 
 * <p>Tento objekt je automaticky inicializovany a dostupny jako instance "browser".</p>
 * 
 * <p>Vystaveno na zakladu kodu "Browser detect" od Peter-Paul Kocha:<br>
 * <a href="http://www.quirksmode.org/js/detect.html">http://www.quirksmode.org/js/detect.html</a></p>
 * 
 * @example Ohlasi typ a verzi prohlizece
 *   alert("Prohlizec: " browser.browser + " " browser.version);
 *    
 * @example Provede kod jen pro IE6 nebo Operu verze 7.52 (oba zpusoby kontroly)
 *   if (browser.isIE6 || ( (browser.browser == "Opera") && (browser.version == 7.52) ))
 *   { ... } 
 *  
 * @class browserDetect - detekce prohlizece - vzdy dostupne
 * @version 1.0  
 * @constructor 
 */ 
function browserDetect()
{
  /**
   * Nazev prohlizece. Hodnota viz {@link browserDetect#dataBrowser}.
   * @public
   * @default "n/a"	   
   * @type string      
   */     
  this.browser = this.searchString(this.dataBrowser) || "n/a";
  
  /**
   * Verze prohlizece.
   * @public
   * @default "n/a"   
   * @type number      
   */     
	this.version = this.searchVersion(navigator.userAgent)
		|| this.searchVersion(navigator.appVersion)
		|| "n/a";
		
	/**
	 * Verze operacniho systemu. Hodnota viz {@link browserDetect#dataOS}.
	 * @public
	 * @default "n/a"	 
	 * @type string
	 */   	
	this.OS = this.searchString(this.dataOS) || "n/a";

  /**#@+
   * @public
   * @type boolean     
   */
  /** Vlastnost indikujici jakoukoliv verzi prohlizece Internet Explorer. */
  this.isIE = (this.browser == "Explorer") ? true : false;
  /** Vlastnost indikujici Internet Explorer verze 5.5 */     
  this.isIE55 = ( (this.isIE) && (this.version == 5.5) ) ? true : false;
  /** Vlastnost indikujici Internet Explorer verze 6 */
  this.isIE6 = ( (this.isIE) && (this.version == 6) ) ? true : false;
  /** Vlastnost indikujici Internet Explorer verze 7 */
  this.isIE7 = ( (this.isIE) && (this.version == 7) ) ? true : false;
  /** Vlastnost indikujici Internet Explorer verze 8 */
  this.isIE8 = ( (this.isIE) && (this.version == 8) ) ? true : false;
  
  /** Vlastnost indikujici jakoukoliv verzi prohlizece Opera. */
  this.isOpera = (this.browser == "Opera") ? true : false;
  /** Vlastnost indikujici jakoukoliv verzi prohlizece Chrome. */
  this.isChrome = (this.browser == "Chrome") ? true : false;
  /** Vlastnost indikujici jakoukoliv verzi prohlizece Safari. */
  this.isSafari = (this.browser == "Safari") ? true : false;
  /** Vlastnost indikujici jakoukoliv verzi prohlizece Konqueror. */
  this.isKonqueror = (this.browser == "Konqueror") ? true : false;
  /** Vlastnost indikujici jakoukoliv verzi prohlizece Firefox */
  this.isFirefox = (this.browser == "Firefox") ? true : false;
  
  /** Vlastnost indikujici Firefox verze 2 */
  this.isFF2 = ( (this.isFirefox) && (this.version.toString().substring(0,1) == "2") ) ? true : false;
  /** Vlastnost indikujici Firefox verze 3 */
  this.isFF3 = ( (this.isFirefox) && (this.version.toString().substring(0,1) == "3") ) ? true : false;
  /**#@-*/
  
  /**
	 * Instance objektu {@link plugins}.
	 * @public
	 * @type object plugins
	 */
  this.plugins = new plugins();
}

/**
 * Pole definicnich objektu pro zjisteni operacniho systemu.
 *
 * <p>Rozsirenim definic pole lze ziskat detekci dalsich systemu.</p>
 * 
 * <p>Struktura definicniho objektu:</p> 
 * <pre>
 *  string    - vlastnost, ktera se bude porovnavat
 *  substring - hledana cast textu ve vlastnosti <string>
 *  identity  - text, ktery bude vracet vlastnost browserDetect.OS
 * </pre>
 * 
 * @private
 * @type array of object
 */ 
browserDetect.prototype.dataOS = [
  {
  	string: navigator.platform,
  	subString: "Win",
  	identity: "Windows"
  },
  {
  	string: navigator.platform,
  	subString: "Mac",
  	identity: "Mac"
  },
  {
  	string: navigator.userAgent,
  	subString: "iPhone",
  	identity: "iPhone/iPod"
  },
  {
  	string: navigator.platform,
  	subString: "Linux",
  	identity: "Linux"
  },
  {
  	string: navigator.userAgent,
  	subString: "X11",
  	identity: "Linux"
  }
]

/**
 * Pole definicnich objektu pro zjisteni typu prohlizece.
 *
 * <p>Rozsirenim definic pole lze ziskat detekci dalsich prohlizecu.</p>
 * 
 * <p>Struktura definicniho objektu:</p> 
 * <pre>
 *  string        - vlastnost, ktera se bude porovnavat
 *  substring     - hledana cast textu ve vlastnosti <string>
 *  versionSearch - hledana cast textu, za kterym se skryva verze  
 *  identity      - text, ktery bude vracet vlastnost browserDetect.OS
 * </pre>
 * 
 * @private
 * @type array of object
 */ 
browserDetect.prototype.dataBrowser= [
  {
  	string: navigator.userAgent,
  	subString: "Chrome",
  	identity: "Chrome"
  },
  {
    string: navigator.userAgent,
  	subString: "OmniWeb",
  	versionSearch: "OmniWeb/",
  	identity: "OmniWeb"
  },
  {
  	string: navigator.vendor,
  	subString: "Apple",
  	identity: "Safari",
  	versionSearch: "Version"
  },
  {
  	prop: window.opera,
  	identity: "Opera"
  },
  {
  	string: navigator.vendor,
  	subString: "iCab",
  	identity: "iCab"
  },
  {
  	string: navigator.vendor,
  	subString: "KDE",
  	identity: "Konqueror"
  },
  {
  	string: navigator.userAgent,
  	subString: "Firefox",
  	identity: "Firefox"
  },
  {
  	string: navigator.vendor,
  	subString: "Camino",
  	identity: "Camino"
  },
  {		// for newer Netscapes (6+)
  	string: navigator.userAgent,
  	subString: "Netscape",
  	identity: "Netscape6"
  },
  {
  	string: navigator.userAgent,
  	subString: "MSIE",
  	identity: "Explorer",
  	versionSearch: "MSIE"
  },
  {
  	string: navigator.userAgent,
  	subString: "Gecko",
  	identity: "Mozilla",
  	versionSearch: "rv"
  },
  { 		// for older Netscapes (4-)
  	string: navigator.userAgent,
  	subString: "Mozilla",
  	identity: "Netscape",
  	versionSearch: "Mozilla"
  }
]

/**
 * Metoda, ktera vyhledava string pro detekci.
 *  
 * @private
 * @return {string} nalezena identita
 */  
browserDetect.prototype.searchString = function (data)
{
	for (var i=0; i<data.length; i++)
  {
		var dataString = data[i].string;
		var dataProp = data[i].prop;
		this.versionSearchString = data[i].versionSearch || data[i].identity;
		if (dataString)
    {
			if (dataString.indexOf(data[i].subString) != -1) return data[i].identity;
		}
		else if (dataProp) return data[i].identity;
	}
}

/**
 * Metoda pro vyhledani verze ve stringu.
 * 
 * @private
 * @return {number} verze  
 */ 
browserDetect.prototype.searchVersion = function (dataString)
{
	var index = dataString.indexOf(this.versionSearchString);
	if (index == -1) return;
	return parseFloat(dataString.substring(index+this.versionSearchString.length+1));
}


/**
 * Metoda, ktera vraci prirazeni ciselnych konstant tlacitkum mysi.
 *
 * <p>Struktura vraceneho objektu:</p> 
 * <pre>
 *   left   - konstanta pro leve mysitko
 *   middle - konstanta pro prostredni mysitko
 *   right  - konstanta pro prave mysitko
 * </pre>
 * <p>Pro prohlizece, ktere umi vicekliky (IE) pridava nasledujici vlastnosti:</p>
 * <pre>
 *   leftmiddle      - konstanta pro leve a stredni mysitko stistene najednou
 *   rightmiddle     - konstanta pro prave a stredni mysitko stistene najednou
 *   leftright       - konstanta pro leve a prave mysitko stistene najednou
 *   lefrighttmiddle - konstanta pro leve, prave a stredni mysitko stistene najednou   
 * </pre>    
 * 
 * @public
 * @return {object} objekt s definici konstant tlacitek 
 */  
browserDetect.prototype.getMouseButtons = function()
{
  if ( this.isIE )
  {
    return {left: 1, middle: 4, right: 2, leftmiddle: 5, rightmiddle: 6, leftright: 3, leftrightmiddle: 7}   //nedodrzuje standard, ale zato lze ziskat informaci o vicekliku
  }
  if ( (this.isKonqueror)
        || ( (this.isOpera) && (this.version > 7) && (this.version < 9) ) )
  {
    return {left: 1, middle: 4, right: 2}   //nedodrzuje standard (model IE), a nelze ziskat informaci o vicekliku
  }
  if (this.isSafari)
  {
    if (this.version > 2)
    {
      return {left: 0, middle: 0, right: 2};
    }
    else
    {
      return {left: 1, middle: 1, right: 2};
    }
  }
  if ( (this.browser == "Netscape") || (this.browser == "Netscape6") )
  { //Netscape 4 - pro zjisteni hodnoty kliku pomoci event.which
    //Netscape 6+ - zjisteni sice pomoci e.button, ale hodnoty ma spatne...
    return {left: 1, middle: 2, right: 3};
  }
  return {left: 0, middle: 1, right: 2};
}

/**
 * Inicializovana instance objektu browserDetect. 
 * @type object browserDetect
 * @public  
 */ 
//var browser = new browserDetect();
autoinit.module["browserDetect"] = {variable: "browser"};
autoinit.load("browserDetect");


/******************************************************************************
 *   OBJEKT EVENTS
 ******************************************************************************/ 

/**
 * Objekt pro praci s udalostmi s podporou pro objektove programovani.
 * 
 * <p>Pouziva se jako staticky objekt - pristupuje se primo ke statickym metodam (tj. bez nutnosti vytvareni instance objektu)</p>  
 *
 * <p>TODO:<br />
 *  - metoda na poveseni udalostni funkce na stisk urcite klavesove kombinace
 * </p>   
 * 
 * @class events - prace s udalostmi - vzdy dostupne
 * @version 1.6 
 * @extends Object
 * @constructor    
 */
events = {}

/**
 * Metoda vygeneruje callback funkci pro objekt AJAX. Funkce pridava kontext objektu.   
 * 
 * @example
 *   this.ajax.callback = events.getAJAXcallback(this.processAJAX, this);
 *  
 * @member events 
 * @see ajaxObject 
 * @see events.getEvent 
 * @param {function} fnct   Obsluzna staticka funkce
 * @param {object}   scope  Kontext objektu obsluzne funkce - volitelny
 * @return {function} Callback funkci pro pouziti v objektu ajax
 * @type function  
 */
events.getAJAXcallback = function(fnct, scope)
{
  var f = scope ? function(responseText, responseStatus, responseXML) { fnct.apply(scope, [responseText, responseStatus, responseXML]); } : fnct;
  return f;
}


/**
 * Metoda vygeneruje dynamickou callback funkci a prida ji kontext objektu.    
 * 
 * <p>Kontextem objektu bude udalost zpracovavana jen v teto instanci objektu, obsah funkce muze spolupracovat s ostatnimi vlastnostmi a metodami objektu pomoci bezneho kontextu "this."</p>
 *  
 * @example
 *   var timer = setTimeout(events.getEvent(this.afterSecond, this), 1000);
 *  
 * @member events 
 * @param {function} fnct   Obsluzna staticka funkce
 * @param {object}   scope  Kontext objektu obluzne funkce
 * @return {function} Dynamickou callback funkci
 * @type function  
 */
events.getEvent = function(fnct, scope)
{
  var f = scope ? function() { fnct.apply(scope); } : fnct;
  return f;
}


/**
 * Metoda vytvori a zavesi funkci jako obsluznou funkci udalosti objektu. Volitelne prirazuje kontext objektu.    
 * 
 * <p>Kontextem objektu bude udalost zpracovavana jen v teto instanci objektu, obsah funkce muze spolupracovat s ostatnimi vlastnostmi a metodami objektu pomoci bezneho kontextu "this."</p>
 * <p>Udalost se zadava pouze svym nazvem, tj. "mousemove" apod. Presne tak, jak to chodi ve FF, Safari atd. V pripade IE je automaticky prejmenovano na udalost "onmousemove" apod.</p> 
 * <p>Je-li zadan parametr <i>ret</i>, bude vracen po ukonceni obsluhy udalosti (nezavisle na tom, co vraci funkce sama). Vhodne pro nektere prohlizece, ktere ocevaji boolean hodnotu od zpracovani udalosti a podle toho ridi mechanismus probublavani udalosti (starsi verze IE apod.)</p>
 *    
 * @example
 * pri vygenerovani udalosti "mousemove" nad elementem bude tato udalost obslouzena metodou "onMouseFnct"
 *  
 *   var evMouse = events.addEventListener(element, "mousemove", this.onMouseFnct, this);
 * @example 
 * kliknuti na objektu "this.elButton" bude obslouzeno metodou "onClickFnct" instance
 * objektu "other" a vzdy bude vracet hodnotu "false"
 * V tomto pripade nepujde obsluhu udalosti zrusit, nebyl ulozen odkaz na obsluznou funkci!
 *    
 *   events.addEventListener(this.elButton, "click", other.onClickFnct, other, false);  
 *  
 * @member events 
 * @see events.removeEventListener
 * @param {object}   element      Objekt, na ktery se zavesi obsluha udalosti
 * @param {string}   eventName    Nazev udalosti
 * @param {function} eventHandler Obsluzna staticka funkce udalosti
 * @param {object}   scope        Kontext objektu obluzne funkce
 * @param {mixed}    ret          Volitelny parametr, ktery vraci bsluzna funkce po svem vykonani
 * @return {function} Dynamickou callback funkci (pro ulozeni a pozdejsi odstraneni obsluhy udalosti)
 * @type function  
 */
events.addEventListener = function(element, eventName, eventHandler, scope, ret)
{  
  //vytvori volaci funkci na metodu s kontextem objektu
  //pokud je zadan parametr RET, volaci funkce bude tuto hodnotu navracet
  if (ret != null)
  { //volaci funkce, ktera vraci hodnotu RET
    var scopedEventHandler = scope ? function(e) { eventHandler.apply(scope, [e]); return ret; } : eventHandler;  
  }
  else
  { //bezna volaci fce
    var scopedEventHandler = scope ? function(e) { eventHandler.apply(scope, [e]); } : eventHandler;
  }
  
  if(document.addEventListener)  
  { //Firefox, Opera... - bez probublavani

    //preklad nazvu udalosti pro Firefox, pokud si nekoresponduji
    if (browser.isFirefox)
    {
      switch (eventName)
      {
        case "mousewheel":
          eventName = "DOMMouseScroll";
          break;
      }
    }
    
    element.addEventListener(eventName, scopedEventHandler, false);
  }
  else if (document.attachEvent)
  { //IE
    element.attachEvent("on"+eventName, scopedEventHandler);
  }
  
  return scopedEventHandler;    //vrati vytvorenu funkci, ktera je navazana na event
}

/**
 * Metoda odstrani obsluznou funkci udalosti objektu.    
 *    
 * <p>Udalost se zadava pouze svym nazvem, tj. "mousemove" apod. Presne tak, jak to chodi ve FF, Safari atd. V pripade IE je automaticky prejmenovano na udalost "onmousemove" apod.</p>
 *  
 * @example Prida a odstrani obsluhu udalosti
 *  
 *  var evMouse = events.addEventListener(element, "mousemove", this.onMouseFnct, this);
 *  events.removeEventListener(element, "mousemove", evMouse);
 *  
 * @member events 
 * @see events.addEventListener
 * @param {object}   element      Objekt, ze ktereho se odstranuje obsluha udalosti
 * @param {string}   eventName    Nazev udalosti
 * @param {function} eventHandler Obsluzna dynamicka funkce udalosti, ktera se odstranuje  
 */
events.removeEventListener = function(element, eventName, eventHandler)
{
  if(document.removeEventListener)
  { //Firefox, Opera...
    element.removeEventListener(eventName, eventHandler, false);
  }
  else if (document.detachEvent)
  { //IE
    element.detachEvent("on"+eventName, eventHandler);
  }
}

/**
 * Metoda vraci zdrojovy element, na kterem byla udalost vygenerovana
 *  
 * @example
 *  alert(events.eventSource(e).tagName); 
 *  
 * @member events 
 * @param {object event} e Udalostni objekt, ktery predava jadro obsluznym funkcim (ev. se ziskava jinak)
 * @return {object} Zdrojovy element udalosti  
 * @type object
 */
events.eventSource = function(e)
{
  var src = null;
  if (e.target)
  {
    src = e.target;
  }
  else if (e.srcElement)
  { //IE
    src = e.srcElement;
  }
  if (src.nodeType == 3) //defeat Safari bug
	{
    src = src.parentNode;
  }
  return src;
}

/**
 * Metoda vraci pozici mysi pri udalosti
 *  
 * @example
 *  alert("[x,y]: " + events.mousePosition(e)); 
 *  
 * @member events 
 * @param {object event} e Udalostni objekt, ktery predava jadro obsluznym funkcim (ev. se ziskava jinak)
 * @return {array} Pole s hodnotami souradnic, [0] => x & [1] => y  
 * @type array
 */
events.mousePosition = function(e)
{
  var x = 0;
  var y = 0;
  
  if (!e)
  {
    e = window.event;
  }
  if (!e)
  {
    return;
  }
  if (typeof(e.pageX) == 'number')
  { //Mozilla
    x = e.pageX;
    y = e.pageY;
  }
  else if (typeof(e.clientX) == 'number')
  { //IE
    x = e.clientX;
    y = e.clientY;
    if (document.body && (document.body.scrollLeft || document.body.scrollTop))
    {
      x += document.body.scrollLeft;
      y += document.body.scrollTop;
    }
    else if (document.documentElement && (document.documentElement.scrollLeft || document.documentElement.scrollTop) )
    {
      x += document.documentElement.scrollLeft;
      y += document.documentElement.scrollTop;
    }
  }
  else
  { //nejde zjistit, nejaka historie
    return;
  }
  return [x, y];
}

/**
 * Metoda vraci element, ze ktereho mys pri udalosti mouseover odesla 
 *  
 * @member events 
 * @param {object event} e Udalostni objekt, ktery predava jadro obsluznym funkcim (ev. se ziskava jinak)
 * @return {object Element} Objekt, ze ktereho mys pri udalosti odesla  
 * @type object Element
 */
events.mouseoverTarget = function(e)
{
  if (!e) var e = window.event;
  return e.relatedTarget || e.fromElement;
}

/**
 * Metoda vraci element, do ktereho mys pri udalosti mouseout presla 
 *  
 * @member events 
 * @param {object event} e Udalostni objekt, ktery predava jadro obsluznym funkcim (ev. se ziskava jinak)
 * @return {object Element} Objekt, do ktereho mys pri udalosti presla  
 * @type object Element
 */
events.mouseoutTarget = function(e)
{
  if (!e) var e = window.event;
  return e.relatedTarget || e.toElement;
}

/**
 * Metoda vraci deltu posunu kolecka mysi.
 * 
 * <p>Vyznam hodnty delta: 
 *  <ul>
 *    <li>kladna hodnota - posun kolecka smerem od uzivatele (nahoru)</li>
 *    <li>zaporna hodnota - posun kolecka smerem k uzivateli (dolu)</li>
 *    <li>hodnota false - k posunu nedoslo</li>
 *  </ul>   
 * </p>
 * <p>Poznamka 1:<br />
 * neni implementovano na Konqueror, OmniWeb a iCab.<br />
 * podporovano a testovano: IE6+, Firefox 1.0+, Opera 9+, Safari</p>
 * <p>Poznamka 2:<br />na iPhone je udalost generovana jen pri dvoprstovem gestu.</p>   
 *  
 * @member events
 *   
 * @param {object event} e Udalostni objekt, ktery predava jadro obsluznym funkcim (ev. se ziskava jinak)
 * @return {int} Delta posunu  
 * @type int
 * @since v2.3 
 */
events.mouseWheel = function(e)
{
  var delta = 0;
  
  if (!e) var e = window.event;
  
  if (e.wheelDelta)
  {
    delta = e.wheelDelta/120;   // IE+Opera
    
    if (window.opera && window.opera < 9.5)
    { //Opera < 9.5 vraci negovanou hodnotu, od 9.5 opraveno
      delta = -delta;
    }
  }
  else if (e.detail)
  { // Mozilla - DOM
    delta = -e.detail/3;
  }        
  
  if (delta != 0)
  {
    return Math.round(delta);   //pro Safari se musi zaokrouhlovat
  }
  else
  {
    return false;
  }
}

/**
 * Metoda vraci hodnotu stisknuteho tlacitka.
 * 
 * <p>Ma smysl volat pri udalostech mousedown a mouseup, pri onclick nedava presne vysledky, v nekterych prohlizecich dokonce zadne.</p>
 * <p>Vraci ciselnou konstantu stisknuteho tlacitka - nutno porovnavat s hodnotami objektu {@link browserDetect#getMouseButtons}.</p>
 * <p>Zatim pouze IE vraci v pripade stisku vice tlacitek najednou konstanty i pro tyto varianty, ostatni prohlizece vraci vzdy jen posledni stisknute tlacitko.</p>
 * 
 * <p>Poznamka 1:<br />
 * V IE se nesmi spolehat pouze na hodnotu jednoho tlacitka pro pripad stisku vice tlacitek najednou. Doporucuje se pouzivat metodu {@link events.mouseButtonState}, ktera vraci objekt bitovych vlastnosti pro jednotliva tlacitka.</p>
 * <p>Poznamka 2:<br />
 * V Opere lze navazat udalosti mysitka right jen po predchozim prenastaveni prohlizece.</p>
 *  
 * @member events
 * 
 * @see events.mouseButtonState
 * @see events.mouseLeft
 * @see events.mouseMiddle
 * @see events.mouseRight
 *   
 * @param {object event} e Udalostni objekt, ktery predava jadro obsluznym funkcim (ev. se ziskava jinak)
 * @return {int} Hodnotu stisknuteho tlacitka/tlacitek  
 * @type int    
 * @since v2.3 
 */
events.mouseButton = function(e)
{
  if (!e) var e = window.event; 

  if (typeof(e.button) == "number") //podpora pro nove MZ, Chrome, Operu...
  { //IE
    return e.button;  //IE all + DOM
  } 

  if (e.which)
  { //typicky Netscape 4 - funguje i v Mozille apod, vraci vsak jine vysledky
    return e.which;
  }
}

/**
 * Metoda vraci objekt bitovych vlastnosti kliku mysitek. 
 * 
 * <p>Vyhodnocuje {@link events.mouseButton}. Zpracovava i vicekliky a je to tak bezpecna metoda pro zjisteni vsech stisknutych tlacitek.</p>
 * <p>Vlastnosti vraceneho objektu (typ bool):</p>
 * <pre>
 *   left   - stisteno leve mysitko
 *   middle - stisteno prostredni mysitko
 *   right  - stisteno prave mysitko
 * </pre>     
 *  
 * @member events
 * 
 * @see events.mouseLeft
 * @see events.mouseMiddle
 * @see events.mouseRight
 *   
 * @param {object event} e Udalostni objekt, ktery predava jadro obsluznym funkcim (ev. se ziskava jinak)
 * @return {object} Objekt vlastnosti tlacitek (true - stisteno, false - nestisteno)  
 * @type object
 * @since v2.3 
 */
events.mouseButtonState = function(e)
{
  mb = this.mouseButton(e);
  buttons = browser.getMouseButtons();  //definice prirazeni hodnot tlacitkum
  
  b = {left: false, middle: false, right: false}; //vychozi objekt stisknutych tlacitek
    
  //pokud je hodnota jina, jedna se IE, ktery umi vratit hodnotu vsech stistenych tlacitek najednou
  switch (mb)
  {
    case buttons.left:
      b.left = true;
      break;
    case buttons.right:
      b.right = true;
      break;
    case buttons.middle:
      b.middle = true;
      break;
    case buttons.leftright:
      b.left = true;
      b.right = true;
      break;
    case buttons.leftmiddle:
      b.left = true;
      b.middle = true;
      break;
    case buttons.rightmiddle:
      b.right = true;
      b.middle = true;
      break;
    case buttons.leftrightmiddle:
      b.left = true;
      b.middle = true;
      b.right = true;
      break;
  }
  return b; //vrat stav tlacitek, v pripade nezname chyby vraci stav "nic nestisteno"
}

/**
 * Metoda testuje, zda je stisteno leve mysitko. 
 * 
 * <p>Vyhodnocuje {@link events.mouseButton}. Zpracovava i vicekliky a je to tak bezpecna metoda pro zjisteni vsech stisknutych tlacitek.</p>
 *  
 * @member events
 * 
 * @see events.mouseButtonState
 * @see events.mouseMiddle
 * @see events.mouseRight
 *   
 * @param {object event} e Udalostni objekt, ktery predava jadro obsluznym funkcim (ev. se ziskava jinak)
 * @return {boolean} true - stisteno / false - nestisteno  
 * @type boolean
 * @since v2.3 
 */
events.mouseLeft = function(e)
{
  return this.mouseButtonState(e).left;
}

/**
 * Metoda testuje, zda je stisteno prostredni mysitko. 
 * 
 * <p>Vyhodnocuje {@link events.mouseButton}. Zpracovava i vicekliky a je to tak bezpecna metoda pro zjisteni vsech stisknutych tlacitek.</p>
 *  
 * @member events
 * 
 * @see events.mouseButtonState
 * @see events.mouseLeft
 * @see events.mouseRight
 *   
 * @param {object event} e Udalostni objekt, ktery predava jadro obsluznym funkcim (ev. se ziskava jinak)
 * @return {boolean} true - stisteno / false - nestisteno  
 * @type boolean
 * @since v2.3 
 */
events.mouseMiddle = function(e)
{
  return this.mouseButtonState(e).middle;
}

/**
 * Metoda testuje, zda je stisteno prave mysitko. 
 * 
 * <p>Vyhodnocuje {@link events.mouseButton}. Zpracovava i vicekliky a je to tak bezpecna metoda pro zjisteni vsech stisknutych tlacitek.</p>
 *  
 * @member events
 * 
 * @see events.mouseButtonState
 * @see events.mouseMiddle
 * @see events.mouseLeft
 *   
 * @param {object event} e Udalostni objekt, ktery predava jadro obsluznym funkcim (ev. se ziskava jinak)
 * @return {boolean} true - stisteno / false - nestisteno  
 * @type boolean
 * @since v2.3 
 */
events.mouseRight = function(e)
{
  return this.mouseButtonState(e).right;
}

/**
 * Metoda vraci znak stisknuteho tlacitka.
 * 
 * <p>Pouziti pro udalosti KeyPress a KeyDown/KeyUp.</p>
 * 
 * <p>Vraci znakovou prezentaci prirazenou klavese podle aktualniho rozlozeni klavesnice (pri udalosti KeyPress - tato se vola az pri napsani znaku, i kdyz k tomu je zapotrebi zmacknout sled klaves - napr. Z s hackem).</p>
 *   
 * <p>Upozorneni: U KeyDown/KeyUp vraci ASCII hodnutu tlacitka v zakladni EN klavesnicicovem rozliseni, nelze rozeznat velikost pismena, nelze pouzit pro rozpoznani narodnich znaku.</p>
 *   
 * @member events
 * @param {object event} e Udalostni objekt, ktery predava jadro obsluznym funkcim (ev. se ziskava jinak)
 * @return {string} Znakova prezentace stisknute klavesy (vcetne tzv. bilych znaku pro systemove klavesy)
 * @type string 
 */  
events.keyPressedChar = function(e)
{  
  return String.fromCharCode(this.keyPressedCode(e));
}

/**
 * Metoda vraci kod stisknuteho tlacitka.
 * 
 * <p>Pouziti pro udalosti KeyPress a KeyDown/KeyUp.</p>
 *
 * <p>Vraci kod znaku prirazeneho klavese v atualnim rozlozeni klavesnice (pri udalosti KeyPress - tato se vola az pri napsani znaku, i kdyz k tomu je zapotrebi zmacknout sled klaves - napr. Z s hackem).</p>
 *      
 * <p>Upozorneni: U KeyDown/KeyUp vraci ASCII hodnutu tlacitka v zakladni EN klavesnicicovem rozliseni, nelze rozeznat velikost pismena, nelze pouzit pro rozpoznani narodnich znaku.</p>
 *   
 * @member events
 * @param {object event} e Udalostni objekt, ktery predava jadro obsluznym funkcim (ev. se ziskava jinak)
 * @return {int} Kod stisknute klavesy
 * @type string 
 */  
events.keyPressedCode = function(e)
{
  var code;
  if (!e) var e = window.event;
  if (e.keyCode)
  {
    code = e.keyCode;
  }
  else if (e.which)
  {
    code = e.which;
  }
  
  return code;
}

/**
 * Metoda vraci true, pokud je stistena klavesa Shift.
 * 
 * <p>Pouziti pro udalosti KeyPress a KeyDown/KeyUp.</p>
 *   
 * <p>Upozorneni: zapnuty Caps Lock nema na funkci vliv</p>
 *   
 * @member events
 * @param {object event} e Udalostni objekt, ktery predava jadro obsluznym funkcim (ev. se ziskava jinak)
 * @return {boolean} True - Shift stisten, False - Shift uvolnen 
 * @type boolean
 * @since v2.3 
 */
events.keyPressedShift = function(e)
{
  if (!e) var e = window.event;
  
  return e.shiftKey;
}

/**
 * Metoda vraci true, pokud je stistena klavesa Ctrl.
 *
 * <p>Pouziti POUZE pro udalosti KeyDown a KeyUp.</p>  
 * 
 * <p>Upozorneni: pravy a levy Ctrl se nerozeznava</p>
 *   
 * @member events
 * @param {object event} e Udalostni objekt, ktery predava jadro obsluznym funkcim (ev. se ziskava jinak)
 * @return {boolean} True - Ctrl stisten, False - Ctrl uvolnen 
 * @type boolean
 * @since v2.3 
 */
events.keyPressedCtrl = function(e)
{
  if (!e) var e = window.event;
  
  return e.ctrlKey;
}

/**
 * Metoda vraci true, pokud je stisteno tlacitko Alt.
 * 
 * <p>Pouziti POUZE pro udalosti KeyDown a KeyUp.</p>
 *   
 * <p>Upozorneni: pravy a levy Alt se nerozeznava</p>
 *   
 * @member events
 * @param {object event} e Udalostni objekt, ktery predava jadro obsluznym funkcim (ev. se ziskava jinak)
 * @return {boolean} True - Alt stisten, False - Alt uvolnen 
 * @type boolean
 * @since v2.3 
 */
events.keyPressedAlt = function(e)
{
  if (!e) var e = window.event;
  
  return e.altKey;
}

/**
 * Metoda vraci nazev stistene klavesy (lowercase).
 *
 * <p>Pouziti POUZE pro udalosti KeyDown a KeyUp.</p> 
 * 
 * <p>Vracene kody klaves lze (re)definovat v objektu {@link events.keySpecialCodes}. Vychozi nastaveni vraci tyto hodnoty:</p> 
 * <ul>
 *  <li>u klaves A..Z vraci hodnotu "a".."z"</li>
 *  <li>u klaves 0..9 na hlavni casti klavesnice vraci "0".."9"</li>
 *  <li>u ostatnich klaves z hlavni klavesnice vraci hodnotu standardniho EN rozlozeni v lowercase (napr. "`", "/", "[" apod.)</li>
 *  <li>u numerickych klaves vraci hodnoru "num 0".."num 9" a "num /" apod.</li>
 *  <li>u specialnich Windows klaves vraci hodnotu "win start", "win flip", "win menu"</li> 
 *  <li>u ostatnich klaves vraci jejich bezne oznaceni (lowercase) - napr. "f10", "space", "enter" apod.</li>
 *  <li>nerozeznava mezi hlavnim enterem a numerickym enterem</li>
 *  <li>u nerozeznanych klaves vraci hodnotu "n/a"</li> 
 * </ul>
 * 
 * <p>Pokud je VOLITELNY parametr "num" true, vraci prelozenou hodnotu stistene klavesy numericke klavesnice jako by byly stisteny na hlavni casti klavesnice (tj. "num 0" vraci jako "0" - pozor, klavesa "num +" a "num *" vraci "+" resp. "*" i presto, ze tyto klavesy v hlavni casti klavesnice nejsou /tyto znaky se pisi se Shiftem/). Vhodne hlavne pro funkce, ktere testuji vstupy dekadickych cifer.</p>
 * 
 * <p>Upozorneni: Pokud budou prepsany vlastnosti objketu {@link events.keySpecialCodes} "num X", parametr "num" nebude fungovat spravne a je nutno redefinovat tuto funkci.</p>
 *       
 * @see events.keySpecialCodes  
 *      
 * 
 * @member events
 * @param {object event} e   Udalostni objekt, ktery predava jadro obsluznym funkcim (ev. se ziskava jinak)
 * @param {boolean}      num Priznak prekladu numerickych klaves
 * @return {string} Nazev stisknute klavesy 
 * @type string
 * @since v2.3 
 */
events.keyPressed = function(e, num)
{
  if (!num) num = false;
  var key = this.keyPressedCode(e);
  
  //pismena A..Z
  if ( (key > 64) && (key < 91) ) return String.fromCharCode(key).toLowerCase();
  
  //cislice 0..9
  if ( (key > 47) && (key < 58) ) return String.fromCharCode(key);
  
  for (var k in this.keySpecialCodes)
  {
    if (key == this.keySpecialCodes[k])
    {
      if ( num && (k.length == 5) && (k.indexOf("num ", 0) != -1) ) return k.substring(3);  //pri stisku num klavesy ji vraci jako by byla stistena mimo numericke casti.
      return k;
    }
  }
  
  return "n/a"; //neznamy keycode
}

/**
 * Objekt - pole - kodu klaves.
 * 
 * <p>Nazev vlastnosti je nazev kodu klavesy (vraci metoda {@link events.keyPressed}), hodnota vlastnoti je kod stisknute klavesy.</p>
 * 
 * <p>Objekt lze modifikovat tak, aby vracel vlastni kody, popr. rozsirit o specialni kody rozrsirenych klavesnic.<p>
 * @example
 *   delete events.keyCodes["tab"];           //smaze definici klavesy "tab"
 *   events.keyCodes["moje klavesa"] = 4;     //prida novou definice "moje klavesa"
 *      //redefinice se provede smazanim a opetovnym pridanim vlastnosti jako vyse  
 * 
 * @public 
 * @type object
 * @since v2.3 
 */
events.keySpecialCodes = {
  "backspace"   : 8,
  "tab"         : 9,
  "enter"       : 13,
  "shift"       : 16,
  "ctrl"        : 17,
  "alt"         : 18,
  "pause"       : 19,
  "caps lock"   : 20,
  "esc"         : 27,
  "space"       : 32,
  "page up"     : 33,
  "page down"   : 34,
  "end"         : 35,
  "home"        : 36,
  "left"        : 37,
  "up"          : 38,
  "right"       : 39,
  "down"        : 40,
  "insert"      : 45,
  "delete"      : 46,
  "win start"   : 91,
  "win flip"    : 92,
  "win menu"    : 93,
  "num 0"       : 96,
  "num 1"       : 97,
  "num 2"       : 98,
  "num 3"       : 99,
  "num 4"       : 100,
  "num 5"       : 101,
  "num 6"       : 102,
  "num 7"       : 103,
  "num 8"       : 104,
  "num 9"       : 105,
  "num *"       : 106,
  "num +"       : 107,
  "num -"       : 109,
  "num ."       : 110,
  "num /"       : 111,
  "f1"          : 112,
  "f2"          : 113,
  "f3"          : 114,
  "f4"          : 115,
  "f5"          : 116,
  "f6"          : 117,
  "f7"          : 118,
  "f8"          : 119,
  "f9"          : 120,
  "f10"         : 121,
  "f11"         : 122,
  "f12"         : 123,
  "num lock"    : 144,
  "scroll lock" : 145,
  ";"           : 186,
  "="           : 187,
  ","           : 188,
  "-"           : 189,
  "."           : 190,
  "/"           : 191,
  "`"           : 192,
  "["           : 219,
  "\\"          : 220,
  "]"           : 221,
  "'"           : 222
}

/**
 * Metoda pozastavi provadeni kodu na urcity cas.
 * 
 * <b>POZOR, vytezuje vyrazne procesor a cas je jen priblizny (nelze pouzit na stopky apod.).</b>   
 *  
 * @member events
 * @param {int} msec Pocet milisekund, po ktere ma byt pozdrzeno provadeni kodu
 * @since 1.6   
 */
events.wait = function(msec)
{
  var start = new Date().getTime();
  var cur = start
  
  while(cur - start < msecs)
  {
    cur = new Date().getTime();
  } 
} 

//priradit udalost onload objektu autonit, ktery provede inicializaci objektu
events.addEventListener(window, "load", autoinit.onload, autoinit);


/*****************************************************************************
 *  Objekt CFN_WINDOW
 ******************************************************************************/ 


/**
 * Objekt cfn_window pro vytvareni dynamickych okynek na strance.
 *
 * Nahrada nepouzitelneho window.open pri blokovani otevirani oken navic v designu CFN.
 *
 * <p>Struktura vstupniho objektu:</p> 
 * <pre>
 *    id      - string - volitelne
 *            - identifikator vytvoreneho okna
 *               
 *    show    - boolean - volitelne
 *            - pokud je vlastnost definovana a je nastavena na false, okno nebude 
 *              pri inicializaci objektu zobrazeno a musi se to zajistit pozdeji  
 *              volanim {@link cfn_window#show}
 *              
 *    width   - int - volitelne
 *            - sirka okna
 *            - pokud neni definovano, pouzije se vychozi nastaveni v CSS stylech 
 *              (definice div.window)  
 *    
 *    height  - int - volitelne
 *            - vyska okna
 *            - pokud neni definovano, pouzije se vychozi nastaveni v CSS stylech 
 *              (definice div.window) 
 *    
 *    top     - int - volitelne
 *            - pozice okna na strance - top souradnice horniho leveho rohu
 *            - pokud neni definovano, okno bude umisteno doprostred okna 
 *    
 *    left    - int - volitelne
 *            - pozice okna na strance - left souradnice horniho leveho rohu
 *            - pokud neni definovano, okno bude umisteno doprostred okna
 *            
 *    content - object DOM - volitelne
 *            - obsah okna, ktery bude vlozen pri inicializaci
 *            - neni-li definovano, pak bude zobrazeno prazdne okno
 *            
 *    title   - string - volitelne
 *            - nadpis okna, pokud je definovan, jinak bude okno bez nadpisu   
 *                              
 *    texts   - object - volitelne
 *            - definice objektu textovych promennych - viz {@link cfn_window#texts}
 *            - nejsou-li zadany vsechny potrebne vlastnosti, doplni se objekt o  
 *              tyto vlastnosti s vychozim nastavenim
 * </pre>  
 * 
 * @example
 *  
 * @class cfn_window - vytvareni dynamickych okynek na strance - vzdy dostupne
 * @extends cfn
 * @version 1.0  
 * @constructor 
 */ 
function cfn_window(p)
{ 
  /**
   * Objekt element okna.
   *    
   * @type object window  
   * @private   
   */            
  this.el = null;
  
  /**
   * Identifikator objektu okna.
   *    
   * @type string
   * @public
   * @readonly
   */            
  this.id = null; 
 
  /**
   * Objekt textovych promennych pro okno.
   *
   * <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>
   *    close
   *    title (pokud je pozadovan titulek okna)   
   * </pre>
   * 
   * @see Vyznam promennych je popsan ve zdrojaku.
   * @public      
   * @type object
   */
  this.texts = null;
  
  /**
   * Vlastnost, ktera rika, zda ma okno titulek. V takovem pripade je definovana vlastnost this.texts.title.
   *
   * @private
   * @type boolean
   */
  this.isTitle = false;
  
  /**
   * Element textu titulku okna. Lze pouzit pro vlastni dynamickou zmenu titulku.
   * 
   * @public
   * @type object element
   */
  this.elTitle = null;  
  
  /**
   * Element obsahu vygenerovaneho okna. Lze pouzit pro vlastni pristup k obsahu okna a dynamickou zmenu obsahu.
   * 
   * @see cfn_window#insertContent
   * @public
   * @type object element
   */
  this.elContent = null;
  
  /**
   * Sirka okna.
   * 
   * @private
   * @type int
   */
  this.width = null;
  
  /**
   * Vyska okna.
   *
   * @private
   * @type int
   */
  this.height = null;
  
  /**
   * Umisteni okna - top horniho leveho rohu.
   * 
   * @private
   * @type int
   */
  this.top = null;
  
  /**
   * Umisteni okna - left horniho leveho rohu.
   * 
   * @private
   * @type int
   */
  this.left = null;
  
  /**
   * Udalostni funkce odchytavani udalosti klavesnice.
   *    
   * @private
   * @type function
   */
  this.evKeypress = null;
   
   
  //konstanty
  /**
   * Kod klavesy, ktera zajisti zavreni okna. Vychozi nastaveni [Esc].
   *    
   * @constant
   * @type int
   */
  this.cCloseKeyCode = 27;
  
  /**
   * Zdroj obrazku ikony zavreni okna. 
   *   
   * @constant
   * @type string   
   */        
  this.cCloseImg = _imageDirectory + "w_close.png";
        

  this.darkbox = true;

  //preklady textu
  if ((p) && (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, "close", "Zavřít okno [Esc]");
  }
  //je-li definovan text titulku okna, zobrazovat titulek
  if ( (p) && (typeof(p.title) == "string") )
  {
    this.isTitle = true;
    this.texts.title = p.title;
  }

  if ( (p) && (typeof(p.id) == "string") ) this.id = p.id;

  if ( (p) && (typeof(p.width) == "string") ) this.width = p.width;
  if ( (p) && (typeof(p.height) == "string") ) this.height = p.height;
  if ( (p) && (typeof(p.top) == "string") ) this.top = p.top;
  if ( (p) && (typeof(p.left) == "string") ) this.left = p.left;  
  
  //vygenerovani okna
  this.create();
  
  this.insertContent(p.content);
  //if ( (p) && (typeof(p.content) == "object") ) this.insertContent(p.content);
  if ( (p) && (typeof(p.show) == "boolean") && (p.show == false) ) {} else this.show();     
}

// cfn_window je rozsirenim objektu cfn
cfn_window.prototype = new cfn;

/**
 * Metoda vygeneruje html kod okna.
 *
 * @private
 */    
cfn_window.prototype.create = function()
{
  var p = {
    el: "div",
    atr: [ ["class", "window"] ] }
  if (this.id != null) p.atr.push(["id", this.id]);
  this.el = this.ele(p);
   
  // "tlacitko" zavrit
  var p = {
    el: "img",
    atr: [ ["class", "close"], ["src", this.cCloseImg], ["alt", this.texts.close], ["title", this.texts.close], ["height", "25"], ["width", "25"], ["border", "0"], ["style", "z-index:210;"] ],
    ins: this.el }
  var close = this.ele(p);
  //ulozeni udalosti
  events.addEventListener(close, "click", this.close, this);
  this.evKeypress = events.addEventListener(document, "keypress", this.keyPress, this);
  
  var t = this.ele( { el: "table", atr: [ ["class", "border"] ], ins: this.el } );
  var tb = this.ele( { el: "tbody", ins: t } );
  
  var tr = this.ele( { el: "tr", atr: [ ["class", "wtopline"] ], ins: tb } );
  this.ele( { el: "td", atr: [ ["class", "wcorner wleft"] ], ins: tr }  );
  this.ele( { el: "td", atr: [ ["class", "wtop"] ], ins: tr }  );
  this.ele( { el: "td", atr: [ ["class", "wcorner wright"] ], ins: tr }  );
  
  var tr = this.ele( { el: "tr", atr: [ ["class", "wcontent"] ], ins: tb } );
  this.ele( { el: "td", atr: [ ["class", "wleft"] ], ins: tr }  );
  this.elContent = this.ele( { el: "td", atr: [ ["class", "wcontent"] ], ins: tr }  );
  this.ele( { el: "td", atr: [ ["class", "wright"] ], ins: tr }  );
  
  var tr = this.ele( { el: "tr", atr: [ ["class", "wbottomline"] ], ins: tb } );
  this.ele( { el: "td", atr: [ ["class", "wcorner wleft"] ], ins: tr }  );
  this.ele( { el: "td", atr: [ ["class", "wbottom"] ], ins: tr }  );
  this.ele( { el: "td", atr: [ ["class", "wcorner wright"] ], ins: tr }  );

  if (this.isTitle)
  {
    var d = this.ele( { el: "div", atr: [ ["class", "title"] ], ins: this.elContent } );
    this.ele( { el: "span", txt: this.texts.title, ins: d } );
  }
  
  //vygenerovat content blok
  this.elContent = this.ele( {
    el: "div", 
    atr: [ ["class", "box"], ["id", "window_content"], ["style", "width:"+(parseInt(this.width))+"px; height:"+(parseInt(this.height))+"px;"] ], 
    ins: this.elContent } 
  );
  
  //vlozit do dokumentu
  if (this.darkbox)
  {
    this.createDarkbox();
    this.ins(this.el, this.elDarkbox);  
  }
  else
  {
    this.ins(this.el, document.getElementById("js_add_box"));
  }

  //nastavit parametry okna
  if (this.width != null) this.el.style.width = (parseInt(this.width) + 11 + 11 + 20) + "px";
  if (this.height != null) this.el.style.height = (parseInt(this.height) + 38 + 11) + "px";
  
  /*if (this.width != null) this.elContent.style.width = parseInt(this.width) + "px";
  if (this.height != null) this.elContent.style.height = parseInt(this.height) + "px";*/
  
  var pos_top = (document.documentElement.scrollTop)?document.documentElement.scrollTop:document.body.scrollTop;
  var pos_left = (document.documentElement.scrollLeft)?document.documentElement.scrollLeft:document.body.scrollLeft;
  var screen_width = document.documentElement.clientWidth;
  var screen_height = document.documentElement.clientHeight;
  
  if (this.left == null)
  {
    this.el.style.left = (pos_left + (screen_width / 2.0) - (this.el.offsetWidth / 2.0)) + "px";
  }
  if (this.top == null)
  {
    this.el.style.top = ((screen_height / 2.0) - (this.el.offsetHeight / 2.0)) + "px";
  }
  
/* generuje tuhle strukturu:

<div class="window">
  <img class="close" src="w_close.png" alt="Zavřít okno" title="Zavřít okno [Esc]" border="0" height="25" width="25" />
  
  <table class="border">
  
    <tr class="topline">
      <td class="corner left"></td>
      <td class="top"></td>
      <td class="corner right"></td>
    </tr>
    
    <tr class="content">
      <td class="left"></td>
      <td class="content">
        <div class="title"><span>Window title</span></div>
        <div class="box">
          text okna
        </div>
      </td>
      <td class="right"></td>
    </tr>

    <tr class="bottomline">
      <td class="corner left"></td>
      <td class="bottom"></td>
      <td class="corner right"></td>
    </tr>
    
  </table>
</div>
*/
}

cfn_window.prototype.createDarkbox = function()
{
  var p = {
    el: "div",
    atr: [ ["class", "darkbox"] ] }
  this.elDarkbox = this.ele(p);
 
  this.ins(this.elDarkbox, document.getElementById("js_add_box"));
  
  var pos_top = (document.documentElement.scrollTop)?document.documentElement.scrollTop:document.body.scrollTop;
  var pos_left = (document.documentElement.scrollLeft)?document.documentElement.scrollLeft:document.body.scrollLeft;
  var screen_width = document.documentElement.clientWidth;
  var screen_height = document.documentElement.clientHeight;
  
  this.elDarkbox.style.top = pos_top + "px";
  this.elDarkbox.style.left = pos_left + "px";
  this.elDarkbox.style.height = screen_height + "px";
  this.elDarkbox.style.width = screen_width + "px";

  document.getElementsByTagName("body")[0].style.overflowY = "hidden"; 
}

cfn_window.prototype.destroyDarkbox = function()
{
  this.elDarkbox.parentNode.removeChild(this.elDarkbox);
  document.getElementsByTagName("body")[0].style.overflowY = "auto";
}

/**
 * Metoda osetruje stisk klavesy behem zobrazeni okna.
 * 
 * Pokud je stisknuta klavesa {@link cfn_window#cCloseKeyCode} vola {@link cfn_window#close}.  
 *
 * @public
 */    
cfn_window.prototype.keyPress = function(e)
{
  if (events.keyPressedCode(e) == this.cCloseKeyCode) this.close();
}

/**
 * Metoda zrusi okno.
 *
 * @public
 */    
cfn_window.prototype.close = function()
{ 
  events.removeEventListener(document, "keypress", this.evKeypress);
  
  this.el.parentNode.removeChild(this.el);
  
  if (this.darkbox)
  {
    this.destroyDarkbox();
  }

  this.el = null;
}

/**
 * Metoda zobrazi vygenerovane okno.
 *
 * @public
 */
cfn_window.prototype.show = function()
{
  this.el.style.visibility = "visible";
  
  //nastavit parametry okna
  if (this.top != null) this.el.style.top = this.top;
  if (this.left != null) this.el.style.left = this.left;
}

/**
 * Metoda skryje vygenerovane okno.
 *
 * @public
 */
cfn_window.prototype.hide = function()
{
  this.el.style.visibility = "hidden";
}

/**
 * Metoda vlozi nebo zmeni obsah okna.
 *
 * @param {object DOM} c DOM obsahu okna 
 * @public
 */
cfn_window.prototype.insertContent = function(c)
{
  this.ins(c, this.elContent);
}


/**
 * Objekt pro dynamickou navigaci CFN/Kinobox
 *
 * <p>Zajistuje dynamiku navigaci CFN/Kinobox v designu V3.</p>
 * 
 * <p>Struktura vstupniho objektu:</p> 
 * <pre>
 *    id     - string - povinny
 *           - identifikator UL seznamu primarni navigace
 * </pre>    
 * 
 * @example Typicke pouziti     
 *   var mainmenu = new menu( {id:"navigation"} ); 
 *  
 * @class menu - dynamika hlavni navigace - vzdy dostupne
 * @extends cfn
 * @version 1.2
 * @since cfn v2.5 
 * @constructor
 * @requires events Udalosti
 * @param {object} p Objekt vstupnich parametru
 */
function menu(p)
{
  /*deb*/
  /**
   * Priznak vypisovani debug informaci. Je-li hodnota true, vypisuji se debug informace objektu.
   * @type boolean
   * @private      
   */     
  this.debug = false;
  /*deb*/
  
  /**
   * Element primarni navigace (UL)
   * @type object HTMLUListElement
   * @private      
   */     
  this.el = null;
  
  /**
   * Index pole {@link menu#primary} urcujici aktivni dynamicky otevrenou polozku primarni navigace.
   * Hodnota null znaci, ze neni nic otevreno (tedy vlastne je otevrena vychozi primarni navigace urcena pri zpracovani php interpretu).
   * @type int
   * @private         
   */     
  this.openIndex = null;
    
  //nalezeni elementu navigace, 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() != "UL") return;

  /**
   * Pole objektu popisujici vsechny polozky primarni navigace.
   * 
   * <pre>
   * Struktura objektu v poli:
   *    obj (object HTMLLIElement} 
   *         element sekundarni navigace pro tuto polozku primarni navigace   
   *    txt {string}
   *         text polozky primarni navigace
   *    sel {boolean}
   *          priznak vychozi vybrane polozky primarni navigace   
   *    sec {boolean}
   *          priznak zda obsahuje polozka primarni navigace nejakou subnavigaci            
   * </pre>
   *                
   */     
  this.primary = new Array();
  
  //vyhledat vsechny polozky primarni navigace
  for (var i=0; i<this.el.childNodes.length; i++)
  {    
    if (this.el.childNodes[i].childNodes.length > 0)  //prochazet jen uzly LI
    {
      
      this.primary.push( { 
        obj: this.el.childNodes[i], 
        txt: this.getText(this.el.childNodes[i].childNodes[0]), 
        sel: ( (this.getClass(this.el.childNodes[i]) == "on") ? true : false),
        sec: ( (this.el.childNodes[i].getElementsByTagName("UL").length > 0) ? true : false)
      } );
      
    }
  }
  
  //projit pole primarni navigace a pripadne navazat udalosti pro rozpohybovani sekundarni navigace 
  for (var i=0; i<this.primary.length; i++)
  {
    /*deb*/
    this.deb( 
      this.primary[i].obj + " " + 
      this.primary[i].txt + " " + 
      this.primary[i].sel + " " +
      this.primary[i].sec);
    /*deb*/
      
    if ( (this.primary[i].sec) && (!this.primary[i].sel) )    //vychozi vybranou polozku neresit
    {
      //navazat udalosti
      events.addEventListener(this.primary[i].obj, "mouseover", this.showSecond, this);
      events.addEventListener(this.primary[i].obj, "mouseout", this.hideSecond, this);
    }
  }

}

// menu je rozsirenim objektu cfn
menu.prototype = new cfn;

/*deb*/
/**
 * Redefinice metody deb pro vypisovani debug zprav.
 *
 * @param {mixed} text Obsah poslany do debug okna 
 * @private
 */    
menu.prototype.deb = function(text)
{
  if (this.debug)
  {
    //volej predka s prefixem
    cfn.prototype.deb.call(this, text, "menu-> ");
  } 
}
/*deb*/

/**
 * Metoda zobrazi sekundarni navigaci.
 *
 * @param {object event} e Udalostni objekt, ktery predava jadro obsluznym funkcim (ev. se ziskava jinak) 
 * @private
 */
menu.prototype.showSecond = function(e)
{  
  if (!e) var e = window.event;

  if (this.openIndex != null) this.hideSecond(e); //pokud je neco otevreno, okamzite to zavri
 
  //najdi polozky primarni navigace od kere se ma otevrnit sekundarni subnavigace
  for (var i=0; i<this.primary.length; i++)
  {     
    if (this.primary[i].obj.getElementsByTagName("A")[0] == events.eventSource(e))
    {
      /*deb*/
      this.deb("show " + this.primary[i].txt);
      /*deb*/
      
      if (this.primary[i].sec)
      {
        this.addClass(this.primary[i].obj, "on2");    //definice css tridy, ktera zajisti spravne zobrazeni subnavigace
      }
            
      this.openIndex = i;
      break;
    }
  }
    
  //zrusit dalsi probublavani udalosti
  e.cancelBubble = true;
  if (e.stopPropagation) e.stopPropagation();
}

/**
 * Metoda skryje sekundarni navigaci.
 *
 * @param {object event} e Udalostni objekt, ktery predava jadro obsluznym funkcim (ev. se ziskava jinak) 
 * @private
 */
menu.prototype.hideSecond = function(e)
{
  if (!e) var e = window.event;
 
  if (this.openIndex != null)
  {
  
    if ( ( (events.mouseoutTarget(e).tagName == "UL") && (events.mouseoutTarget(e).parentNode == this.primary[this.openIndex].obj) ) || 
         ( (events.mouseoutTarget(e).tagName == "A") && (events.mouseoutTarget(e).parentNode.parentNode.parentNode == this.primary[this.openIndex].obj) ) ||   //IE
         ( (events.mouseoutTarget(e).tagName == "A") && (events.mouseoutTarget(e).parentNode == this.primary[this.openIndex].obj) ) ) //Mozilla
    {
     
    }
    else
    {
      /*deb*/
      this.deb("hide " + this.primary[this.openIndex].txt);
      /*deb*/ 
      
      if (this.primary[this.openIndex].sec)
      {
        this.removeClass(this.primary[this.openIndex].obj, "on2");    //odstraneni css tridy zajisti skryti subnavigace a zobrazeni vychozi subnavigace
      }
      
      this.openIndex = null; 
    }
  }
}
