/**
 * ~form.js
 * *** knihovna ktera umi zalozky ***
 * @author 2008 Michal Sobola, msobola@seznam.cz
 * @revision 2009-11-22
 * @version 2.0.1
 **/

/**
 * ~ changelog from 2.0
 * 2.0.1 - fixed bug Form.checkOnSubmit()
 *       - fixed bug Form.testRegExp()
 *       - trida InputHandler umi i file inputy, limit nakliknutych polozek a rozlisuje zpusob generovani jmen
 **/

/**
 * prida klic do pole
 * @param array arr
 * @param mixed value  
 **/ 
Array.prototype.append = function(value) {
  if (value !== undefined) {
    this[(this.length)] = value;
  } else {
    this[(this.length)] = null;
  }
}

/**
 * vrati vyjimku ve stringu
 * @param object err
 * @return string  
 **/ 
function getException(error) {
  output = '';
  for (i in error) {
    output += error[i] + '\n';
  }
  return output;
}

/**
 * ekvivalent k php strip_tags
 * @param string html
 * @return string  
 **/ 
function strip_tags(html){
	if (arguments.length < 3) {
		html = html.replace(/<\/?(?!\!)[^>]*>/gi, '');
	} else {
		allowed = arguments[1];
		specified = eval("["+arguments[2]+"]");
		if (allowed) {
			regex='</?(?!(' + specified.join('|') + '))\b[^>]*>';
			html = html.replace(new RegExp(regex, 'gi'), '');
		} else {
			regex = '</?(' + specified.join('|') + ')\b[^>]*>';
			html=html.replace(new RegExp(regex, 'gi'), '');
		}
	}
	return html;
}
	
/**
 * ekvivalent k php array_key_exists
 * @param string key
 * @param array | object item
 * @return bool   
 **/
function array_key_exists(key, value) {
  return value[key] !== undefined ? true : false;
}

/**
 * ekvivalent k PHP trim (bez druheho parametru) zdroj: jquery 
 * @param string arg
 * @return arg
 **/
function trim(arg) {
  return (arg || '').replace( /^\s+|\s+$/g, '');
}

/**
 * ekvivalent k PHP in_array (bez tretiho parametru)
 * @param string needle
 * @param array haystack      
 **/
function in_array(needle, haystack) {  
  for (i in haystack) {
    if (needle == haystack[i]) {
      return true;
    }
  }
  return false;  
}

/**
 * pretypovani na bool
 * @return bool 
 **/ 
function bool(arg) {
  return arg ? true : false;
}

/**
 * je IE, popripade jaka verze?
 * @param int no
 * @return bool 
 **/ 
function isIE(no) {
  return (navigator.appVersion).indexOf('MSIE ' + (no ? no : '')) != -1 ? true : false;
}

/**
 * vytvori ajax request
 * potrebuje funkci getException() 
 * @return object
 **/
function createRequest(debug) {
  this.httpRequest = null;
  if (window.XMLHttpRequest) {
    this.httpRequest = new XMLHttpRequest();
    if (this.httpRequest.overrideMimeType) {
      this.httpRequest.overrideMimeType('text/html');
    }
  } else if (window.ActiveXObject) {
    try {
      this.httpRequest = new ActiveXObject('Msxml2.XMLHTTP');
    } catch (err) {
      try {
        this.httpRequest = new ActiveXObject('Microsoft.XMLHTTP');
      } catch (err) {
        if (debug !== undefined && debug) {
          alert(getException(err));
        }
      }
    }
  }
  return this.httpRequest;
}
/**
 * Validace formulare
 * @var object
 **/
 
/**

  // Form.setDebug(1);
  // Form.setBorders('#D2364E', '#AAAAAA'); // cerveny ramecek | vychozi ramecek - argumenty jsou nepovinne
  // Form.setMessages('Following required field was empty:', 'Following field has wrong format:'); // prazdne pole | pole ma chybny tvar
  // Form.setImages('images/false.gif', 'images/true.gif'); // muzeme zavolat i bez argumentu, pak nastavi vychozi obrazky
  // Form.setImageClassName('validation_img'); // trida obrazku
  // Form.setImageIdPrefix('form_image_'); // id prefix obrazku
  Form.setForm('image_upload'); // povinne, nastavi ID formulare
  
  // Form.addRegexp('name', /^([0-9]{5,})$/i);
  
  // muzeme pridat jeste i 2 dalsi argumenty - regexp (pouze klic k poli regexp + id, pokud se lisi od name)
  <? foreach ($tpl['form'] as $value) { ?>
    Form.setField(0, '<?= $value['name'] ?>', '<?= $value['label'] ?>', '<?= $value['type'] ?>', '<?= $value['type_2'] ?>');
  <? } ?>

 **/ 
var Form = {

  /**
   * debug - vypis chyb
   * @var int
   **/
  debug : 1,
 
  /**
   * ramecky inputu - prvni je cerveny, druhy je vychozi
   * @var array
   **/
  borders : [
    'red', 
    '#aaa'
  ],

  /**
   * regulary
   * @var array
   **/
  objRegExp : {
    email : /^(([A-Za-z0-9]+_+)|([A-Za-z0-9]+\-+)|([A-Za-z0-9]+\.+)|([A-Za-z0-9]+\++))*[A-Za-z0-9]+@((\w+\-+)|(\w+\.))*\w{1,63}\.[a-zA-Z]{2,6}$/i,
    psc : /^([0-9.]{5,6}|[0-9 ]{5,6})$/i,
    phone : /^[+]?[()/0-9. -]{9,30}$/i,
    phone_strict : /^\+([0-9]{12})$/i,
    login : /^[.]{5,}$/i,
    passwd : /^[.]{6,}$/i
  },
  
  /**
   * chybove hlasky
   * @var array
   **/
  messages : {
    empty : ' • Následující povinná položka nebyla vyplněna: ',
    wrong : ' • Následující položka má špatný formát: '
  },
  
  /**
   * objekt formulare, ziskany z getElementById
   * @var object
   **/
  formular : null,
  
  /**
   * id formulare, ktery budeme kontrolovat
   * @var string
   **/
  formId : '',
  
  /**
   * povinne polozky
   * @var array
   **/
  fields : {},
  
  /**
   * chyby
   * @var string
   **/
  formErrors : '',
  
  /**
   * pouze kontrola typu
   * @var array
   **/
  types : [
    'select',
    'checkbox',
    'password',
    'text',
    'radio',
    'hidden',
    'textarea',
    'file'
  ],
  
  /**
   * typy, kt. se premalovava border
   * @var array   
   **/     
  typesToBorder : [
    'password',
    'text',
    'textarea',
    'file'    
  ],
  
  /**
   * typy, ktere nas nezajimaji
   * jedna se o atribut type_2, vubec neresime (pouze ajaxem)   
   * @var array   
   **/     
  disabledTypes : [
    'related',
    'multi_image',
  ],
  
  /**
   * obrazky
   * @var array
   **/
  images : false,
  
  /**
   * image id prefix
   * @var string
   **/
  imageIdPrefix : 'form_image_',
  
  /**
   * trida obrazku
   * @var string
   **/
  imageClassName : 'validation_img',

  /**
   * metody na nastaveni povinnych i nepovinnych parametru
   *    
   **/     
  setDebug : function(debug) {
    if (debug !== undefined) {
      this.debug = bool(debug);
    }
  },
  
  setBorders : function(redBorder, defBorder) {
    if (redBorder) {
      this.borders[0] = redBorder;
    }
    if (defBorder) {
      this.borders[1] = defBorder;
    }
  },
  
  setMessages : function(emptyMessage, wrongMessage) {
    if (emptyMessage) {
      this.messages.empty = emptyMessage;
    }
    if (wrongMessage) {
      this.messages.wrong = wrongMessage;
    }
  },
  
  setImages : function(falseImage, trueImage) {
    falseImage = (falseImage ? falseImage : 'images/false.gif');
    trueImage = (trueImage ? trueImage : 'images/true.gif');
    this.images = {
      'true' : trueImage,
      'false' : falseImage
    };
  },
  
  setImageClassName : function(imageClassName) {
    this.imageClassName = imageClassName;
  },
  
  setImageIdPrefix : function(imageIdPrefix) {
    this.imageIdPrefix = imageIdPrefix;
  },
  
  /**
   * nastavi formular
   * jedina povinna set metoda   
   * @param string formId   
   **/     
  setForm : function(formId) {
    this.formId = formId;
    this.formular = document.getElementById(formId);
    if (this.formular === null) {
      return this.writeError('Form of id <strong>' + formId + '</strong> is null.');
    }
    this.formular.onsubmit = function () {
      return (!Form.checkOnSubmit() ? false : true);
    };
  },
  
  /**
   * prida regular do pole regularu
   * @param string name
   * @param string value      
   **/
  addRegexp : function(name, value) {
    this.objRegExp[name] = value;
  },

  /**
   * vypise hlasku je-li ze zaply debug, else nic neudela
   * @param string message   
   **/     
  writeError : function(message) {
    if (this.debug) {
      document.writeln('<span style="color:red">' + message + '</span><br />');
    }
  },

  /**
   * nastavi povinne pole, kt. budeme kontrolovat
   * @param string name
   * @param enum type
   * @param string label
   * @param bool required
   * @param string regexp klic k poli objRegExp   
   * @param string [id] if undefined, prepokladame id == name        
   **/
  setField : function(required, name, label, type, type_2, regexp, id) {
    
    // nepovinny argument
    if (id === undefined) {
      id = name;
    }
    
    // kvuli kompatibilite s dalsi formularovou knihovnou
    if (type == 'bool') {
      type = 'checkbox';
    }

    if (type == 'html') {
      type = 'textarea';
    }
    
    // kontrola typu
    if (!in_array(type, this.types)) {
      type = 'text';
    }
    
    required = bool(required);

    // kontrola regularu
    if (regexp === undefined || !regexp) {
      regexp = null;
    } else {
      if (!this.objRegExp[regexp]) {
        this.writeError('Invalid RegExp name: <strong>' + regexp + '</strong>. Check the <em>objRegExp</em> variable or add it using method <em>Form.addRegexp(name, value)</em>');
        regexp = null;
      }
    }
    
    object = document.getElementById(id);
    
    if (!in_array(type_2, this.disabledTypes)) {
      if (object !== null) {
        if (object.type == 'radio' && required) {
          return this.writeError('Radio button can not be required. Use just html checked="checked" for one of the inputs.');
        } else if (type == 'select' && type_2 == 'related' && required) {
          return this.writeError('Related select can not be required.');
        }
      } else {
        return this.writeError('document.getElementById(' + id + ') is null. Will not check this field.');
      }
  
      // kontrola spravnosti nacteneho prvku
      if (object.tagName != 'INPUT' && object.tagName != 'SELECT' && object.tagName != 'TEXTAREA') {
        return this.writeError('Element of id <strong>' + id + '</strong> is not valid form element. Duplicate id possible.');
      }
  
      // kontrola jestli budeme za input generovat krizky a fajfky, pridani akci polozce
      if (this.images && required) {
        try {
          newImage = document.createElement('img');
          newImage.alt = '#';
          newImage.id = this.imageIdPrefix + id;
          newImage.className = this.imageClassName;
          newImage.src = this.images[(this.checkIt(object, regexp) ? 'true' : 'false')];
          this.insertAfter(newImage, object);
        } catch (err) {
          return this.writeError(err);
        }
  
        if (object.type == 'checkbox' || type == 'select') {
          object.onclick = function() { Form.checkField(this); };
          object.onchange = function() { Form.checkField(this); };
        } else {
          object.onkeyup = function() { Form.checkField(this); };
          object.onblur = function() { Form.checkField(this); };
        }
      }
    }
    
    // prirazeni inputu do pole
    this.fields[id] = {
      id : id,
      name : name, 
      type : type,
      type_2 : type_2, 
      label : label, 
      object : object, 
      regexp : regexp, 
      required : required
    };
  },
  
  /**
   * kontrola inputu kdyz se do nej pise, konci zavolanim funkce o jedno niz
   * @param object object   
   **/
  checkField : function(object) {
    image = document.getElementById(this.imageIdPrefix + (object.id ? object.id : object.name));
    if (image) {
      source = (this.checkIt(object) ? 'true' : 'false');
      if (source == 'true' && this.borders[1]) {
        object.style.borderColor = this.borders[1];
      }
      return image.src = this.images[source];
    } else {
      return true;
    }
  },
  
  /**
   * kontrola value, volano vnitrne
   * @param object object
   * @param string regexp      
   **/
  checkIt : function(object, regexp) {
    if (regexp === undefined) {
      regexp = this.fields[object.id].regexp;
    }
    if (object.type == 'checkbox') {
      return object.checked;
    } else {
      if (regexp !== null) {
        return this.testRegExp(regexp, object.value);
      } else {
        return object.value != '' ? true : false;
      }
    }
  },

  /**
   * vytvori element za jinym elementem
   * @param object document.createElement(vysledek)
   * @param object document.getElementById(rodic)
   **/
  insertAfter : function(item, referenceNode) {
    referenceNode.parentNode.insertBefore(item, referenceNode.nextSibling);
  },
  
  /**
   * vytvori element pred jinym elementem
   * @param object document.createElement(vysledek)
   * @param object document.getElementById(rodic)
   **/
  insertBefore : function(item, referenceNode) {
    referenceNode.parentNode.insertBefore(item, referenceNode);
  },

  /**
   * test regularu
   * @param ref klic pole this.objRegExp
   * @param value testovana hodnota      
   **/
  testRegExp : function(ref, value) {
    if (this.objRegExp[ref]) {
      return this.objRegExp[ref].test(value) ? true : false;
    } else {
      return false;
    }
  },

  /**
   * kontrola po odeslani formulare
   * typy erroru, kt. se nastavuji v cyklu : 
   * 0 = vse ok
   * 1 = prazdne
   * 2 = neshoda s regularem            
   **/
  checkOnSubmit : function() {
    try {
      for (var i in this.fields) {
        if (this.fields[i].required) {
					if (this.fields[i].type == 'checkbox' && this.fields[i].object.checked === false) {
          	continue;
					}
					value = trim(this.fields[i].object.value);
					if (!value) {
						this.fields[i]['object'].style.borderColor = this.borders[0];
						this.formErrors += this.messages.empty + ' ' + this.fields[i].label + '\n';
						continue;
					}

					if (this.fields[i].regexp && !this.testRegExp(this.fields[i].regexp, value)) {
						this.fields[i]['object'].style.borderColor = this.borders[0];
						this.formErrors += this.messages.wrong + ' ' + this.fields[i].label + '\n';
						continue;
					}
					
					if (this.fields[i]['object'].style.borderColor == this.borders[0]) {
						this.fields[i]['object'].style.borderColor == this.borders[1]
					}
        }
        error = 0;
      }
      if (this.formErrors) {
        alert(this.formErrors);
        this.formErrors = '';
        return false;
      } else {
        return true;
      }
    } catch (err) {
      if (this.debug) {
        alert(getException(err));
        return false;
      } else {
        return true;
      }
    }
  }, 
  
  /**
   * projede multiselect a odskrtne vsechny optiony
   * @param string id
   **/
  unSelect : function(id) {
    options = document.getElementById(id).getElementsByTagName('option');
    for (i in options) {
      options[i].selected = false;
    }
  }
};

/**
 * textarea resizer
 * zdroj: 4umi.com/web/javascript/textarearesize.htm
 * modifikovano pro resizovani vice textarei pod sebou, povoleni smeru pouze nahoru a dolu   
 **/

/**

  // AreaResizer.setBgImg('images/resize.gif'); // obrazek
  // AreaResizer.setClassName('textarea_resizer'); // className divu
  // AreaResizer.setIdPatter('_resizer'); // vzor pro ID divu
  
  AreaResizer.addArea('textarea_id'); // pridame jednu textareu na resize
  AreaResizer.init(null); // pokud je null, budeme resizovat jen to, co jsme vlozili pomoci metody setArea()
  
  // AreaResizer.init(); // budeme resizovat vsechny textarey, ktere na strance jsou

 **/
var AreaResizer = {

  /**
   * nastaveni
   * @var object   
   **/
  config : {
    bgImg : 'images/resize.gif',
    className : 'textarea_resizer',
    idPattern : '_resizer'  
  },
  
  /**
   * seznam idcek textarei, kt. budeme resizovat
   * je-li prazdne, tahaji se vsechny
   * @var array      
   **/
  textareas : new Array(),
  
  /**
   * vlozi novou textareu do pole textarei
   * @param string name   
   **/
  addArea : function(name) {
    this.textareas.append(name);
  },

  /**
   * nastaveni nepovinna
   *    
   **/
  setBgImg : function(bgImg) {
    this.config.bgImg = bgImg;
  },
  
  setClassName : function(itemClassName) {
    this.config.className = itemClassName;
  },
  
  setIdPattern : function(idPattern) {
    this.config.idPattern = idPattern;
  },

  /**
   * spusteni
   * @param what - bud null nebo nic. pokud je null, bude se vzdy resizovat jen to, co je ulozeno v poli this.textareas
   **/
  init : function(what) {
    
    /**
     * zmena pozice prvku
     * @param object obj     
     **/
    function loopPositions(obj) {
      var x = 0;
      var y = 0;
      
      do {
        x += obj.offsetLeft;
        y += obj.offsetTop;
      } while (obj = obj.offsetParent);
      
      if (document.all) {
        return { x:(x+3), y:(y+1) };
      } else {
        return { x:x, y:(y-1) };
      }
    }

    /**
     * zachyceni udalosti
     * @param object e     
     **/
    function g(e) {
      e = e || window.event || {};
      return 'number' === typeof e.clientY ? { x:e.clientX, y:e.clientY } : { x:e.x, y:e.y };
    }
    
    /**
     * obecna zmena stylu - zpravidla vlastnosti top, left, height, width
     * @param object obj
     * @param object style
     * @param string value          
     **/
    function changeStyleValue(obj, style, value) {
      obj.style[style] = Math.max(1, value) + 'px';
    }

    var a = new Array;
    var m = document.createElement('div');
    var o;
    var p;
    var s = 11;
    var sh = 10;
    var t;
    var x = s + 'px';
    var y = sh + 'px';

    // nacteme vsechny textarey do pole
    if (!this.textareas.length && what !== null) {
      a = document.getElementsByTagName('textarea');
    } else {
      for (j = 0; j < this.textareas.length; j++) {
        a[j] = document.getElementById(this.textareas[j]);
      }
    }
    
    var i = a.length;
    if (!i) {
      return;
    }

    // obecne styly pro vsechny resizery, lze zmenit v css dle tridy, nutne vsak dodat !important
    m.style.background = 'url(' + this.config.bgImg + ') no-repeat 0 100%';
    m.style.position = 'relative';
    m.style.cssFloat = 'left';
    m.style.cursor = 'n-resize';
    m.style.width = '11px';
    m.style.height = '11px';
    m.style.left = '-11px';
    m.style.position = 'relative';
    
    if (isIE(6)) {
      m.style.left = '-15px';
      m.style.marginTop = '-5px';
    }
    
    if (isIE(8)) {
      m.style.display = 'table-cell'
    }
    
    m.className = this.config.className;

    // od spoda nahoru projizdime vsechny textarey
    while(i--) {
      t = a[i];
      p = loopPositions(t);
      
      // naklonujeme prvek, kt. jsme si predvytorili
      o = m.cloneNode(true);
      
      // unikatni html id
      o.id = t.name + this.config.idPattern;

      o.style.top = t.offsetHeight-11 + 'px';

      // kazdemu nove vytvorenemu prvku pridame akci
      o.onmousedown = function(evt) {
        ob = this;
        p = loopPositions(ob);
        q = g(evt);
        ob.oX = q.x-p.x;
        ob.oY = q.y-p.y;

        // pohybujeme kurzorem
        document.onmousemove = function(e) {
          // textarea je hned pred resizerem
          p = loopPositions(ob.previousSibling);
          q = g(e);
          
          // resizneme textareu
          changeStyleValue(ob.previousSibling, 'height', Math.max(sh, q.y-ob.oY-p.y+6));

          // posuneme dolu
          ob.style.top = ob.previousSibling.offsetHeight-11 + 'px'; 
        };
        
        document.onselectstart = function() {
          return false;
        };
        
        // pusteni mysitka
        document.onmouseup = function() {
          ob = null;
          document.onmousemove = null;
          document.onselectstart = null;
          document.onmouseup = null;

          // osetreni, pac to blbne kdyz chci resizovat 2x po sobe (bylo nutne kliknout pryc)
          document.body.focus();
        };
      };

      // vytvorime prvek hned za textareou
      Form.insertAfter(o, t);
    }
  }
};

/**
 * InputHandler
 * *** obsluha naklikavajicich se nesmyslu ***
 * mod : pri nastaveni na array se generuji jmena formularovych prvku jako name[], name[], atd...
 * mod : pri nastaveni na simple se generuji jmena jako name_1, name_2, atd...  
 **/
 
var ARRAY_MODE = 'array';
var SIMPLE_MODE = 'simple';

function InputHandler() {

  /**
   * pocitadlo - pri generovani polozek phpkem
   * kolik polozek uz mame - kvuli limitu, IDckam a jmenum   
   **/     
  this.counter = 0;

  this.button = {
    value : 'Smazat',
    className : 'submit button'
  };

  var params = new Array();
  
  /**
   * mody - bud vychozi 'array' nebo 'simple'
   * @var enum   
   **/	   
  var mode = 'array';
  
  /**
   * limit - kolik toho muzeme nakliknout max
   * @var int   
   **/     
  var limit = 0;
  
  var defaultWasAdded = 0;

  var that = this;
  
  this.setMode = function(arg) {
		mode = arg;
	};
	
	this.setLimit = function(arg) {
		limit = arg;
	};
 
  this.addParam = function(value) {
    try {
      params.append(value);
    } catch (err) {
      if (Form.debug) {
        alert(getException(err));
      }
    }
  };
  
  /**
   * prida vychozi parametry
   * mazaci inputek, radkovy zlom a prazdny label   
   **/     
  this.addDefaultParams = function(appendBr, appendLabel) {
    try {
      params.append({
        type : 'del'
      });
      if (appendBr === undefined && appendBr != false || appendBr) {
        params.append({
          type : 'br'
        });
       defaultWasAdded++; 
      }
      if (appendLabel === undefined && appendLabel != false || appendLabel) {
        params.append({
          type : 'label',
          innerHTML : '&nbsp;'
        });
        defaultWasAdded++;
      }
    } catch (err) {
      if (Form.debug) {
        alert(getException(err));
      }
    }
  };
  
  this.getParams = function() {
    return params;
  };

  this.addItem = function(self) {  
  	if (limit && this.counter >= limit) {
			return false;
		}
    
    try {
      elem = null;
      for (i = 0; i < params.length; i++) {
        if (typeof params[i].type == 'undefined') {
          continue;
        }
        switch (params[i].type) {
          case 'br' :        
            elem = document.createElement('br');
          break;
          case 'del' :
            elem = document.createElement('input');
            elem.className = this.button.className;
            elem.value =  this.button.value;
            elem.type = 'button';
            elem.name = '';
            elem.onclick = function() {
              that.unset(this);
            };
          break;
          case 'label' :   
            elem = document.createElement('label');
            if (array_key_exists('className', params[i])) {
              elem.className = params[i].className
            }
            if (array_key_exists('innerHTML', params[i])) {
              elem.innerHTML = params[i].innerHTML
            }         
          break;
          case 'textarea' :
          	elem = document.createElement('textarea');
            if (array_key_exists('innerHTML', params[i])) {
              elem.innerHTML = params[i].innerHTML
            }
            if (array_key_exists('className', params[i])) {
              elem.className = params[i].className
            }
            if (array_key_exists('rows', params[i])) {
              elem.rows = params[i].rows
            }
            if (array_key_exists('cols', params[i])) {
              elem.cols = params[i].cols
            }
            elem.name = (mode ==  ARRAY_MODE ? params[i].name+'[]' : params[i].name + this.counter);
            elem.id = params[i].name+'_'+this.counter;
          break;
          case 'select' :    
            if (document.all) {
              elem = document.createElement('span');
              if (array_key_exists('innerHTML', params[i])) {
              	itemName = (mode ==  ARRAY_MODE ? params[i].name+'[]' : params[i].name + this.counter);
                elem.innerHTML = '<select name="' + itemName + '" id="' + params[i].name + '_' + i + '">' + params[i].innerHTML + '</select>';
              }
            } else {
              elem = document.createElement('select');
              elem.name = (mode ==  ARRAY_MODE ? params[i].name+'[]' : params[i].name + this.counter);
              elem.id = params[i].name + '_' + this.counter;
              if (array_key_exists('innerHTML', params[i])) {
                elem.innerHTML = params[i].innerHTML;
              }
            }
          break;
          case 'input' :
            elem = document.createElement('input');
            elem.type = (array_key_exists('inputType', params[i]) ? params[i].inputType : 'text');
            elem.name = (mode ==  ARRAY_MODE ? params[i].name+'[]' : params[i].name + this.counter);
            elem.id = params[i].name + '_' + this.counter;
            if (array_key_exists('className', params[i])) {
              elem.className = params[i].className;
            }
            params[i].id = elem.id;
          break;
          case 'a' :
            elem = document.createElement('a');
            elem.href = (params[i].href).replace('%i', params[i-1].id);
            elem.innerHTML = params[i].innerHTML;
            elem.title = params[i].title;
            elem.className = params[i].className;
            if (array_key_exists('onclick', params[i])) {
              elem.onclick = params[i].onclick;
            }
            if (array_key_exists('target', params[i])) {
              elem.target = params[i].target;
            }
          break;
          default:
            continue;
          break;
        }
        if (elem !== null) {
          Form.insertBefore(elem, self);
        }
      }
      this.counter++;
    } catch (err) {
      if (Form.debug) {
        alert(getException(err));
      }
    }
  };

  this.unset = function(self) {
    for (i = 0; i < params.length - defaultWasAdded - 1; i++) {
      self.parentNode.removeChild(self.previousSibling);
    }
    for (i = 0; i < defaultWasAdded; i++) {
      self.parentNode.removeChild(self.nextSibling);
    }
    self.parentNode.removeChild(self);
    that.counter--;
  };
}

/**
 * Ajax form
 * *** ajaxove zpracovani formulare ***
 * trida je zavisla na vyse definovanem objektu
 * @param string [submitButtonName] name tlacitka na ajaxove ulozeni
 *
 * nasazeni : 
 * staci vytvorit instanci a v parametru pridat jmeno buttonku (nepovinne)
 * buttonek s danym name samozrejme musi existovat ve formulari. predavano v konstruktoru
 *  
 * nastaveni debugu je brano z objektu Form
 *  
 * AjaxForm = new AjaxForm();
 **/
function AjaxForm(submitButtonName) {

  this.submitButtonName = 'ajax_save';
  
  this.requestParam = '?ajax=1';
  
  this.requestUrl = '';

  this.httpRequest = null;
  
  this.loaderImage = 'images/admin/ajax.gif';
  
  this.loader = null;
  
  var activated;
  
  var submitButtons = {};
  
  var post = Form.fields;

  var url;

  var requestString = '';
  
  var that = this;
 
  this.AjaxForm = function() {

    // nataha vsechny submit inputy, aby se mohly disablovat pri odeslani. taky vybere ten spravny
    activated = false;
    inputs = Form.formular.getElementsByTagName('input');
    
    for (i in inputs) {
      if (typeof inputs[i] == 'object' && inputs[i].name == this.submitButtonName) {
      
        inputs[i].onclick = function() {
          that.request();
          return false;
        };
        inputs[i].style.display = 'inline';
        activated = true;
      }
      if (typeof inputs[i] == 'object' && (inputs[i].type == 'button' || inputs[i].type == 'submit')) {
        submitButtons[i] = inputs[i];
      }
    }

    if (!activated) {
      Form.writeError('Submit button with name <em>' + this.submitButtonName + '</em> haven\'t been found.');
    }
    
    try {
      this.loader = document.createElement('img');
      this.loader.src = this.loaderImage;
      this.loader.alt = 'Loading...';
      this.loader.style.position = 'absolute';
      this.loader.style.top = '50%';
      this.loader.style.left = '50%';
      this.loader.style.marginLeft = '-' + Math.ceil((this.loader.width/2)) + 'px';
      this.loader.style.marginTop = '-' + Math.ceil((this.loader.height/2)) + 'px';
      this.loader.style.display = 'none';
      if (window.onload) {
        Form.writeError('<b>Warning:</b> body.onload is an existing function that will be rewrited.');
      }
      window.onload = function() {
        document.body.appendChild(that.loader);
      };
    } catch (err) {
      Form.writeError(err);
    }
  };

  this.request = function() {
    this.loader.style.display = 'block';
    this.disableSubmits(true);
    this.httpRequest = createRequest(Form.debug);
    
    // sesklada request string
   try {
      len = 0;
      obj = null;
   
      for (i in post) {
        if (post[i].type_2 == 'related' || post[i].type_2 == 'multi_image') {
          switch (post[i].type_2) {
            case 'related' :
              possibleItems = document.getElementsByTagName('select'); 
            break;
            case 'multi_image' :
              possibleItems = document.getElementsByTagName('input');
            break;
          }
          k = 0;
          for (j in possibleItems) {
            if (possibleItems[j].name == post[i].name + '[]') {
              requestString += '&' +  post[i].name + '[' + k + ']=' + possibleItems[j].value;
              k++;
              len++;
            }
          }
        } else {
          obj = document.getElementById(i);
          if (obj.type == 'checkbox') {
            requestString += '&' + obj.name + '=' + (obj.checked ? 1 : 0);
            len++;
          } else if (obj.tagName == 'SELECT' && obj.multiple) {
            options = obj.getElementsByTagName('option');
            k = 0;
            for (j in options) {
              if (options[j].selected) {
                requestString += '&' + post[i].name + '[' + k + ']=' + options[j].value;
                k++;
                len++;
              }
            }
          } else {
            requestString += '&' + obj.name + '=' + escape(encodeURI(obj.value));
            len++;
          }
        }
        obj = null;
      }

      // zpracovani requestu
      requestString = requestString.replace(new RegExp('^&'), '');
      this.httpRequest.onreadystatechange = function() {
        that.parseRequest();
      };
  
      // zasle hlavicky
      this.httpRequest.open('POST', window.location.href + this.requestParam, true);
      this.httpRequest.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
      this.httpRequest.setRequestHeader('Content-length', len);
      this.httpRequest.setRequestHeader('Connection', 'close');
      this.httpRequest.send(requestString);
      
      requestString = '';
      len = 0;
      
    } catch (err) {
      if (Form.debug) {
        alert(getException(err));
      }
    }
  };
  
  this.parseRequest = function() {
    try {
      if ((that.httpRequest.readyState == 4) && (that.httpRequest.status == 200)) {
        if (that.httpRequest.responseText) {
          if (Number(that.httpRequest.responseText)) {
            window.location.href = window.location.href + that.httpRequest.responseText + '/';
          } else {
            alert(strip_tags(that.httpRequest.responseText));
          }
        }
        
        // znovu zaktivni submit buttony a skryje loadovaci kolecko
        that.disableSubmits(false);
        that.loader.style.display = 'none';
      }
    } catch (err) {
      if (Form.debug) {
        alert(getException(err));
      }
    }
  };
  
  this.disableSubmits = function(disabled) {
    for (i in submitButtons) {
      submitButtons[i].disabled = disabled;
    }
  };
  
  if (submitButtonName) {
    this.submitButtonName = submitButtonName;
  }
  
  this.AjaxForm();
}