/**
 * ~ func.js
 * *** hyper knihovna ***
 * *** soubor muzete libovolne modifikovat a sirit dal, jen prosim ponechte v kodu tuto hlavicku ***
 * @copyright 2010 Michal Sobola <msobola@seznam.cz> Luke Skywalker a Fox Mulder
 * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
 * @revision 2010-11-30
 * @version 1.3.2
 **/

/**
 * ~ funkce
 * + validace formulare
 * + naklikavatko formularovych prvku
 * + ajaxove odeslilani formulare
 * + jednoduche zalozky
 * + prace s getem a cookies
 * + detekce IE
 * + ekvivalenty php funkci : strip_tags, trim, in_array
 * + rozpoznavac skriptu volanych pres parametr
 * + funkce createOverLayer a destroyOverLayer
 * + hyperslider
 **/

/**
 * ~ changelog from 1.0
 * 1.0.1 - osetrena mozna absence objektu console
 *       - cele obaleno do try / catch
 *       - funkce pouzity v catch umisteny mimo try
 * 1.1.0 - pridano rozpoznavani parametru (main.php?param=value&param2=value2)
 * 1.1.1 - zalozkam pridano opacity pro hezci efekt
 * 1.2.0 - upraven InputHandler, zapomnel generovat IDcka
 * 1.2.1 - pro zalozky upraveno tak, aby kdyz je _cfg.activeTab null, tak to nezobrazilo defaultne nic
 *       - fixed bug s _cfg.activeNo
 * 1.2.2 - pridano rozliseni okna + centrovani objektu
 * 1.2.3 - pridana nova trida Overlayer
 *       - odstraneno to zbytecne testovani na typeof u funkci
 * 1.3.0 - pridan slider
 * 1.3.1 - fixed bug u ajaxoveho ukladani formu
 * 1.3.2 - fixed bug u multiimage 
 **/

function getException(error){
	output = '';
	for (i in error){
		output += error[i]+'\n';
	}
	return output;
}

function isIE(no){
	return ((navigator.appVersion).indexOf('MSIE '+(no ? no : '')) != -1);
}

try {
	if (typeof jQuery == 'undefined'){
		throw new Error('Missing jQuery!');
	}

	function element(pointer){
		return ($(pointer).attr('tagName') !== undefined);
	}

	function get(param){
		if (param){
			var hash = (param.replace(/^(.*)#/, '')).replace(/(&amp;)/, '&');
		} else {
			var hash = document.location.hash.replace(/^(.*)#/, '');
		}
		var get = {};
		if (hash){
			hash = hash.split('&');
			for (i = 0; i < hash.length; i++){
				hash[i] = (hash[i]).split('=');
				get[hash[i][0]] = (hash[i][1] ? hash[i][1] : null);
			}
		}
		return get;
	}

	function getCookie(name){
		replace = new RegExp(name+"=[^;]+", "i");
		if (document.cookie.match(replace)){
			return document.cookie.match(replace)[0].split("=")[1]
		}
		return null;
	}

	function setCookie(name, value){
		expires = new Date();
		expires_str = expires.setDate(expires.getDate()+parseInt(365));
		document.cookie = name+"="+value+"; expires="+expires.toGMTString()+"; path=/";
	}

	function in_array(needle, haystack){  
		for (i in haystack){
			if (needle == haystack[i]){
				return true;
			}
		}
		return false;  
	}

	function trim(arg){
		return (arg || '').replace(/^\s+|\s+$/g, '');
	}

	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;
	}

	/**
	 * get parametry pri volani skriptu
	 * main.js?arg=load
	 * getParams('main.js').arg		 		 
	 **/
	function getParams(a){
		var b = document.getElementsByTagName("script");
		for (var i = 0; i < b.length; i++){
			if (b[i].src.indexOf("/"+a) >-1 ){
				var c = b[i].src.split("?").pop().split("&"); 
				var p = {};
				for (var j = 0; j < c.length; j++){
					var d = c[j].split("=");
					p[d[0]] = d[1];
				}
				return p;
			}
		}
		return { };
	}

	function unselect(obj){
		$(obj).children('option').each(function(){
			$(this).attr('selected', false);
		});
	}

	/**
	 * rozliseni obrazovky
	 * resolution().h
	 * resolution().w	 	 
	 **/
	function resolution(){
		var h = null;
		var w = null;
	    if (window.parent.innerHeight){
	      	h = window.innerHeight;
	      	w = window.innerWidth;
		} else if (document.documentElement && document.documentElement.clientHeight){
	          h = document.documentElement.clientHeight;
	          w = document.documentElement.clientWidth;
		} else if (wdocument.body){
	          h = document.body.clientHeight;
	          w = document.body.clientWidth;
	    } else {
			h = 0;
			w = 0;
		}
		return { w : w, h : h};
	}
	
	/**
	 * vycentrovani prvku
	 * bud primo nastavi styly : alignMiddle('.element');
	 * nebo jen vrati hodnoty : alignMiddle('.element').top // alignMiddle('.element').left
	 **/
	function alignMiddle(_elem, _set){
		if (_set === undefined){
			_set = true;
		}
		var lenghts = { 
			top : (Math.round(resolution().h)/2) - (Math.round(parseInt($(_elem).attr('offsetHeight'))/2)) + $('html, body').scrollTop(),
			left : (Math.round(resolution().w)/2) - (Math.round(parseInt($(_elem).attr('offsetWidth')) /2))
		};
		if (_set){
			$(_elem).css(lenghts);
		} else {
			return lenghts;
		}
	}

	/**
	 * validace formulare
	 * @param array _cfg konfigurace	 
	 **/
	function Form(_cfg){
		var types = ['select', 'checkbox', 'password', 'text', 'hidden', 'textarea', 'file'];
		var borderSet = ['text', 'password', 'textarea'];
		var disabledTypes2 = ['related', 'multi_image'];
		var config = {
			borders : { 
				red : 'red',
				grey : '#aaa' 
			},
			regExp : {
				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,
				login : /^[.]{5,}$/i,
				passwd : /^[.]{6,}$/i,
				phoneStrict : /^\+([0-9]{12})$/i
			},
			msgs : {
				empty : ' • Následující povinná položka nebyla vyplněna: ',
				wrong : ' • Následující položka má špatný formát: '
			},
			images : {
				yes : 'images/true.gif',
				no : 'images/false.gif'
			},
			useImages : true,
			imageIdPrefix : 'form_image_',
			imageClassName : 'validation_img',
			formId : ''
		};
		var form = null;
		var fields = { };
		var errs = '';
		var that = this;

		this.__construct = function(_cfg){
			form = $(_cfg.formId);
			if (form.attr('tagName') != 'FORM'){
				throw new Error('Form of id <strong>'+_cfg.formId+'</strong> is null.');
			}
			for (i in _cfg){
				config[i] = _cfg[i];
			}
			form.submit(function(){
				that.checkForm();
			});
		};

		this.addRegExp = function(name, value){
			cfg.regExp[name] = value;
		};

		this.addAllFields = function(_fields){
			for (i in _fields){
				this.addField(_fields[i]);
			}
		};

		this.addField = function(_field){
			var elem, key, disabled;
			if (!in_array(_field.type, types)){
				type = 'text';
			}
			disabled = false;
			for (i in disabledTypes2){
				if (_field.type_2 && disabledTypes2[i] == _field.type_2){
					disabled = true; 
					break;
				}
			}
			_field.object = $('[name="'+_field.name+'"]');
			if (!disabled){
				if (typeof _field.object.attr('tagName') == 'undefined'){
					_field.object = $('[name="'+_field.name+'[]"]');
					if (typeof _field.object.attr('tagName') == 'undefined'){
						throw new Error('Field of name '+_field.name+' is null. Will not check this field.');
					}
				}
			}
			if (config.useImages && _field.required){
				elem = $(document.createElement('img'));
				elem.attr({
					alt : '#',
					className : config.imageClassName,
					id : config.imageIdPrefix+_field.name,
					src : this.check(_field, true) ? config.images.yes : config.images.no 
				});
				
				elem.insertAfter(_field.object);
			}
			if (_field.type == 'checkbox' || _field.type == 'select'){
				_field.object.click(function(){
					that.check(this); 
				});
				
				_field.object.change(function(){
					that.check(this); 
				});
			} else {
				_field.object.keyup(function(){
					that.check(this); 
				});
				
				_field.object.blur(function(){
					that.check(this); 
				});
			}
			key = _field.name.replace(/\[\]/, '');
			_field.key = key;
			fields[key] = _field;
		};

		/**
		 * kontrola pole
		 * muze byt volana 3 mi ruznymi zpusoby
		 * @param object self - z dokumentu, this
		 * @param bool inner - je volani ocad, uz je tam objekt
		 * @param bool type - chceme, aby funkce vracela 2 hodnoty - volano z kontroly na onsubmit	 	 	 	 
		 **/
		this.check = function(_self, _inner, _type){
			var fld, type;
			var ok = false;
			fld = _inner ? _self : fields[_self.name];
			if (typeof fld == 'undefined'){
				return true;
			}
			if (!fld.required){
				return true;
			}
			ok = false;
			if (fld.type == 'checkbox'){
				ok = fld.object.attr('checked');
				type = 1;
			} else {
				if (fld.regExp){
					ok = (config.regExp[fld.regExp]).test(fld.object.val());
					type = 2;
				} else {
					ok = trim(fld.object.val()) ? true : false;
					type = 1;
				}
			}
			if (config.useImages){
				$('#'+config.imageIdPrefix+_self.name).attr('src', (ok ? config.images.yes : config.images.no));
			}
			fld.object.css('borderColor', (ok ? config.borders.grey : config.borders.red));
			if (!_type){
				return ok;
			} else {
				return { ok : ok, type : type };
			}
		};

		this.checkForm = function(){
			var check;
			errs = '';
			for (i in fields){
				if (fields[i].required){
					check = this.check(fields[i], true, true);
					if (!check.ok){
						errs += (check.type == 1 ? config.msgs.empty : config.msgs.wrong)+' '+fields[i].label+'\n';
					}
				}
			}
			if (errs){
				alert(errs);
				return false;
			}
			return true;
		};

		this.getConfig = function(){
			return config;
		};

		this.getFields = function(){
			return fields;
		};

		this.__construct(_cfg);
	}

	/**
	 * ajaxove odeslani formulare
	 * @param object _form reference na objekt Form
	 * @param array _cfg nepovinna konfigurace	 	 
	 **/
	function AjaxForm(_form, _cfg){
		var Form = _form;
		var config = {
			msgDiv : '#ajaxUpdate',
			button : '[name="ajax_save"]',
			loaderId : 'ajax_form_loader',
			url : '',
			redirectUrl : '',
			requestNewUrl : '',
			successMsg : ''
		};
		var button = null;	
		var formId;
		var that = this;
		this.loader = null;

		this.__construct = function(){
			var elem;
			for (i in _cfg){
				config[i] = _cfg[i];
			}
			elem = $(document.createElement('div'));
			elem.attr({ id : config.loaderId });
			elem.css('display', 'none');
			formId = Form.getConfig().formId;
			$(formId).append(elem);
			$(formId).submit(function(){
				that.request();
				return false;
			});
			this.loader = elem;
			button = $(config.button);
			button.css('display', 'inline');
			button.click(function(){
				that.request();
				return false;
			});
		};

		this.redirectUrl = function(){
			return config.redirectUrl;
		};

		this.requestNewUrl = function(){
			return config.requestNewUrl ? config.requestNewUrl : window.location.href;
		};

		this.msgDiv = function(){
			return config.msgDiv;
		};

		this.request = function(){
			try {
				var data = Form.getFields();
				var sent = { };
				var it, url;
				this.loader.css('display', 'block');
				this.handleButtons(true);
				$.ajax({
					type: 'POST',
					url : config.url ? config.url : window.location.href,
					data : $(formId).serialize(),
					success : function(_response){
						if (that.redirectUrl()){
							if (!_response || Number(_response)){
								window.location.href = that.redirectUrl()
							} else {
								that.handleButtons(false);
								that.loader.css('display', 'none');
								that.drawMsgDiv(_response);
							}
						} else {
							if (_response != '' && Number(_response)){
								window.location.href = that.requestNewUrl()+_response+'/#success=1';
							} else {
								that.drawMsgDiv(_response);
							}
							that.handleButtons(false);
							that.loader.css('display', 'none');
							if (!_response){
								that.drawMsgDiv();
							}
						}
					},
					error : function(_response){
						that.drawMsgDiv(_response);
						that.handleButtons(false);
						that.loader.css('display', 'none');
					}
				});
			} catch (err){
				alert(getException(err));
			}
		};

		/**
		 * zobrazeni message divu
		 * hlaska o uspechu se taha z nastaveni, hlaska o neuspechu je odpoved skriptu volaneho ajaxem
		 * podle toho se delaji akce : napr. pri neuspechu se div po 4 vterinach neschova	 	 
		 **/
		this.drawMsgDiv = function(_msg){
			var div = $(config.msgDiv);
			var msg = _msg ? _msg : config.successMsg;
			div.css({
				display : 'block',
				height : 'auto'
			});
			div.attr('className', (_msg ? 'evil' : 'good'));
			div.children('div').html(msg);
			if (!_msg){ 
				setTimeout(function(){
					div.animate({ height : 0 }, null, null, function(){
						div.css('display', 'none');
					});
				}, 4000);
			}
		};

		this.handleButtons = function(_disabled){
			$(formId+' button[type="submit"], '+formId+' input[type="submit"]').each(function(){
				$(this).attr('disabled', _disabled);
				if (_disabled){
					$(this).addClass('disabled');
				} else {
					$(this).removeClass('disabled');
				}
			});
		}

		this.__construct(_cfg);
	}

	/**
	 * InputHandler
	 * @param object _cfg konfigurace - kopiruje se do promenne konfig
	 * @param object _params - co se naklikava (klic je jmeno html tagy, polozky jsou do attr() pro jQuery)
	 * @param string _adder - jakakoli reference na naklikavaci tlacitko, pujde to do $(_adder)
	 * @param string _remover - reference na odstranovaci tlacitko
	 * @param array _values - pokud jsou uz nejake hodnoty, netiskne se to v sablone ale tuta funkce si to sama prida  
	 **/
	function InputHandler(_cfg, _params, _adder, _remover, _values){
		var config = {
			count : 0,
			buttonValue : 'Smazat',
			buttonClassName : 'submit button'
		};
		var btn = {
			prev : 0,
			next : 0
		};
		var inserted = { };
		var adder = null;
		var remover = null;
		var params = null;
		var defaultWasAdded = false;
		var that = this;

		this.__construct = function(_cfg, _params, _adder, _remover, _values){
			var delAdded = false;
			for (i in _cfg){
				config[i] = _cfg[i];
			}
			for (j in _params){
				if (j == 'DEL'){
					delAdded = true;
				} else {
					delAdded ? btn.next++ : btn.prev++;
				}
			}
			window.counter = 0;
			params = _params;
			adder = $(_adder);
			adder.click(that.add);
			remover = $(_remover);
			remover.click(function(){
				that.unset(this);
			});
			if (_values && _values.length){
				for (k in _values){
					this.add(_values[k]);
				}
			}
		};

		this.add = function(_vals){
			var elem, tagName, valName;
			var time = (new Date()).getTime();
			var idCreated = false;
			try {
				for (key in params){
					tagName = key.replace(/([0-9]+)/, '');
					if (tagName != 'DEL'){
						elem = $(document.createElement(tagName));				
						if (params[key]){
							if (params[key].name){
								valName = params[key].name
								if (_vals && _vals[valName]){
									params[key].value = _vals[valName]
								}
							}
							if (!params[key].id && params[key].name){
								params[key].id = (params[key].name).replace(/\[\]/, '')+'_'+''+time;
								idCreated = true;
							}
			 				elem.attr(params[key]);
			 				if (idCreated && params[key].id){
			 					delete(params[key].id);
			 					idCreated = false;
			 				}
			 				if (params[key].value){
								params[key].value = '';
							}
						}
		 			} else {
					 	elem = $(document.createElement('input'));
					 	elem.attr({
							className : config.buttonClassName,
							value : config.buttonValue,
							type : 'button',
							name : null
						});
						elem.click(function(){
							that.unset(this);
						});
					}
					elem.insertBefore(adder);
				}
			} catch (err){
				throw new Error(getException(err));
			}
		};

		/**
		 * odmaze jednu davku vlozenych elementu
		 * neni to pres jQuery ale normalne, pac uz jsem to mel hotove a nechtelo se mi to hledat
		 * @param object _self normalne this z inputu	 	 
		 **/
		this.unset = function(_self){
			try {
				for (i = 0; i < btn.prev; i++){
					_self.parentNode.removeChild(_self.previousSibling);
				}
				for (i = 0; i < btn.next; i++){
					_self.parentNode.removeChild(_self.nextSibling);
				}
				_self.parentNode.removeChild(_self);
			} catch (err){
				throw new Error(getException(err));
			}
		};
	
		this.__construct(_cfg, _params, _adder, _remover, _values);
	}

	var Tabs = function(_cfg){
		var config = {
			url : true,
			activeNo : 0,
			activeClass : 'active',
			menu : '#tabs a',
			tabs : '.domtab',
			getVar : 'tabs',
			opacity : true,
			opacityTimeout : 250
		};
		var that = this;

		this.__construct = function(_cfg){
			var wasDisplayed = false;
			var toDisplay = null;
			var tab, anc;
			for (i in _cfg){
				config[i] = _cfg[i];
			}
			if (config.url && (toDisplay = get()[config.getVar])){
				tab = $('#'+toDisplay);
				anc = $('a[href="'+toDisplay+'"]');
				if (typeof anc.attr('tagName') != 'undefined'){
					anc.addClass(config.activeClass);
				}
				if (typeof tab.attr('tagName') != 'undefined'){
					tab.css('display', 'block');
					wasDisplayed = true;
				}
			}
			$(config.menu).each(function(_i){
				if (_i == config.activeNo && !wasDisplayed || $(this).attr('href') == '#'+toDisplay){
					$(this).addClass(config.activeClass);
				}
				$(this).click(function(){
					return that.showTab(this);
				});
			});
			$(config.tabs).each(function(_j){
				if ((config.activeNo !== null) && (_j == config.activeNo && !wasDisplayed || $(this).attr('id') == toDisplay)){
					$(this).css('display', 'block');
				} else {
					$(this).css('display', 'none');
				}
			});
		};

		this.showTab = function(_self){
			var href = $(_self).attr('href');
			var loc;
			$(config.tabs).each(function(_j){
				$(this).css('display', 'none');
			});
			$(config.menu).each(function(_i){
				$(this).removeClass('active');
			});
			$(_self).addClass('active');
			if (config.opacity){
				$(href).css('opacity', 0);
				$(href).css('display', 'block');
				$(href).animate({
					opacity : 1
				}, config.opacityTimeout);
			} else {
				$(href).css('display', 'block');
			}
			if (config.url){
				loc = (window.location.href).replace(/#(.*)$/, '');
				window.location.href = loc+'#'+config.getVar+'='+$(href).attr('id');
			}
			return false;
		};

		this.__construct(_cfg);
	}

	function Overlayer(){
		this.id = 'overlayer';
		this.layer = null;
		this.effect = null;
		this.offset = 1000;

		this.show = function(){
			this.layer.css('display', 'block');
			if (this.effect == 'fade'){
				this.layer.css('opacity', 0);
				this.layer.animate({
					opacity : 0.5
				}, this.offset);
			}
		};

		this.hide = function(){
			var layer = this.layer;
			if (this.effect == 'fade'){
				layer.animate({
					opacity : 0
				}, this.offset, null, function(){
					layer.css('display', 'none');
				});
			} else {
				layer.css('display', 'none');
			}
		};

		this.__construct = function(){
			if (element('#'+this.id)){
				this.layer = $('#'+this.id);
				return true;
			}
			_w = $('body').width();
			_h = $(document).height();
			elem = $(document.createElement('div'));
			elem.attr('id', this.id);
			elem.css({
				position : 'absolute',
				background : 'black',
				display : 'none',
				opacity : 0.5,
				width : _w,
				height : _h,
				top : 0,
				left : 0,
				zIndex : 1000
			});
			if (isIE()){
				elem.css('background-color', null);
			}
			$('body', document).append(elem);
			this.layer = elem;
		}; 

		this.__construct();
	}

	function ProcessHyperSlider(_all, _cfg){
		this.config = {
			animTime : null,
			waitTime : null,
			start : true,
			end : null
		};
		var loop = 1;
		var all;
		var first;
		var actual;
		var next;
		var that = this;
		var timeouts = [];

		this.setStyles = function(){
			all.css({
				position : 'absolute',
				opacity : 0
			});
			actual.css({
				opacity : 1
			});
			all.parent().css({
				position : 'relative'
			});
		};

		this.getNext = function(returnIt){
			var stop = false;
			var nextItem = null;
			all.each(function(){
				if (stop && !nextItem){
					nextItem = $(this);
				}
				if ($(this)[0] == actual[0]){
					stop = true;
				}
			});
			if (nextItem === null){
				loop = loop+1;
				nextItem = first;
			}
			if (returnIt){
				return nextItem;
			} else {
				next = nextItem;
			}
		};

		this.switchIt = function(){
			this.getNext();
			all.css('opacity', 0);
			actual.css('opacity', 1);
			actual.animate({
				opacity : 0
			}, this.config.animTime);
			next.animate({
				opacity : 1
			}, this.config.animTime);
			actual = next;
			if (typeof this.config.end == 'number'){
				if (loop > this.config.end){
					loop = 1;
					return that.endIt();
				}
			}
			timeouts.push(setTimeout(function(){
				that.switchIt();
			}, this.config.waitTime));
		};

		this.endIt = function(){
			for (i in timeouts){
				clearTimeout(timeouts[i]);
			}
		};

		this.__construct = function(_all, _cfg){
			if (typeof _cfg == 'object'){
				for (i in _cfg){
					if (typeof this.config[i] != 'undefined'){
						this.config[i] = _cfg[i];
					}
				}
			}
			first = _all.first();
			actual = first;
			all = _all;
			this.setStyles();
			if (all.size() > 1){
				if (this.config.start === true){
					this.switchIt();
				} else if (this.config.start == 'hover'){
					all.parent().hover(function(){
						that.switchIt();
					}, function(){
						if (this.config.end === true){
							that.endIt();
						}
					});
				}
			}
		};

		this.__construct(_all, _cfg);
	}

	/**
	 * HyperSlider
	 * Nasazeni :
     * new HyperSlider({
     *    animTime : 1000,     // cas pro animate()
     *    waitTime : 1000,     // cas pro setTimeout
     *    parent   : '.image', // rodic
     *    elem     : 'img',    // jednotlive prvky
     *    start    : 'hover',  // 'hover' nebo true nebo nic
     *    end      : 2         // cislo nebo true (if true && [start] == hover { end na mouseout } if number, cely slide probehne n krat a vrati se na zacatek
     * });
	 **/
	function HyperSlider(_cfg){
		var config = {
			parent : '.image',
			elem : 'img',
			animTime : 1500,
			waitTime : 3000,
			start : true,
			end : null
		};
		
		this.__construct = function(_cfg){
			if (typeof _cfg == 'object'){
				for (i in _cfg){
					if (typeof config[i] != 'undefined'){
						config[i] = _cfg[i];
					}
				}
			}
			$(_cfg.parent).each(function(){
				var children = $(this).children(_cfg.elem);
				new ProcessHyperSlider(children, config);
			});
		};

		this.__construct(_cfg);
	}
} catch (err){
	if (typeof window.console != 'undefined' && !isIE()){
		window.console.log(getException(err));
	} else {
		throw new Error(getException(err));
	}
}
