

/* hned vytvarime pole pro seznam funkci, ktere se maji skustit pri zmene stavu dokumentu. Nemuzeme je vytvaret az v knihovne binargon, protoze v IE7 a IE8 to nejde */
var binargon_onCommplete = binargon_onCommplete || [],
		binargon_onInteractive = binargon_onInteractive  || [],
		binargon_onLoaded = binargon_onLoaded || [],
		binargon_onLoading = binargon_onLoading  || [],
		binargon_onUninitialized = binargon_onUninitialized  || [];

(function(){

	var binargon = window.binargon = new function(){

		/* REGULARNI VYRAZY */
		var regFloat = 	new RegExp('(?:[-]{0,1}[1-9]+[0-9]*[,.]{0,1}[0-9]*)|(?:[-]{0,1}[0]*[,.]{1}[0-9]*)', '');
	  var regMezera = new RegExp(' ', '');
		var regMezeraGlobal = new RegExp(' ', 'g');

		// ORIZNE HODNUT dle MIN a MAX
		function clamp(min, val, max){
      return Math.min(Math.max(val, min), max)
		}

		this.clamp = clamp;


		// VRATI JSON s udaji z DATA-BINARGON
		function getMetaBinargonJSON(){
			var vysl = {
				"fce":"1",
				"id":"0",
				"menaId":"1",
				"menaName":"Kč",
				"languageCode":"cs-CZ",
				"skindir":"",
				"cmslang":"1"
			};

      var source = document.querySelector('meta[data-binargon]');
      if(source != null){
				source = source.getAttribute('data-binargon');
				if(source != null){
					try{
						source = JSON.parse(source);
						Object.keys(source).forEach(key=>{
							vysl[key] = source[key].toString(); // zaznam bude vzdy string
						})
					}catch(err){}
				}
			};
			return vysl;
		}

		this.getMetaBinargonJSON = getMetaBinargonJSON;



		// vrati aktualni menu
    this.getCurrency = function(){
			var json = getMetaBinargonJSON();
			return {
				"id": parseFloat(json.menaId),
				"name": json.menaName
			};
		}

		/* vraci jazyk, v jakem bezi aktualni stranka */
		this.getLanguage = function(){
      
			var metaData = getMetaBinargonJSON();
			var languageCode = metaData.languageCode.split('-');
			var zkratka = (languageCode.length == 2) ? languageCode[0] : 'cz';

			if(zkratka == 'cs'){
				zkratka = 'cz';
			}

			return {
				"id": metaData.cmslang,
				"zkratka": zkratka,
				"languageCode": metaData.languageCode
			};

		}

		this.getSkin = function(){
			return {
				"name": getMetaBinargonJSON().skindir
			};
		}
		
		function getCookie(key){
			var c = document.cookie.split(/\s*;\s*/);
			for(var i=0; i<c.length; i++){
				c[i]=c[i].split('=');
				if(c[i].length==2 && c[i][0]==key){
					return c[i][1];
				}
			}
			return null;
		}
		
		this.getCookie=getCookie;
		
		
		// ttl se zadava v milisekundach
		function setCookie(key, value, ttl, path){
			
			switch(myTypeOf(key)){
				case 'string': break;
				case 'number': key = key.toString();
				default: return; break; /* klic je povinny udaj */
			}
			
			switch(myTypeOf(value)){
				case 'string': break;
				case 'number': value=value.toString(); break;
				default: value = ''; break;
			}
			
			switch(myTypeOf(ttl)){
				case 'number': 	ttl = Math.max(0, Math.round(ttl)); break;
				case 'string': 	ttl = Math.max(0, Math.round(parseFloat(ttl))); break;
				default: 				ttl = ''; break;
			}
			
			if(ttl != ''){
				var date = new Date(); 
				ttl = date.setTime(date.getTime() + ttl); 
				ttl = ';expires=' + date.toGMTString();
			}
			
			switch(myTypeOf(path)){
				case 'string': 	path = ';path='+path.split(';').join(''); break;
				default: 				path = ';path=/'; break;
			}
			
			document.cookie = key + '=' + value + ttl + path;
		}
		
		this.setCookie = setCookie;

		
		function deleteCookie(key){
			document.cookie = (key.toString())+'=; expires=Thu, 01 Jan 1970 00:00:00 UTC;';
		}
		
		this.deleteCookie = deleteCookie;
		
		
		function addClass(obj, className){
			if(myTypeOf(obj)=='domNode' && myTypeOf(className)=='string' && className.length>0){
				obj.classList.add(className);
				/*
				var p = obj.className.split(/\s+/);
				if(p.indexOf(className)==-1){
					p.push(className);
					obj.className = p.join(' ');
				} */
			}
		}
		
		this.addClass = addClass;
		
		/* odstrani CSS tridu z objektu*/
		function removeClass(obj, className){
			if(myTypeOf(obj)=='domNode' && myTypeOf(className)=='string' && className.length>0){
				obj.classList.remove(className);
				/*
				var p = obj.className.split(/\s+/);
				while(p.indexOf(className) != -1){
					var x = p.splice(p.indexOf(className),1);
				}
				obj.className = p.join(' ');
				*/
			} 
		}
		
		this.removeClass = removeClass;
		

		// TYPE OF
		// vrati typ elementu zadaneho do prvniho parmetru
		// do druheho parametru jde zadat string, nebo funkci vracejici string. Tento string je cesta danym objektem. Muzu tak zkontrolovat, jaky tym ma cesta objekt.property.dalsi.neco.vnoreneho je number. Pokud je zadana nevalidni cesta, vraci se undefined (protoze proste takova hodnota neni nadefinovana)
		function myTypeOf(attr, path){

			function checkIfIsArray(attr){
				// normalni pole
				if(attr instanceof Array){return true;}
				if('isArray' in Array && Array.isArray(attr)==true){return true;}
		    if(Object.prototype.toString.call(attr) == '[object Array]'){return true;}
				return false;
			};

			// specialni typy
			function checkSpecialObjectTypes(attr){
				if(attr instanceof RegExp){return 'RegExp'}
				if(window!=undefined && window!=null && ('constructor' in window) && (attr instanceof window.constructor)){return 'window';}
				return 'object';
			}

			// typovana pole jsou ve skutecnosti OBJEKTY, ktere maji PODOBNE metody jako Array. V jejich případě tedy nesím vrátit, že se jedná o Array, protože mají jiné metody!
			function checkIfISTypedArray(attr){
				var typedArrayClases = ['Int8Array', 'Uint8Array', 'Uint8ClampedArray', 'Int16Array', 'Uint16Array', 'Int32Array', 'Uint32Array', 'Float32Array', 'Float64Array'];
				for(var i=0; i<typedArrayClases.length; i++){
					if(typedArrayClases[i] in window && attr instanceof window[typedArrayClases[i]]){
						return typedArrayClases[i];
					}
				}
				return false;
			}

			// pokud je attribut null, rovnou vratim 'null', protoze null nejde nijak prochazet, ani se ptat na jeho hodnoty
			if(attr === null){return 'null';}

			if(path != null){
				// vytvorim cestu, ktera se ma kontrolovat (defaultne null)
				switch((typeof path).toLowerCase()){
					case 'string':		path = path.split('.');	break;
					case 'function': 	path = (path()).toString().split('.'); break;
					default:					path = null; 	break;		// jestli neni zadana cesta, nastavim ji na null.
				}

				// TODO pridat podporu pro jine nez teckove zapisy? tedy neco['prvy']['druhy']
				if(path != null){
					for(var i=path.length-1; i>=0; i--){
						if(path[i].length==0){ // TODO: nemela by se kontrolovat delka, ale regularni vyraz? Otazka je, zda muzou byt v nazvu property treba procenta
							path.splice(i,1); // vyhodim prazdne zaznamy
						}
					}

					for(var i=0; i<path.length; i++){
						//if(attr.hasOwnProperty(path[i])){ // hasOwnProperty nekontroluje v prototypu. Melo by byt pouzito IN
						if((typeof attr).toLowerCase() == 'object' && path[i] in attr){ //používá se IN místo hasOwnProperty, protoze hasOwnProperty nehledá v prototypu.
							attr = attr[path[i]];
						}else{
							return 'undefined'; // pokud objekt nema danou vlastnos, vracim typ undefined, protoze cesta vede k nedefinovane property daného objektu.
						}
					}
				}

				// po tom, co jsem prosel celou path musim znova zkontrolovat, zda neny attr typu null
		    if(attr === null){return 'null';}

			}

			switch((typeof attr).toLowerCase()){
				case 'undefined':
		      return 'undefined';
				break;
				case 'object':
					// pole
	        //console.log('JE TO', typeof attr, attr);
					if(checkIfIsArray(attr)==true) return 'array';
	        //console.log('JE TO', typeof attr, attr);
					//console.log('TED2',attr, typeof attr);
					if(attr instanceof Event || ('hasOwnProperty' in attr && attr.hasOwnProperty('originalEvent'))){
						return 'event';
					}
	        // typovana pole
					var typedArray = checkIfISTypedArray(attr);
					if(typedArray != false){return typedArray};
					// domNode
					if('nodeType' in attr && attr.nodeType == 1) return 'domNode';
          if('nodeType' in attr && attr.nodeType == 11) return 'documentFragment';
					// node list
					if(attr instanceof NodeList){ return 'nodeList'; }
          // zbyle mozne typy
					return checkSpecialObjectTypes(attr);
				break;
		    case 'function':
		      return 'function';
				break;
				case 'boolean':
		      return 'boolean';
				break;
				case 'number':
					if(isNaN(attr)){return 'NaN';}
					// if(!isFinite(attr)){return 'infinity'} NEKONECNO NERESIME, protoze s nim jde pocitat jako s normalnim cislem?
		      return 'number';
				break;
				case 'symbol':
		      return 'symbol';  /* new in ECMAScript 2015 */
				break;
				case 'string':
					return 'string';
				break;
				default:
		      if(checkIfIsArray(attr)==true) return 'array';
				break;
			}

			return '';

		}
		
		this.typeOf = myTypeOf;
		

		/* kontrola, zda je zadany argument pole */
		this.isArray = function(arg){
			if(arg instanceof Array){return true;}
			if('isArray' in Array && Array.isArray(arg)==true){return true;}
      if(Object.prototype.toString.call(data) == '[object Array]'){return true;}
			return false;
		}

		/* vyparsuje float.. pokud to nedokaze(neni to cislo) tak vrati nulu */
		this.parseFloat = function(str, ignorovatMezery){
			
			/* kontrola typu */
			switch(myTypeOf(str)){
				case 'string':
          /* string se bude dale zpracovavat */
				break; 
				case 'number':
					//if(isNaN(str)){return 0;} return str;
					if(isNaN(str)){return 0;} 						/* pokud je NaN tak vracim nulu */
					if(str == -0){return 0;}    					/* neni to nutne matematicky, ale protoze se muze cislo nekde dale prevadet na string, kontroluji i zapornou nebo kladnou nulu */
					return str;														/* jinak se jedna skutecne o cislo a vracim str, protoze je to proste cislo */
				break; 
				default:
					return 0;
				break; /* ve vsech ostatnich pripadech vrati nulu */
			}

			/* pokud mam ignorovat mezery, tak je ze stringu odstranim... kdyz prijde '1 0.5', tak to beru jako '10.5' */
			if(ignorovatMezery==true) str = str.replace(regMezeraGlobal,'');

	    var value = regFloat.exec(str);

			if(value!=null && value.length>0){
				var value1=value[0].replace(',','.');
				if(value1.indexOf('.')==0){value1 = '0'+value1;} 				/* kdyz string zacina na desetinou tecku, tak PRED neho pridam nulu */
				if(value1.indexOf('.')==value1.length-1){value1+='0';} 	/* kdyz string konci na desetinou tecku, tak ZA neho pridam nulu */
				var value2 = parseFloat(value1)*1;
				return value2;
			}

			return 0;
		}
		
		//this.parseFloat = parseFloat; NE NE NE, musi to byt prez this, protoze jinak prepisu standardni funkci parseFloat!

		// NAFORMÁTUJE VSTUP JAKO CENU (1 234.50)
		function formatPrice(value, pocetDesetinnychMist, oddelovacTisicu, zaokrouhlit, odstranitNuly, oddelovacDesetin){

			// cislo, ktere chci naformatovat
			var value = myParseFloat(value, false);

			// pocet desetinnych mist, ktere ma mit vysledek (defaultně 2)
      var pocetDesetinnychMist = (pocetDesetinnychMist!=undefined && pocetDesetinnychMist==parseInt(pocetDesetinnychMist,10)) ? parseInt(pocetDesetinnychMist,10) : 2;

			// oddělovač tisíců (defaultně mezera)
	    var oddelovacTisicu = (oddelovacTisicu!=undefined && oddelovacTisicu.toString()==oddelovacTisicu)? oddelovacTisicu.toString() : ' ';

			// ma se vysledek zaokrouhlit?
	    var zaokrouhlit = (zaokrouhlit===false) ? false : true;

			// oddělovač desetin desetiny jsou defaultně odděleny tečkou
      var oddelovacDesetin = (oddelovacDesetin!=undefined && oddelovacDesetin.toString()==oddelovacDesetin) ? oddelovacDesetin.toString() : '.';

			// maji se odstranit nuly? (defaultne se odstranuje 00)
			var odstranitNuly = odstranitNuly;

      //odstranitNuly = (odstranitNuly===false)? false: true;
			switch(odstranitNuly){
				case true: 	break;                      // nuly se budou odstranovat
				case false: break;  										// nuly se nebudou odstranovat
				default: odstranitNuly = '00'; break; 		// nuly odstrani jen pokud jsou by cislo koncilo na '.00'
			}
			/*
			switch(odstranitNuly){
				case '00': 	break;                      // nuly odstrani jen pokud jsou by cislo koncilo na '.00'
				case false: break;  										// nuly se nebudou odstranovat
				default: odstranitNuly = true; break; 	// nuly se budou odstranovat
			}*/

			// zkontroluji, ze pocet desetinnych mist je v rozmezi 0 az 14
	    pocetDesetinnychMist = Math.min(Math.max(pocetDesetinnychMist, 0), 14);

			// zazalohuju si pocet desetinnychmist
			var zalohaPoctuDesetinnychMist = pocetDesetinnychMist;

			// vprevedu na nasobic ... kdyz mi prijdou 2, tak je vysledek 100 ... protoze potrebuju pridat 2 mista, nasobim stovkou
	    pocetDesetinnychMist = Math.pow(10, pocetDesetinnychMist);

			// cislo zaokrouhlim na zadany pocet desetinnych mist
			if(zaokrouhlit){value = Math.round(value * pocetDesetinnychMist) / pocetDesetinnychMist ;}

			// naformatovani poctu desetinnych mist + rozdeleni podle desetinne tecky
			value = value.toFixed(zalohaPoctuDesetinnychMist).split('.');

			// dale se s value pracuje jako s polem dvou stringu. V jedne casti je cela cast a v druhe desetinna cast
			//value = value.toString().split('.');


      // jesli ma cislo i desetinnou cast, zkontroluji, zda se nema osetrit
			if(value.length > 1){
				switch(odstranitNuly){
          // pokud se ma na konci odstranit dvojit nula '.00' tak ji odstranim.
					case '00':
            if(value[1]=='00'){value.splice(1);}
					break;
          // pokud ma cislo desetiny a mam zapnuto odstranovani nul z desetinne casti (napr. aby cislo nekoncilo .00) tak nuly odstranim
					case true:
						// od konce najdu pozici, na ktere se vyskytuje nula
						var pozicePosledniNuly = null;
						for(var i = value[1].length-1; i>=0; i--){
							if(value[1].substr(i,1) == '0'){
		            pozicePosledniNuly = i;
							}else{
								break;
							}
						}

						// nuly na konci desetinne casti ze stringu odriznu
						if(pozicePosledniNuly != null){value[1] = value[1].substr(0,pozicePosledniNuly);}

						// z pole odstrain desetinnou cast, pokud je prazdna, (jinak by se za cislem vypsala desetinna tecka)
						if(value[1].length==0){value.splice(1);}

					break;
				}
			}

			// kolik znaku se musi odriznout od zacatku? 50 000 = 2 znaky, 500 00 = 3 znaky
			var nadbytek = (value[0].length>3) ? value[0].length % 3 : 0;

			return	((nadbytek>0) ? value[0].substr(0,nadbytek)+oddelovacTisicu : '') + // prvni cast retezce, ktery ma mene znaku nez 3
							value[0].substr(nadbytek).replace(/(\d{3})(?=\d)/g, '$1' + oddelovacTisicu) + // zbytek cele casti s oddelenyma tisicema
							((value.length >= 2)? (oddelovacDesetin + value[1]) : ''); // desetinna cast
		}

		this.formatPrice = formatPrice;


		/* prirazeni posluchace udalsoti */
		// 0 skinu, ktere by to pouzivalo, 0 knihoven, ktere by to pouzivalo
		this.addEvent = function(elm, evType, fn, useCapture) {
			if(elm.addEventListener){
				elm.addEventListener(evType, fn, useCapture); return true;
			}else if(elm.attachEvent){
				var r = elm.attachEvent('on'+evType, fn); return r;
			}
		}

		/* vrati status dokumentu, prelozi nazev na poradove cislo (nekdy potrebuju porovnavat, ze stav je vetsi nez X, nebo je v rozsahu X-Y) */
		function getReadyState(){
      switch((document.readyState).toString().toLowerCase()){
				case 'uninitialized': 	return 1; break;
				case 'loading': 				return 2; break;
				case 'loaded': 					return 3; break;
				case 'interactive': 		return 4; break;
				case 'complete': 				return 5; break;
			};
		}

		function zpracujAktualniStavDokumentu(){

			var state = getReadyState();
			var seznamUkolu = [];
			/* bez BREAKu! pokud nastal stav 5, je treba aby se zpracovaly i pozadavky z udalosti 4 atd... */
			switch(state){
        case 5: seznamUkolu.push(zpracuj_binargon_onCommplete);
        case 4: seznamUkolu.push(zpracuj_binargon_onInteractive);
        case 3:	seznamUkolu.push(zpracuj_binargon_onLoaded);
        case 2: seznamUkolu.push(zpracuj_binargon_onLoading);
				case 1:	seznamUkolu.push(zpracuj_binargon_onUninitialized);
				break;
			}
			/* ukoly se musi provest v opacnem poradi, nez v jakem byly do pole pridany, takze pole otocim */
			seznamUkolu.reverse();
			/* jednotlive ukoly provedu */
			for(var i=0; i<seznamUkolu.length; i++){
				seznamUkolu[i]();
			}
		}

		/* vyvori seznam, do ktereho jdou pridavat funkce, ktere se maji zavolat ihned, kdyz se dokument preklopi do urciteho stavu (napr. vsechny funkce, ktere se maji zavolat kdyz se dokument dostane do stavu 'loaded' nebo 'complete') */
		function vytvorObjektProFrontuPosluchacuStavuDoukmentu(nazevObjektu, cisloStavu){
			/* programator muze ve skinu jiz seznam zalozit a plnit, i kdyz se tato knihovna jeste nenacetla. Plni jej do obycejneho pole. Ja pak toto pole vezmu a predelam ho na objekt. */
			var seznam = (nazevObjektu in window)? window[nazevObjektu]:[];
			/* vrati delku seznamu */
			this.length = function(){
				return seznam.length;
			}
			/* prida do seznamu novy kod, ktery se ma zavolat */
			this.push=function(zaznam){
				var state = getReadyState();
				if(zaznam!=undefined && zaznam!=null){
					seznam.push(zaznam);
					/* pokud je stav dokumentu vetsi nez X, tak rovnou pozadam o zpracovani celeho seznamu (napr. pridam kod, ktery se ma spustit po nacteni dokumentu, ale dokument uz je nacteny vice jak 5 minut... provede se tedy hedn po pridani) */
					if(state>=cisloStavu){
						
						//this['zpracuj_'+nazevObjektu]();
						switch(nazevObjektu){
							case 'binargon_onCommplete':			zpracuj_binargon_onCommplete(); break;
							case 'binargon_onInteractive':    zpracuj_binargon_onInteractive(); break;
							case 'binargon_onLoaded':         zpracuj_binargon_onLoaded(); break;
							case 'binargon_onLoading':        zpracuj_binargon_onLoading(); break;
							case 'binargon_onUninitialized':  zpracuj_binargon_onUninitialized(); break;
						}
					}
				}
			}
			/* smaze seznam, ale vrati pole se seznamem prvku, ktere smazal */
			this.spliceAll=function(){
				return seznam.splice(0, seznam.length);
			}
		}

		/* funkce, ktere se maji zpracovat, pokud se dokument dostane do urciteho stavu. Napr. zpracuj_binargon_onCommplete se zavola, kdyz s doklument dostane do stavu 'commplete' */
		function zpracuj_binargon_onCommplete()			{var seznam = binargon_onCommplete.spliceAll(); 			for(var i=0; i<seznam.length; i++){(seznam[i])();}}
		function zpracuj_binargon_onInteractive()		{var seznam = binargon_onInteractive.spliceAll(); 		for(var i=0; i<seznam.length; i++){(seznam[i])();}}
		function zpracuj_binargon_onLoaded()				{var seznam = binargon_onLoaded.spliceAll(); 					for(var i=0; i<seznam.length; i++){(seznam[i])();}}
		function zpracuj_binargon_onLoading()				{var seznam = binargon_onLoading.spliceAll(); 				for(var i=0; i<seznam.length; i++){(seznam[i])();}}
		function zpracuj_binargon_onUninitialized()	{var seznam = binargon_onUninitialized.spliceAll(); 	for(var i=0; i<seznam.length; i++){(seznam[i])();}}

		/* prepise pole binargon_onCommplete na objekt */
    var binargon_onCommplete = 					window.binargon_onCommplete = 			new vytvorObjektProFrontuPosluchacuStavuDoukmentu('binargon_onCommplete', 5);
    var binargon_onInteractive = 				window.binargon_onInteractive = 		new vytvorObjektProFrontuPosluchacuStavuDoukmentu('binargon_onInteractive', 4);
    var binargon_onLoaded = 						window.binargon_onLoaded = 					new vytvorObjektProFrontuPosluchacuStavuDoukmentu('binargon_onLoaded', 3);
    var binargon_onLoading = 						window.binargon_onLoading = 				new vytvorObjektProFrontuPosluchacuStavuDoukmentu('binargon_onLoading', 2);
    var binargon_onUninitialized = 			window.binargon_onUninitialized = 	new vytvorObjektProFrontuPosluchacuStavuDoukmentu('binargon_onUninitialized', 1);

		/* spusti posluchac udalosti pro readystatechange */
		this.addEvent(document, 'readystatechange', zpracujAktualniStavDokumentu, false);





		// pouziva se v productDetail class

    /* DOBRE: http://www.xmlshop.cz/imagegen.php?name=p18-6-2-7-1/2.png&sizex=-1&sizey=-1 */
		/* MOJE:	http://www.xmlshop.cz/imgcache/3/3/pnone_-1_-1_4187.jpg */
		/* prida do URL zadane parametry a vrati je. URL muze byt string nebo pole, params musi byt json */
		function createURL(url, params){

			function addParamsToURLString(originalUrl, paramsString, char_andType){
				var url = originalUrl.toString().toLowerCase();

				// prazdne url, vratim jen parametry
				if(url.length == 0){
					return '?' + paramsString;
				}

				// kdyz konci na &amp;
				if(url.length>=5 && url.substr(url.length-5,5)=='&amp;'){
					return originalUrl + paramsString;
				}

				// kdyz konci na jeden z vyjmenovanych znaku
				switch(url.substr(url.length-1,1)){
					case '/': return originalUrl + '?' + paramsString; break;
          case '?':
          case '&': return originalUrl + paramsString;  break;
				}

				// pokud ma otaznik nebo and a pritom to neni posledni znak url (to by spadlo do predchozich podminek)
				if(url.indexOf('?') != -1 || url.indexOf('&') != -1){
          return originalUrl + char_andType +paramsString;
				}

				// v ostatnich pripadech stringy proste spojim
				return originalUrl + '?' + paramsString;

			}

			function paramsToArray(params){
				var vysl = [];
				for(var i in params){
					var key = encodeURIComponent(i);
					var value = (params[i]!=undefined && params[i]!=null) ? encodeURIComponent(params[i].toString()) : '';
					vysl.push(key + '=' + value);
				}
				return vysl;
			}

      var char_andType = '&';
			var paramsArray = (myTypeOf(params)=='object') ? paramsToArray(params) : [];

			switch(myTypeOf(url)){

				case 'array':
					for(var i=0; i<url.length; i++){
						if(myTypeOf(url[i])==string){
              char_andType = (url[i].indexOf('&amp;')!=-1) ? '&amp;' : '&';
							url[i] = addParamsToURLString(url[i], paramsArray.join(char_andType), char_andType);
						}
					}
					return url;
				break;

				case 'string':
          char_andType = (url.indexOf('&amp;')!=-1) ? '&amp;' : '&';
					return addParamsToURLString(url, paramsArray.join(char_andType), char_andType);
				break;

			}

			return url;


		}

		this.createURL = createURL;

		// TODO: safari uz zrejme umoznuje ulozit az 5MB v local storage, tento test zrejme jiz nebude nutny. NEVIM ale, zda se to tyka i iOS (https://support.apple.com/guide/safari/give-more-space-to-website-databases-sfri20879/mac)
		/* TEST LOCAL STORAGE, kvuli anonymnimu modu na iOS je potřeba otestovat i to, zda do nej jde zapsat, ne jen zda je k dispozici */
		function isLocalStorageAvailable(){
			if('localStorage' in window && localStorage != undefined && localStorage != null){
        //var testString = 'binargon test 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789';
        var testString = 'binargon test ';
				// vyplnime 300 znaku, aby byl testovaci string dlouhy;
				for(var i=0; i<300; i++){
          testString += 'X';
				}
				var testKey = '_binargon_testLocalStorage';
				try{
          localStorage[testKey] = testString;
          if(localStorage[testKey] == testString){
						localStorage[testKey] = 'test probehl uspesne';
						return true; /* pokud slo do localStorage zapsat, vratim true */
					}
				}catch(err){}
			}
			return false;
		}

		this.isLocalStorageAvailable = isLocalStorageAvailable;
		
		
		
		/* escapuje string pro vlozeni do XML (ci XHML) (v adminu je tato funkce pod jmenem escapeXML();) */
		function stringifyForXML(t){
			switch(myTypeOf(t)){
				case 'object':
					t = JSON.stringify(t);
				break;
				case 'string':
				case 'number':
				case 'boolean': 
				case 'array':
					t=t.toString();
				break;
				default:
					return '';
				break;
			}

		  t=t.replace(/&/g,'&amp;');
			t=t.replace(/"/g,'&quot;');
			t=t.replace(/>/g,'&gt;');
			t=t.replace(/</g,'&lt;');
			t=t.replace(/'/g,'&#39;');
			return t;
		}
		
		this.stringifyForXML = stringifyForXML;
		
		
		function log(string, format){
      console.log(string, format);
		}

		this.log = log;



	
		// pouzivaji metoddy ze sekce math
		function mathParameterType(a){
			var cislo = a;
			var ok = true;
			switch(myTypeOf(a)){
				case 'object': 																									break;
				case 'string': 	cislo = myParseFloat(a); 	ok = isFinite(a);			break;
				case 'number': 	cislo = a;								ok = isFinite(a);			break;
				default:				 													ok = false; 					break;
			};
			return {
				"cislo": 	cislo,
				"ok": 		ok
			};
		}
	
	
		// pouziva to funkce presne nasobeni, presne deleni
		function mathOperation(operation, cisla){
	
			// najdu si vsechna cisla
			var ok 			= true;
			var vysl 		= NaN;
			var pocetMist = [];
			
			// zkontroluju kazde cislo, ktere mi prislo
			for(var i=0; i<cisla.length; i++){
				cisla[i] = mathParameterType(cisla[i]);
				if(cisla[i].ok == false){
					ok = false;
				}
			}
			
			// spocitam vysledek pro danou operaci (napr. vsechna cisla vynasobim nebo vydelim)
			if(cisla.length > 1){
				vysl = cisla[0].cislo;
				for(var i=1; i<cisla.length; i++){
					switch(operation){
						case '+': 	vysl += cisla[i].cislo;		break;
						case '-': 	vysl -= cisla[i].cislo;		break;
						case '*': 	vysl *= cisla[i].cislo;		break;
						case '/': 	vysl /= cisla[i].cislo;		break;
					}
				}
			}
			
			//console.log('cisla', cisla, vysl);
			
			// pokud byly vsechna zadana cisla skutecne cisla, a zaroven je vysledek konecne cislo (neni periodicke) udelam presny vysledek a vratim jej 
			if(ok && isFinite(vysl)){
				pocetMist = vysl.toString().split('.');
				pocetMist = (pocetMist.length == 2) ? pocetMist[1].length : 0;
				//if(pocetMist > 14){pocetMist = 14;} // PROBLEM: nepresnost nevznika zvdycky na patnactem miste Např. 963*0.1 = 96.30000000000001 = 14 mist   ALE 0.7 / 0.1 =  6.999999999999999 = 15 mist!
				if(pocetMist > 10){pocetMist -= 1;} // oriznu posledni misto. Je to prasarna, ale: nepresnost nevznika zvdycky na patnactem miste Např. 963*0.1 = 96.30000000000001 = 14 mist   ALE 0.7 / 0.1 =  6.999999999999999 = 15 mist!
				return parseFloat(vysl.toFixed(pocetMist));
			}
			
			// jinak vratim to, co vzniklo nasobenim
			return vysl;
			
		}
		
		
		// presne nasobeni
		// binargon.math.multiply
		function multiply(/* libovolny pocet argumentu */){
			return mathOperation('*', Array.prototype.slice.call(arguments, 0));
		}
		
		// presne deleni (s presnosti na 14 desetinnych mist)
		function div(/* libovolny pocet argumentu */){
			return mathOperation('/', Array.prototype.slice.call(arguments, 0));
		}
		
		function plus(/* libovolny pocet argumentu */){
			return mathOperation('+', Array.prototype.slice.call(arguments, 0));
		}
		
		function minus(/* libovolny pocet argumentu */){
			return mathOperation('-', Array.prototype.slice.call(arguments, 0));
		}		
	
		// M
		this.math = {
			"div":				div,
			"minus":			minus,
			"multiply":		multiply,
			"plus":				plus
		};

		// VRACI VALUE ZADANEHO OBJEKTU
		// obj						objekt, ze ktereho chci value ziskat
		//		pole  	- vrati prvni prvek
		//		string	- vrati string
		//		number	-	vrati number osetreny pomoci myParseFloat
		//		boolean	-	vrati true/false
		//		domNode	- u formularovych prvku vraci value, jinak inner html
		//		function 	- vrati to, co vraci funkce
		//
		// defaultValue 	se pouzije, pokud nejde ze zadaneho objektu value dostat (napr. pokud misto objektu prijde null, undefined...)
		function value(obj, defaultValue){
			switch(myTypeOf(defaultValue)){
				case 'array':			defaultValue = (defaultValue.length > 0) ? defaultValue[0] : '';
				case 'string': 		break;
				case 'number': 		myParseFloat(obj); break;
				case 'boolean': 	break;
				case 'domNode': 	defaultValue = defaultValue.innerHTML; break;
				case 'function': 	defaultValue = defaultValue(obj); break;
				default: 					defaultValue = ''; break;
			}

			switch(myTypeOf(obj)){
				case 'array':			return (obj.length > 0) ? obj[0] : '';
				case 'string': 		return obj; break;
				case 'number': 		return obj; break;
				case 'boolean': 	return obj;	break;
        case 'object':    return obj; break;
				case 'domNode':
					switch(obj.nodeName.toLowerCase()){
						case 'select': 	return obj.value; break;
						case 'input':
							switch(obj.type.toString().toLowerCase){
								case 'checkbox':  return parseBoolean(obj); break;
							}
							return obj.value;
						break;
					}
					return obj.innerHtml;
				break;
				case 'event':
					if('target' in obj){return value(obj.target);}
				break;
				case 'function':	return obj(); break;
			}
			return defaultValue;
		}

		this.value = value;

		/* zavolam readyStateChange, protoze dokument uz od pocatku v nejakem stavu je a i tento stav je treba zpracovat */
		zpracujAktualniStavDokumentu()

	}

})();


/* kvuli zpetne kompatibilite... nektere starsi skiny vyuzaivaji tuto funkci misto volani metody binargon.parseFloat */
function myParseFloat(str){
	return binargon.parseFloat(str);
}

/* callback pro reCaptchu v2 */
      var reCaptchaCallback = function(){
        var g_captcha = document.querySelectorAll('.g-recaptcha');

        for (var i = 0; i < g_captcha.length; i++) {
          grecaptcha.render(g_captcha[i], {'sitekey' : '6LcdSkMjAAAAAJXs1LJ9yZtVtZTOvEr4db7OMCIr'});
        }
      };
    
if (!("console" in window))
{     
  window.console = {
      log: function () {},
      dir: function () {},
      clear: function () {}
  };
}

  	/* common_message */
    $(function(){      
      if($('#commonMessage').length>0)
      {
        var mesDiv = $('#commonMessage');
        var mesOpacityDiv = $('#commonMessageOpacity');

        /*hide message*/
          mesOpacityDiv.toggle();
          mesDiv.toggle();
        /*hide message*/

        /*pozadi*/
          var wh = $(document).height();
          var ww = $(document).width();
          if(mesOpacityDiv.hasClass('messageOpacityDefaultClass'))
          {
            mesOpacityDiv.css({'position':'absolute','top':'0px','left':'0px','width':ww+'px','height':wh+'px','background':'black','opacity':'0.9','zIndex':'1000'});
          }
        /*pozadi*/

        /*message*/
          if(mesDiv.hasClass('messageDefaultClass'))
          {
            mesDiv.css({'position':'absolute','top':'200px','left':'50%','width':'400','background':'white','zIndex':'1001','box-shadow':'0 0 5px 5px #444','-moz-box-shadow':'0 0 5px 5px #444','-webkit-box-shadow':'0 0 5px 5px #444','padding':'20px','border':'1px solid black','textAlign':'center'});
            mesDiv.find('.messageNazev').css({'marginBottom':'20px','fontWeight':'bold','fontSize':'120%'});
          }

          //var w = mesDiv.outerWidth()/2;
          var h = mesDiv.outerHeight()/2;
          /*mesDiv.css({'marginLeft':'-'+w+'px'});*/
          mesDiv.css({'marginLeft':'-200px'});
          /*mesDiv.css({'marginTop':'-'+h+'px'});*/
        /*message*/

        /*show message*/
          mesOpacityDiv.toggle();
          mesDiv.toggle();
        /*show message*/

        /*close message*/
          $('.closeMessage').click(function(){
            mesDiv.hide();
            mesOpacityDiv.slideUp();
          });
        /*close message*/
      }
    });
    /* common_message end */
  

		window.MediaQuery = {
			'S' : 'all and (min-width: 0px) and (max-width: 425px)',
			'M' : 'all and (min-width: 426px) and (max-width: 767px)',
			'L' : 'all and (min-width: 768px) and (max-width: 1279px)',
			'XL': 'all and (min-width: 1280px)',

			'SML': 'all and (min-width: 0px) and (max-width: 1279px)'
		};

		$(function(){
		
			// fancybox
			$('.js-fancy').click(function(){
				var target = $(this).attr('href');     
				$.fancybox({
					'href' : target,
					'autoDimensions': true,
					'transitionIn' :'elastic',
					'transitionOut' :'elastic',
					'closeSpeed': 80 
				});
			}); 

			$('.js-fancy-banner').fancybox({'closeSpeed': 80});

			// cart popup
			if ($('#js-cart-popup').length) {
				$.fancybox({
					content: $('#js-cart-popup'),
					padding: 0,
					modal: true
					
				});

				$('.js-cart-popup-close').click(function(){
					$.fancybox.close();
				});
			}

			// dropdown
			function createDropdown(wrappingElement,innerElement,button){
				var originalHeight = wrappingElement.height();

				if(innerElement.height() > originalHeight){
					button.show();
				} else {
					button.hide();
				}

				button.toggle(function(){
					wrappingElement.animate({ maxHeight: innerElement.height() }, 200);
					$(this).text($(this).data('less')).addClass('open');
				}, function(){
					wrappingElement.animate({ maxHeight: originalHeight }, 200);
					$(this).text($(this).data('more')).removeClass('open');
				});
			}

			// bestsellers dropdown
			if ($('#js-bestsellers-container').length){
				createDropdown($('#js-bestsellers-container'),$('#js-bestsellers-items'),$('#js-bestsellers-button'));
			}

			// recommended dropdown
			if ($('#js-recommended-container').length){
				createDropdown($('#js-recommended-container'),$('#js-recommended-items'),$('#js-recommended-button'));
			}

			// category description dropdown
			if($('#js-category-description-wrapping-default').length){
				createDropdown($('#js-category-description-wrapping-default'),$('#js-category-description-inner-default'),$('#js-category-description-button-default'));
			}
				  
			// popup filters
			$('.js-popup-filters-button, #js-popup-filters .filterSubmitButton').click(function(){
				$('#js-popup-filters').toggleClass('visible');
			});

			// menu (mobile)
			$('#js-menu-button').click(function(){
				$(this).toggleClass('open');
				$('#js-menu').slideToggle().toggleClass('visible');
				//$('#js-menu-items, #js-user-menu-mobile, #js-contact-mobile').slideToggle();
			});

			// scroll to element
			$('.js-scroll-to').click(function(){
				$('html, body').animate({
                    scrollTop: $('#' + $(this).data('scroll-to')).offset().top
                }, 500);
			});

			// delegate click on element
			$('.js-delegate-click').click(function(){
				$('#' + $(this).data('click-on')).click();
			});

			// show / hide search (mobile)
			$('.js-search-toggle').click(function(){
				var searchFormElement = window.matchMedia('(min-width: 1280px)').matches ? $('#js-search-form') : $('#js-search-form-mobile');

				if($(this).data('animation') == 'fade'){
					searchFormElement.fadeToggle();
				} else {
					searchFormElement.slideToggle();
				}	
			});

			// show / hide textpages (mobile)
			$('.js-prefooter-textpages-button').click(function(){
				if(window.matchMedia(window.MediaQuery.M).matches || window.matchMedia(window.MediaQuery.S).matches){
					$(this).toggleClass('open');
					$('.js-footerTextpages[data-id="' + $(this).data('id') + '"]').slideToggle();
				}
			});

			// show / hide recent reviews (mobile)
			$('#js-recent-reviews-button').click(function(){
				$(this).toggleClass('open');
				$('#js-recent-reviews-items').slideToggle();
			});

			var searchInputId = window.matchMedia('(min-width: 1280px)').matches ? '#js-search-input' : '#js-search-input-mobile';

			// WHISPERER
			var whisperer = new whispererClass({
				input					:	searchInputId,
				categories				:	4,
				vyrobci					:	4,
				products				:	6,
				highlight				:	true,
				imageproduct_width		:	47,
				imageproduct_height		:	47,
				//whispererTarget			:	'.js-search-whisperer',
				htmlItemClass			:	'whisperer__item',
				htmlSelectedItemClass	:	'whisperer__item--highlight',
				htmlWhisperer			:	function(data){
					// producers
					var producers = [];

					if(data && data.vyrobci && data.vyrobci.length){
						producers.push('<div class="whisperer__title">Výrobci</div>');
						producers.push('<div class="whisperer__links">');
							for(var i = 0; i < data.vyrobci.length; i++){
								producers.push('<a href="' + data.vyrobci[i].href + '" class="whisperer__item whisperer__item--categories">' + data.vyrobci[i].name + '</a>');
							}
						producers.push('</div>');
					}

					// categories
					var categories = [];

					if(data && data.categories && data.categories.length){
						categories.push('<div class="whisperer__title">Kategorie</div>');
						categories.push('<div class="whisperer__links">');
							for(var i = 0; i < data.categories.length; i++){
								categories.push('<a href="' + data.categories[i].href + '" class="whisperer__item whisperer__item--categories">' + data.categories[i].name + '</a>');
							}
						categories.push('</div>');
					}

					// products
					var products = [];

					if(data && data.products && data.products.length){
						products.push('<div class="whisperer__title">Produkty</div>');
						products.push('<div class="whisperer__links">');
							for(var i = 0; i < data.products.length; i++){
								products.push('<a href="' + data.products[i].href + '" class="whisperer__item whisperer__item--product"><div><img src="' + data.products[i].img + '" class="whisperer__item__image"/><span class="whisperer__item__name">' + data.products[i].name + '</span></div></a>');
							}
						products.push('</div>');
					}

					var submitButton = '<a href="#" data-whispereritemindex="submit" class="whisperer__item whisperer__item--submit whispererItemSubmit"><span class="submit">Zobrazit vše</span></a>';

					var html = producers.length || categories.length || products.length ? '<div class="whisperer__inner">' + producers.join('') + categories.join('') + products.join('') + submitButton + '</div>' : '';

					return html;
				}
			});

			// banners
			if ($('#js-slider-banners').length){
				$('#js-slider-banners').slick({
					dots: false,
					pager: false,
					infinite: true,
					speed: 500,
					fade: true,
					cssEase: 'linear',
					adaptiveHeight: true,
					autoplay: true,
					autoplaySpeed: $('#js-slider-banners').data('speed')
				});
			}

			// infobar close
			if($('#js-infobar-close').length){
				if (!sessionStorage.getItem('infobarHidden')){
					$('#js-infobar').css({display: 'grid'});

					$('#js-infobar-close').click(function(){
						$('#js-infobar').slideUp();
						sessionStorage.setItem('infobarHidden', 1);
					});
				}
			}

			// $('.js-leaf-toggle').click(function(event){
			// 	event.preventDefault();
			// 	var leaf = $(this).parent().parent();
				
			// 	if(leaf.hasClass('leaf--open-true')){
			// 		leaf.removeClass('leaf--open-true').addClass('leaf--open-false');
			// 		leaf.find('.tree').slideUp();
			// 	} else {
			// 		leaf.removeClass('leaf--open-false').addClass('leaf--open-true');
			// 		leaf.find('.tree').slideDown();
			// 	}
			// });

			// $('.js-leaf-toggle .tree--level-2').click(function(event){
			// 	event.stopPropagation();
			// });
		});
	
      /* recaptcha v2 */
      binargon_onCommplete.push(function(){
      var s = document.createElement('script');
      s.setAttribute('src', 'https://www.google.com/recaptcha/api.js?onload=reCaptchaCallback&render=explicit&hl=cs');
      document.getElementsByTagName('head')[0].appendChild(s);
      });
      

		binargon_onCommplete.push(function(){
			var povoleni = document.getElementById('id_povoleniCookiesCommonTemplate_binargon');
			if(povoleni!=null){
				var refreshCount = parseInt(document.getElementById('id_povoleniCookiesCommonTemplate_binargon_refreshCount').innerHTML, 10);
				var mini = document.getElementById('id_povoleniCookiesCommonTemplate_binargon_povoleniCookiesMini');
				var big = document.getElementById('id_povoleniCookiesCommonTemplate_binargon_povoleniCookiesBig');

		    document.getElementById('id_povoleniCookiesCommonTemplate_binargon_euCookies1').innerHTML = 'Tento web používá k poskytování služeb, personalizaci reklam a analýze návštěvnosti soubory cookie. Používáním tohoto webu s tím souhlasíte.';
				document.getElementById('id_povoleniCookiesCommonTemplate_binargon_euCookies4').innerHTML = 'Používáme cookies';

				/*
				if(document.cookie.indexOf('euCookiesAgree=1') > -1){
					povoleni.style.display = 'none';
				}
				*/
				if(document.cookie.indexOf('euCookiesAgree=1') == -1){
					povoleni.style.display = 'block';
				}else{
					povoleni.style.display = 'none';
				}

				document.getElementById('id_povoleniCookiesCommonTemplate_binargon_button').addEventListener('click', function() {
					var date = new Date();
					date.setFullYear(date.getFullYear() + 10);
					document.cookie = 'euCookiesAgree=1; path=/; expires=' + date.toGMTString();
					povoleni.style.display = 'none';
				}, false);

				if(refreshCount > 1){
					povoleni.addEventListener('mouseover', function(){
						mini.style.display = 'none';
						big.style.display = 'block';
					}, false);

			    povoleni.addEventListener('mouseout', function(){
						mini.style.display = 'block';
						big.style.display = 'none';
					}, false);
				}
			}



		});

	