// UTF-8

/*
function objectTagXhrCreate(id, fn_success, fn_error)
	{
	var div, obj, xhrObj;
	div = $('#xr_'+type);
	obj = document.createElement('OBJECT');
//	obj.onload  = function (event) {fn_success(type, event.target.result);}	// !!!not work!!!
	obj.onerror = function (event) {fn_error(type, event);}
	div.appendChild(obj);
	xhrObj = {};
	xhrObj.open = function (method, url, asyn, user, psw)
		{
		obj.src = url;	// GET
		}
	xhrObj.send = function () {};
	return xhrObj;
	}

function scriptXhrCreate(type, fn_success, fn_error)
	{
	var div, obj, xhrObj, script;
	script = document.createElement('OBJECT');
	script.onload  = function (event) {fn_success(type, event.target.result);}
	script.onerror = function (error) {fn_error(type, error);}
	document.head.append(script);
	xhrObj = {};
	xhrObj.open = function (method, url, asyn, user, psw)
		{
		script.src = url;	// GET
		}
	xhrObj.send = function () {};
	return xhrObj;
	}


*/

function iframeXhrCreate(type, fn_success, fn_error)
	{
	var div, iframe, xhrObj;
//	div = $('#xr_'+type);
	div = xapp.vars.el['reader'];
	iframe = document.createElement('IFRAME');
	iframe.onload  = function (event)
		{
		var doc, body, req_charset, doc_charset;
		doc  = event.target.contentWindow.document;
		body = doc.body.innerHTML;
		fn_success(type, body);
		}
	iframe.onerror = function (event) {fn_error(type, event);}
	div.appendChild(iframe);
	xhrObj = {};
	xhrObj.open = function (method, url, asyn, user, psw)	// 'GET', url, false
		{
		iframe.src = url;	// GET
		}
	xhrObj.send = function () {};
	return xhrObj;
	}
//		req_charset = doc.characterSet  ? doc.characterSet : doc.charset ? doc.charset : 'UTF-8';
//		doc_charset = doc.inputEncoding ? doc.inputEncoding : 'UTF-8'; 	//ISO-8859-2 meta tag WIN-1250
//		body = conv.convert(body, 'ISO-8859-2', 'UTF-8');
//		body = conv.convert(body, 'UTF-8', 'ISO-8859-2');
//		body = conv.convert(body, doc_charset, req_charset);


function xmlRequestCreate() {
    var xhrObj;
    
    if (window.XMLHttpRequest) {
        // branch for native XMLHttpRequest object - Mozilla, IE7
        try {
            xhrObj = new XMLHttpRequest();
        } catch (e) {
            xhrObj = null;
        }
    } else if (window.createRequest) {
        try {
            xhrObj = window.createRequest();
        }
        catch (e) {
            xhrObj = null;
        }
    } else if (window.ActiveXObject) {
        // branch for IE/Windows ActiveX version
        try {
            xhrObj = new ActiveXObject("Msxml2.XMLHTTP");
        } catch(e) {
            try{
                xhrObj = new ActiveXObject("Microsoft.XMLHTTP");
            }
            catch(e) {
                xhrObj = null;
            }
        }//catch
    } //if-else
    return xhrObj;
}//eof createXHR

function xmlXhrCreate(type, fn_success, fn_error)
	{
	var xhrObj, req;
	req = xmlRequestCreate();
	req.onreadystatechange = function()
		{
		var content;
		if (req.readyState == 4)
			{
		        try	{
				if (req.status == 200) 
					{
					xapp.dataTransfer.add(req.responseText.length);
					fn_success(type, req.responseText);
					}
				else 
					{
					fn_error(type, null, "Status error " + xhrObj.url);	//fn_error();
					}
				}
			catch (e)
				{
				if (req.responseText)
					{
					xapp.dataTransfer.add(req.responseText.length);
					fn_success(type, req.responseText);	// only localhost
					}
				else 	{
					fn_error(type, null, "Server Error " + xhrObj.url);	//fn_error("Server Error")
					}
				}
			}
		} 
	xhrObj = {};
	xhrObj.req  = req;
	xhrObj.open = function (method, url, asyn, user, psw)	// 'GET', url, false
		{
		xhrObj.url = url;
//		xhrObj.req.open(method, url, asyn);
		xhrObj.req.open('POST', url, asyn, user, psw);
		}
	xhrObj.send = function (params)
		{
		xhrObj.req.send(params?params:null);
		};
	return xhrObj;
	}


var $, $$;
$  = document.querySelector.bind(document);	// $ = function(id) {return documen.getElementById(id);}
$$ = document.querySelectorAll.bind(document);

function escapeRegexp(str)
	{
	var reg, symbols;
	patt = ('(['+'\\^$*+?.()|{}[]'.split('').join('\\'))+'])';
	reg  = new RegExp(patt,'g');
//alert(str)
	return str.replace(reg,'\\$1');
	}
function escapeUrl(str)
	{
	var func;
	func = encodeURIComponent || encodeURI || escape;
	return func(str);
	//encodeURIComponent(value).replace(/!/g,'%21').replace(/'/g,'%27').replace(/\(/g,'%28').replace(/\)/g,'%29').replace(/\*/g,'%2A').replace(/%20/g,'+');
	}

function isExist(item)   {return typeof(item)!='undefined' && item!=null;}
function isSet(item,key) {return typeof(item[key])!='undefined' && item!=null;}
function isArray(data)	 {return typeof(data)==='object' || typeof(data)==='array';}

function cloneArray(arr)
	{
	var i, i_end, new_arr;
	if (!isArray(arr))
		{return false;}
	new_arr = [];
	i_end = arr.length;
	for (i=0; i<i_end; i++)
		{
		if (!isArray(arr[i]))
			{new_arr[i] = arr[i];}
		else	{new_arr[i] = cloneArray(arr[i]);}
//alert([i, i_end])
		}
	return new_arr;
	}


var xapp = {};

xapp.vars = {};

xapp.fn_error = function (type, event, msg)
	{
	alert("Error loading " +  (isExist(event)? ' '+event.target.src : '') + (isExist(msg)? ' '+msg : ''));
	};

xapp.getTime = function()
	{
	return new Date().getTime();
	}

xapp.encode = function(content)
	{
	return JSON.stringify(content);
	}

xapp.send = function()
	{
	var cooldowner_list, msg, el, url_params;
	el  = xapp.vars.el['message_text'];
	msg = [
		xapp.vars.msg_whisper,
		xapp.vars.msg_user,
		el.value
		];
	el.value = '';				// smaz message-input policko
	if (xapp.vars.msg_whisper)
		{
		msg[2]   = xapp.messageUsernameRemove(msg[1]);
		el.value = xapp.messageUsernameAdd('', msg[1]);	// predvypln nick do message-input policka
		}
	else	{
		xapp.vars.msg_user = '';	// smaz user name pro pristi zpravu
		}
	xapp.vars.msg_time_sended = xapp.getTime();	// afk, last message
	cooldowner_list = xapp.vars.cooldowner_list;
	cooldowner_list['room_users'].pause3s();	// if not get receive after send, autorun refresh timer again
	cooldowner_list['room_screen'].pause3s();
	url_params = xapp.encode(msg);
	url_params = 'msg='+escapeUrl(url_params);
	xapp.receive('room_message', url_params);
	el.focus();
	return false;
	}

//xapp.sendText = function(xhr, url)
//	{
//	xapp.receiveText(xhr, url);
//	}

xapp.receiveMsgSended = function()
	{
	var cooldowner_list;
	xapp.vars.msg_time_sended = xapp.getTime();	// afk, last message
	cooldowner_list = xapp.vars.cooldowner_list;
	cooldowner_list['room_users'].start();
	cooldowner_list['room_screen'].start();
	}

xapp.receiveText = function(xhr, url, url_params)
	{
	if (isExist(url_params) && url_params!=='')
		{
		url += (url.indexOf('?')>=0 ? '&' : '?') + url_params;
		}
//	xhr.open("GET", url , true);
//	xhr.send(null); 
	xhr.open("POST", url.replace(/[?].*$/,'') , true);
	xhr.send(url.replace(/^.*?[?]/,'')); 
	} 

xapp.receive = function(type, url_params)
	{
	if (!xapp.vars.url[type]) {return;}
	return xapp.receiveText(xapp.vars.xhr[type], xapp.vars.url[type], url_params);	//, opt.fn_success, opt.fn_error
	}



xapp.decode = function(type, content)
	{
	var out, found, charset;
//	content = conv.convert(content, 'ISO-8859-2', 'UTF-8');
//	content = conv.convert(content, 'UTF-8', 'ISO-8859-2');
//	content = conv.convert(content, 'WIN-1250', 'UTF-8');
//	content = conv.convert(content, 'UTF-8', 'WIN-1250');
	out = [];
	if (type=='room_smileys')// html/json to array
		{
//alert(['room_smileys _content_', content]);
		if (content=='')
			{return false;}
		content = content.replace(/^.*?<body[^>]*>(.*)$/gm, '$1').replace('</body>', '');	// pro xml request z html stranky
		return JSON.parse(content);
		}
	if (type=='room_users')	// html/text to array
		{
		content.replace(/<p>(.+?)<\/p>/g, function(match, content0, offset, input_string)
			{
//			alert(content0)
			var row;
			row = [];
			row[0] = content0.indexOf('alt="M')>=0					// gender
					? 'm'
					: 'z';
			row[1] = content0.indexOf('alt="MC"')>=0 || content0.indexOf('alt="C"')>=0	// certifikovany
					? 'c'
					: '';
			row[2] = content0.replace(/.*userPopup\('([^']*).*$/g, '$1');		// name
			row[3] = content0.replace(/.* ([^"]*)\" onclick="userPopup.*/g, '$1');	// time
//alert(content0)
			row[4] = content0.indexOf('alt="star"')>=0	// star level
					? content0.replace(/^.*?\/star\/([^.]+?)\..*$/g, '$1')
					: '';
			if (row[2]!==content0)
				{
				out[out.length] = row;
				}
		        return "";
			});
//alert(out[0]);
		return out;
		}
	else {if (type=='room_screen')	// html/text to array
		{
//alert(content)
		content.replace(/(.+?)<br[^>]*>/g, function(match, content0, offset, input_string)
			{
//alert(content0)
//			out[out.length] = content0;

			var row, x;
			row = [];
			row[0] = content0.indexOf(' class="systemtext"')>=0 ? '1' : '0'; 
//if (row[0]=='0') alert(content0)
			row[1] = content0.indexOf(' class="systemtime')>=0
					? content0.replace(/^.*? class="systemtime"[^>]*>([^<]+).*$/g, '$1') // time from system msg
					: content0.replace(/^.*? (.*?) .*/, '$1');	// time from user msg
			row[2] = (x=content0.indexOf(' color="#')) && x>0 && x<20
					? content0.replace(/^.*? color="#([^"]+).*$/g, '$1')
					: ''; // color
			
			row[3] = row[0]=='1'	// user name FROM
					? '' // system mgs - umsg_room, umsg_roomi
					: content0.replace(/^.*? class="umsg_room[^>]*><b>(.+?)\:<\/b>.*?<\/span><\/font>.*$/g, '$1'); // user mgs
//if (row[0]!='0')
//alert(row)
//			content0 = content0.replace(/^( class="systemtime"[^>]+>[^<]+)$/g, '>'); // odstran time
//if (row[0]=='0')
//alert(content0)
			row[5] = row[0]=='1'
					? content0.replace(/^.*? class="systemtext"[^>]*>(.+?)<\/font>.*$/g, '$1').replace(/["]/g, '').replace(/<[^>]*>/,'')+'.' // system mgs, odstran uvozovky, odstran tagy, pridej tecku na konci vety
					: content0.replace(/^.*? class="umsg_room[^>]*>.*?<\/b>(.+?)<\/span><\/font>.*$/g, '$1'); // user mgs, odstran nick
			row[5] = row[5].replace(/<img[^>]*?(\*\d+\*)[^>]*>/, '$1');	// nahrad smajliky

			row[4] = row[0]=='1'	// user name TO
					? '' // system mgs - umsg_room, umsg_roomi
					: row[5].replace(/^\s+|\s+$/g, '').replace(/[: ]+.*$/,'');
//			alert(row[4]);
			row[4] = xapp.userlistFindByName(row[4])!==false ? row[4] : '';
//			alert(row[4]);
//if (row[0]=='0') alert(row)
//alert(row[3])
			if (row[0]!==content0)
				{
				out[out.length] = row;
//				out[out.length] = row.join(' ');
				}

		        return "";
			});

		return out;
		}}
	return false;
	}

xapp.format = function(type, content)
	{
	var i, i_end, j, j_end, str,  t, g, o, s, cert, user_list, text, name, reg, smiley_list, name2, me;
	switch (type)
	{
	case 'plain':
		if (typeof content!='string')
			{return false;}
		return content.replace("\n", '<br>');
		break;
//var pets = '{"pets":[{"name":"jack"},{"name":"john"},{"name":"joe"}]}';
//var arr = JSON.parse(pets);
//alert(arr.pets[0].name);
	case 'room_smileys':
		i_end = content.length;
		smiles_list = {};
		str   = '';
		for (i=0; i<i_end; i++)
			{
			smiles_list[content[i][0]] = content[i];
			str += ""+'<span class="smiley" onclick="xapp.messageAdd(\'smiley\','+content[i][0]+')">'+xapp.smileyCreateImg(content[i][0], content[i][1])+'</span>';	// name
			}
		xapp.vars.smiles_list = smiles_list;
		return str;
		break;
	case 'room_users':
		str   = '';
		i_end = content.length;
		for (i=0; i<i_end; i++)
			{
			t = content[i][3].split(':');
			t = t[0] * 1;
			o = t<=15 ? '0' : '1';
			g = content[i][0]=='m' || content[i][0]=='?' ? '1' : '0';
			content[i][5] = o;
			content[i][6] = o+g+content[i][2].toLowerCase(); // serazeni: offline na konec, zeny pred muze
			content[i][7] = true;	// online (by screen) = true
			content[i][8] = false;	// add by screen = false
			}
		xapp.vars.user_list = content;
//alert(xapp.vars.user_list.length)
		xapp.userlistDraw();
		return;
		break;
	case 'room_screen':
		user_list = xapp.vars.user_list;
		me        = xapp.vars.user_name;
//alert(['user_list', user_list, xapp.vars.user_list]);
		j_end = user_list.length;
		str   = '';
		i_end = content.length;
		for (i=i_end-1; i>=0; i--)		// pridej/odeber uzivatele podle screen (muze odstranit cert a hvezdicky)
			{
			name = content[i][3].replace(/^\s+|\s+$/g, '');
			if (content[i][0]!=='1')	// no system msg
				{
				xapp.userlistAddByScreen(name, null);
				continue;
				}
			// system msg
			text = content[i][5];
			if (text.match('vstoupila')!==null || text.match('vstoupil')!==null)
				{
				g = text.match('vstoupila')!==null ? 'z' : 'm';
				name = text.match(/ ([^ <]+)/);
				name = name[0].replace(/^\s+|\s+$/g, '');	// trim
				xapp.userlistAddByScreen(name, g);
				continue;
				}
			else {if (text.match('vyhozen|vyhozena|opustil|opustila')!==null)
				{
				xapp.userlistRemoveByScreen(name);
				}
				}
			}
		xapp.userlistDraw();
		for (i=0; i<i_end; i++)
			{
			text = content[i][5];
			if (content[i][0]=='1')
				{
				text = text.replace(/ ([^ <]+)/, ' <span class="name" onclick="xapp.messageAdd(\'name\',this.innerHTML)">$1</span>'); // clickable nick
				str += "\n"+'<div class="msg_system"><span class="time">'+content[i][1]+'</span><span class="text">'+text+'</span></div>';
//  onclick="xapp.messageAdd(\'name\',this.innerHTML)
				continue;
				}
			name = content[i][3];
			content[i][1] = '<span class="time">'+content[i][1]+'</span>';	// time
			content[i][3] = '<span class="name" style="color:#'+content[i][2]+'" onclick="xapp.messageAdd(\'name\',this.innerHTML)">'+content[i][3]+': </span>';	// name
/*	// zvyrazneni nicku
			for(j=0; j<j_end; j++)
				{
				name = escapeRegexp(user_list[j][0]);
//alert(name);
				reg  = new RegExp('^.?('+name+')(:)|^.?('+name+')( )', 'i');
				if (text.match(reg))
					{
					text = text.replace(reg, '<span class=\"name_founded\">$1</span>$2');
					break;
					}
				}
*/
			text = text.replace(/\*(\d+)\*/, function (match, content0, offset, input_string)	// smajliky
					{
					var id, title, id99, bool, url, file;
//					id    = content0;
//					bool  = isSet(xapp.vars.smiles_list, id);
//					title = bool ? xapp.vars.smiles_list[id][1] : id;
//					file  = bool ? xapp.vars.smiles_list[id][0] : id;
//					file  = file+'.gif';
//					id99  = (''+id).replace(/.*?(\d\d|\d)$/, '$1');
//					url   = xapp.vars.smiles_url+id99+'/'+file;
//					return '<img src="'+url+'" alt="'+file+'" title="'+title+'">';
					return xapp.smileyCreateImg(content0);
					});
			name2 = content[i][4];
//alert(name2)
			content[i][5] = '<span class="text" style="color:#'+content[i][2]+'">'+text+'</span>';
			content[i][0] = '';	// type system msg
			content[i][2] = '';	// time
			content[i][4] = '';	// name2 TO
//alert([content[i][1], me, name2])
			str += "\n"+'<div class="msg '+(me==name ? 'sended' : (me==name2 ? 'receivedme' : 'received'))+'">' + content[i].join(' ') + '</div>';
			}
		return str;
		break;
		}
	return false;
	}

xapp.messageUsernameRemove = function(msg)
	{
	var n, msg_user;
	msg_user = xapp.vars.msg_user;
	if (msg_user!=='')	// smaz stary nick
		{
		n = msg.indexOf(msg_user);
		if (n>=0 && n<5)
			{
			msg = msg.substring(n+msg_user.length).replace(/^[\: ]*/, '');
			}
		}
	return msg;
	}

xapp.messageUsernameAdd = function(msg, msg_user)
	{
//	msg = xapp.messageRemoveUsername(msg, msg_user)
	msg = (''+msg_user).replace(/[\: ]+$/g, '') + ': ' + msg;
	return msg;
	}

xapp.messageAdd = function(type, str)
	{
	var el, n, msg_user;
	el = xapp.vars.el['message_text'];
	if (!el)
		{return;}
	switch (type)
		{
		case 'name'   : 
//				msg_user = xapp.vars.msg_user;
//				if (msg_user!=='')	// smaz stary nick
//					{
//					n = el.value.indexOf(msg_user);
//					if (n>=0 && n<5)
//						{
//						el.value = el.value.substring(n+msg_user.length).replace(/^[\: ]*/, '');
//						}
//					}
//				el.value = (''+str).replace(/[\: ]+$/g, '') + ': ' + el.value;
				el.value = xapp.messageUsernameRemove(el.value);
				el.value = xapp.messageUsernameAdd(el.value, str);
				xapp.vars.msg_user = str;
				break;
		case 'smiley' : el.value += ' *' + str + '*'; break;
		case 'whisper':
			xapp.vars.msg_whisper = !xapp.vars.msg_whisper;
			if (xapp.vars.msg_whisper)
				{
				xapp.classAdd(el, 'icon-ghost');
				}
			else    {
				xapp.classRemove(el, 'icon-ghost');
				}
			break;
		default: break;
		el.value = el.value;	// move cursor to end text
		el.focus();
		}
	}


xapp.smileyCreateImg = function(id, title)
	{
	var file, id99;
	file  = id;
	title = !isExist(title) && isExist(xapp.vars.smiles_list[id]) ? xapp.vars.smiles_list[id][1] : id;
	file  = file + '.gif';
	id99  = (''+id).replace(/.*?(\d\d|\d)$/, '$1');
	url   = xapp.vars.url['img_smiley'] + id99 + '/' + file;
	return '<img src="'+url+'" alt="'+file+'" title="'+title+'" onload="xapp.smileyDownload(this.src,'+id+')">';
	}

xapp.smileyDownload = function(url, id)
	{
	if (isExist(xapp.vars.smiles_list[id]) && !isExist(xapp.vars.smiles_list[id][2]))
		{
		xapp.vars.smiles_list[id][2] = url;
		xapp.dataTransfer.addLoadedFileSize(url);
		}
	}

xapp.userlistDraw = function(bool)
	{
	var i, i_end, list, out, t, g, o, s, cert, row, new_row;
	out  = '';
	list = cloneArray(xapp.vars.user_list);	// naklonuj userlist, aby jsi neprepisoval array
	list.sort(function(a,b) {return a[6]>b[6];});
	i_end = list.length;
	for (i=0; i<i_end; i++)
		{
		if (list[i][7]==false)	// kdyz podle room_screen opustil mistnost
			{continue;}
		row = list[i];
		if (list[i][8]==true)	// uzivatel pridany podle screen, pozor! muze to byt fake user, tak mozna tuto funkci zakazat
			{
			t = -1;
			g = row[0];
			s = '';
			cert = '';
			}
		else	{
			t = row[3].split(':');
			t = t[0] * 1;
			g = row[0];
			o = t<=15 ? '' : 'offline';
			s = row[4];
			s = s=='x2' ? 'modra - VIP uzivatel' : (
			    s=='x1' ? 'cerna - xchat VIP uzivatel' : (
			    s=='x8' ? 'zluta - xchat admin' : (
			    s=='x98' ? 'zelena - xchat admin ve zkusebni dobe' : (
			    s=='x99' ? 'cervena - xchat admin vedeni' : ''
				))));
			cert = row[1];
			}
		new_row = [];
//		content[i][0] = '<span class="gender '+g+' '+g+cert+'">'+(cert ? g.toUpperCase() : g)+'</span>';	// gender
		new_row[0] = '<span class="gender icon '+(g=='m' || g=='?' ? 'icon-male' : 'icon-female')+'">'+' &nbsp; &nbsp; '+'</span>';	// gender // '+g+cert+' ... (cert ? g.toUpperCase() : g)
		new_row[1] = '<span class="name" onclick="xapp.messageAdd(\'name\',this.innerHTML)">'+row[2]+'</span>';	// name
		new_row[2] = t<=15 ? '' : '('+t+' min)';		// time
		new_row[3] = row[4]!=='' && row[4]!=='?' ? '<span class="star '+row[4]+'" title="'+s+'">&#9733;</span>' : '';	// star
		out += "\n"+'<div class="user '+o+' '+cert+g+'" title="'+t+' min'+(cert!='' ? ', reálný uživatel (certifikovaný) ':', anonymní uživatel')+'">' + new_row.join(' ') + '</div>';
//		str += content[i].join(' ') + '<br>';
		}
	if (bool)
		{
		return out;
		}
	xapp.vars.el['room_users'].innerHTML = out;
	}

xapp.userlistFindByName = function(name)
	{
	var i, i_end, list;
	if (!isExist(name) || name=='')
		{return false;}
	list  = xapp.vars.user_list;
	i_end = list.length;
	for(i=0; i<i_end; i++)
		{
		if (list[i][2]==name) {return i;}
		}
	return false;
	}

xapp.userlistAddByScreen = function(name, gender)
	{
//	var row, g, t, o, list, h, m, s;
	var list, i, row;
	if (!isExist(name) || name=='')
		{return false;}
	list = xapp.vars.user_list;
	i    = xapp.userlistFindByName(name);
	if (i!==false)
		{
		row    = list[i];
		row[7] = true;
		}
	else	{
		i   = list.length;
		row = [gender, '?', name, '', '?', 0, '11', false, false];
		o   = '0';
		g   = row[0]=='m' || row[0]=='?' ? '1' : '0';
		row[5] = o;
		row[6] = o + g + row[2].toLowerCase(); // serazeni: offline na konec, zeny pred muze
		row[7] = true;
		row[8] = true;	// if from screen, use special render
		}
	xapp.vars.user_list[i] = row;
	}
//		// !!! pozor, chybne to nastavuje pro aktualni datum, protoze nemam cele casove razitko
//		time = time.split(':');
//		t = new Date()
//		t.setHours(time[0])
//		t.setMinutes(time[1])
//		t.setSeconds(time[2])
//		t = xapp.getTime() - t.getTime();
//		h = Math.floor(t / 1000 / 60 / 60);	// hod
//		m = Math.floor(t / 1000 / 60 - h * 60);	// min
//		s = Math.floor(t / 1000 - m * 60);	// min
//		t = h+':'+m+':'+s;

xapp.userlistRemoveByScreen = function(name)
	{
	var i;
	if (isExist(name) && name=='')
		{return false;}
	i = xapp.userlistFindByName(name);
	if (i>0)
		{
		xapp.vars.user_list[i][7] = false;
		}
	}


xapp.drawScreen = function(type, content)
	{
	var arr, str;
//alert('content='+content)
//alert(content);
	arr = xapp.decode(type, content);
	str = arr!==false ? xapp.format(type, arr) : xapp.format('plain', content);
	if (str=='')
		{return;}

	xapp.vars.el[type].innerHTML = str;
	}


xapp.drawUsers = function(type, content)
	{
	var arr, str;
//alert(content);
	arr = xapp.decode(type, content);
	if (arr!==false)
		{
		xapp.format(type, arr);
		}
	}

xapp.drawSmileys = function(type, content)
	{
	var arr, str;
//alert(content);
	arr = xapp.decode(type, content);
	str = arr!==false ? xapp.format(type, arr) : xapp.format('plain', content);
	if (str=='')
		{return;}
	xapp.vars.el[type].innerHTML = str;
//	xapp.receive('room_screen');
	}

xapp.drawName = function(type, content)
	{
	if (isExist(type) && isExist(content))
		{
		xapp.vars.user_name = content;
		}
	xapp.vars.el[type].innerHTML = xapp.vars.user_name;
	}

xapp.classRemove = function(el, name)
	{
	var patt, reg, str, s;
	if (!isExist(el))
		{return;}
	s    = '\\s+';
	str  = el.className;
	patt = '^'+name+'$' +'|'+ '^'+name+s +'|'+ s+name+'$' +'|'+ s+name+s;
	reg  = new RegExp(patt, 'g');
	str  = str.replace(reg, '');
	el.className = str;
	return str;
	}

xapp.classAdd = function(el, name)
	{
	var str, root;
	root = xapp;
	if (!isExist(el))
		{return;}
	str = root.classRemove(el, name);
	str = str=='' ? name : ' '+name;
	el.className += str;
	return str;
	}

xapp.classToggle = function(el, name)
	{
	var root, a, b;
	root = xapp;
	if (!isExist(el))
		{return;}
	a = el.className;
	b = root.classRemove(el, name);
	if (a==b)
		{root.classAdd(el, name);}
	}

xapp.classToggleAll = function(el, name)
	{
	var root, a, b;
	root = xapp;
	if (!isExist(el))
		{
		xapp.btnTabHideAll();
		return;
		}
	a = el.className;
	b = root.classRemove(el, name);
	xapp.btnTabHideAll();
	if (a!=b)
		{
		root.classRemove(el, name);
		}
	}
/*
xapp.btnUsersClick = function (bool)
	{
	var root, el, a, b;
	root = xapp;
	el = xapp.vars.el['chat'];
	if (!isExist(el))
		{return;}
	a = el.className.length;
	b = root.classRemove(el, 'usershiden');
	b = b.length;
	if (a==b || bool)
		{root.classAdd(el, 'usershiden').length;}
	};

xapp.btnSmilesClick = function (bool)
	{
	var root, el, a, b;
	root = xapp;
	el   = root.vars.el;
	root.classAdd(el['room_users'], 'd-none');
//	root.btnUsersClick(true)
//
//	el = $('#x_usershide');
//	if (!isExist(el))
//		{return;}
//	a = el.className.length;
//	b = root.classRemove(el, 'usershide');
//	b = b.length;
//	if (a==b || bool)
//		{root.classAdd(el, 'usershide').length;}

	};
*/

xapp.btnTabHideAll = function ()
	{
	var root, el;
	root = xapp;
	el   = root.vars.el;
	root.classAdd(el['room_users']  , 'd-none');
	root.classAdd(el['room_smileys'], 'd-none');
	root.classAdd(el['room_sett']   , 'd-none');
	}

xapp.btnTabShow = function (type, bool)
	{
	var root, el;
	root = xapp;
	el   = root.vars.el;
//	xapp.btnTabHideAll();
	root.classToggleAll(el[type], 'd-none');
	}



xapp.init = function()
	{
	var xhr, el, url, timer_list, type;

	xapp.vars.user_list = [];
	xapp.vars.smiles_list = {};
	xapp.vars.xhr_list = {};
	xapp.vars.el_list  = {};
	xapp.vars.timer_list = {};
	xapp.vars.user_session = 'wh=~holy~c8e210bf279c92755986830950322a9e';
	xapp.vars.user_name = 'holy';
	xapp.vars.msg_whisper = false;
	xapp.vars.msg_user  = '';
	xapp.vars.msg_time_sended = xapp.getTime();	// afk, last message
//	xapp.vars.msg_text  = '';
	xapp.vars.cooldown_list = {};
	xapp.vars.cooldown_list['room_screen'] = {0: 17, 2: 30, 5: 60, 10: 120, 15: 180};	// dynamicky refresh podle afk
	xapp.vars.cooldown_list['room_users']  = {0:180, 2:180, 5:360, 10: 720, 15:1440};	// dynamicky refresh podle afk
//	xapp.vars.cooldown_list['room_screen'] = {0: 5, 5: 10, 10: 20, 15: 180};	// dynamicky refresh podle afk
//	xapp.vars.cooldown_list['room_users']  = {0:180, 5:360, 10: 720, 15:1440};	// dynamicky refresh podle afk
//	xapp.vars.refresh_list = {};
//	xapp.vars.refresh_list['room_screen'] = xapp.getRefresh('room_screen');
//	xapp.vars.refresh_list['room_users']  = xapp.getRefresh('room_users');

	url = {};
//	url['chat'] = 'https://mlich.zam.slu.cz/js-xchat/';
	url['chat'] = 'http://localhost/js-xchat/';
//	url['ws'  ] = url['chat'] + 'pages/';	// web-services
	url['ws'  ] = url['chat'] + 'pages_utf8/';// web-services
	url['ws_opt'  ] = '&format=json&codepage=utf-8';	// json, csv, txt, html
	url['img_smiley'  ] = url['chat'] + 'smiles/';
	url['chat_login'  ] = url['ws'] + 'chat_login.html'  + '?'+xapp.vars.user_session+url['ws_opt'];
	url['chat_rooms'  ] = url['ws'] + 'chat_rooms.html'  + '?'+xapp.vars.user_session+url['ws_opt'];
	url['room_enter'  ] = url['ws'] + 'room_enter.html'  + '?'+xapp.vars.user_session+url['ws_opt'];
	url['room_info'   ] = url['ws'] + 'room_info.html'   + '?'+xapp.vars.user_session+url['ws_opt'];
	url['room_screen' ] = url['ws'] + 'room_screen.html' + '?'+xapp.vars.user_session+url['ws_opt'];
	url['room_users'  ] = url['ws'] + 'room_users.html'  + '?'+xapp.vars.user_session+url['ws_opt'];
	url['room_message'] = url['ws'] + 'room_message.html'+ '?'+xapp.vars.user_session+url['ws_opt'];
	url['room_smileys'] = url['ws'] + 'room_smileys.html'+ '?'+xapp.vars.user_session+url['ws_opt'];
	xapp.vars.url = url;
//xapp.vars.smiles_url = 'https://x.ximg.cz/images/x4/sm/';
//	var chat_url = 'https://mlich.zam.slu.cz/js-xchat/';
//	var ws_url   = chat_url + 'pages/';
//	url['room_screen'] = ws_url + 'room_screen.html';
//	url['room_users' ] = ws_url + 'room_users.html';

/*
//	url['screen']   = 'https://m.xchat.cz/?c=0&m=4&rnd=9228#content';		//&wh=~mracek123~c8e210bf279c92755986830950322a9e
//	url['users']    = 'https://m.xchat.cz/?c=0&m=4&tif=&d=1#content';		//&wh=~mracek123~c8e210bf279c92755986830950322a9e&rnd=9286&rif=12611732
//	url['screen']   = 'http://localhost/js-xchat/test-screen.html';
//	url['message']  = '';
//	url['rooms']    = 'https://m.xchat.cz/?c=0&m=4&rnd=9180&p=2&cid=2#content';	//&wh=~mracek123~c8e210bf279c92755986830950322a9e
//	url['session']    = '';
//	url['login']    = 'https://xchat.cz/?login=1#content';
	url['users']    = 'https://m.xchat.cz/?c=0&m=4&tif=&d=1#content';		//&wh=~mracek123~c8e210bf279c92755986830950322a9e&rnd=9286&rif=12611732
	url['screen']   = 'http://localhost/js-xchat/test-screen.html';
	url['message']  = '';
	url['rooms']    = 'https://m.xchat.cz/?c=0&m=4&rnd=9180&p=2&cid=2#content';	//&wh=~mracek123~c8e210bf279c92755986830950322a9e
	url['session']    = '';
	url['login']    = 'https://m.xchat.cz/?login=1#content';
*/
// https://mistnost.xchat.cz/16-let-a-vice
//https://www.xchat.cz/~$13262955~c8e210bf279c92755986830950322a9e/modchat/room/16-let-a-vice
//document.body.parentElement.innerHTML
// document.documentElement.innerHTML;
//document.documentElement.outerHTML
//document.getElementsByTagName('html')[0].innerHTML 

	el = {};
	el['chat']         = $('#x_chat');
	el['message_text'] = $('#x_room_message_text');
	el['reader']       = $('#x_chatreader');
	el['name']         = $('#x_room_message_nick');
	el['data_transfer']= $('#x_data_transfer');

	

//	type = 'chat_login'  ; el['xr_'+type] = $('#xr_'+type); el['x_'+type] = $('#x_'+type);
//	type = 'room_enter'  ; el['xr_'+type] = $('#xr_'+type); el['x_'+type] = $('#x_'+type);
//	type = 'room_info'   ; el['xr_'+type] = $('#xr_'+type); el['x_'+type] = $('#x_'+type);
	type = 'room_screen' ; el[type] = $('#x_'+type+'_panel'); el[type+'_cooldown'] = $('#x_'+type+'_cooldown');
	type = 'room_users'  ; el[type] = $('#x_'+type+'_panel'); el[type+'_cooldown'] = $('#x_'+type+'_cooldown');
	type = 'room_message'; el[type] = $('#x_'+type);
	type = 'room_smileys'; el[type] = $('#x_'+type+'_panel');
	type = 'room_sett'   ; el[type] = $('#x_'+type+'_panel');
	xapp.vars.el = el;

	xhr = {};
	// iframe request
//	xhr['room_users']   = iframeXhrCreate('room_users'  , xapp.drawUsers   , xapp.fn_error);
//	xhr['room_screen']  = iframeXhrCreate('room_screen' , xapp.drawScreen  , xapp.fn_error);
//	xhr['room_smileys'] = iframeXhrCreate('room_smileys', xapp.drawSmileys , xapp.fn_error);
	// xml request
	xhr['room_users']   = xmlXhrCreate('room_users'  , xapp.drawUsers   , xapp.fn_error);
	xhr['room_screen']  = xmlXhrCreate('room_screen' , xapp.drawScreen  , xapp.fn_error);
	xhr['room_smileys'] = xmlXhrCreate('room_smileys', xapp.drawSmileys , xapp.fn_error);
	xhr['room_message'] = xmlXhrCreate('room_message'    , xapp.receiveMsgSended , xapp.fn_error);

//	xhr['chat_login']  = iframeXhrCreate('chat_login' , xapp.receiveScreen , xapp.fn_error);
//	xhr['chat_rooms']  = iframeXhrCreate('chat_rooms' , xapp.receiveScreen , xapp.fn_error);
//	xhr['room_enter']  = iframeXhrCreate('room_enter' , xapp.receiveScreen , xapp.fn_error);
//	xhr['room_info']   = iframeXhrCreate('room_info' , xapp.receiveScreen , xapp.fn_error);


//	xhr['room_info'] = scriptTagXhrCreate('xr_session', xapp.receiveSession, fn_error);


	xapp.vars.xhr = xhr;

	cooldowner_list = {};
	type = 'room_users';
	cooldowner_list[type] = new classCooldown({
		func: {
			receive: xapp.receive,
			},
		type: type,
		el  : el[type+'_cooldown'],
		cooldown_list: xapp.vars.cooldown_list[type]
		});
	type = 'room_screen';
	cooldowner_list[type] = new classCooldown({
		func: {
			receive: xapp.receive,
			},
		type: type,
		el  : el[type+'_cooldown'],
		cooldown_list: xapp.vars.cooldown_list[type]
		});
	xapp.vars.cooldowner_list = cooldowner_list;
//	cooldown_list = {};
//	type = 'room_users' ; timer_list[type].start(type);
//	type = 'room_screen'; timer_list[type].start(type);
	xapp.dataTransfer = new classDataTransfer({el: el['data_transfer']});
	xapp.dataTransfer.add(document.getElementsByTagName('HTML')[0].outerHTML.length);
//	xapp.dataTransfer.add(xapp.getLoadedFileSize(location.href));
//	xapp.dataTransfer.add(xapp.getLoadedFileSize(url['chat'] + 'convert_codepage.js'));
//	xapp.dataTransfer.add(xapp.getLoadedFileSize(url['chat'] + 'x_chat_app.js'));
	el['message_text'].focus();

	};

// msg send
// xapp.vars.user_afk = 0;
//	type = 'room_users' ; xapp.timer_list[type].start();
//	type = 'room_screen'; xapp.timer_list[type].start();




xapp.init();
xapp.drawName('name');
xapp.receive('room_users');
xapp.receive('room_screen');
xapp.receive('room_smileys');
//xapp.btnTabShow('room_users');
xapp.btnTabShow('');


// --- cooldown class ---
function classCooldown(opt)
{
//var that_timer = this;
var root = this;
this.vars = {};
this.receive = null;

this.computeCooldown = function()
	{
	var t, i, list, out;
	t     = Math.round((xapp.getTime() - xapp.vars.msg_time_sended) / 1000 / 60);	// min
	list  = root.vars.cooldown_list;
	out = list[0];
	for(i in list)
		{
		if (t>i) {out = list[i]}
		}
	return out;
	}

this.printCooldown = function()
	{
	var el;
	root.vars.el.innerHTML = root.vars.cooldown;
	el = xapp.vars.el['message_text'];
//	el.focus();
	}

this.start = function()	//type
	{
	root.vars.cooldown = root.computeCooldown();
//	root.vars.timer.start();
	root.vars.timer.run();
	};

this.pause3s = function()	//type
	{
	root.vars.timer.pause();
	setTimeout(root.pause3sCB, 3000);
	};

this.pause3sCB = function()
	{
	if (root.vars.timer.vars.state==2)
		{
		root.vars.timer.run();
		}
	}

this.run = function()	//type
	{
//	root.vars.timer.stop();
	root.vars.cooldown--;
	root.printCooldown();
	if (root.vars.cooldown<=0)
		{
		root.receive(root.vars.type);
		root.vars.cooldown = root.computeCooldown();
//		root.stop();
//		root.start();
		return 1;
		}
//	root.vars.timer.run();
	return 1;
	};

this.stop = function(type)
	{
	root.vars.timer.stop();
//	root.start();
	}

this.init = function(opt)
	{
	root.receive   = isExist(opt.func) && isExist(opt.func.receive) ? opt.func.receive : null;
	root.vars.type = isExist(opt.type)       ? opt.type       : null;
	root.vars.el   = isExist(opt.el)         ? opt.el         : null;
	root.vars.cooldown_list = isExist(opt.cooldown_list) ? opt.cooldown_list : null;
	root.vars.cooldown      = null;
	root.vars.timer = new classTimer({
		func: {
//			start: root.start,
			run  : root.run
//			stop : root.stop
			},
		 speed: 1000
		});
	root.start();
	root.run();
	}

this.init(opt);
}



// --- timer class ---
function classTimer(opt)
{
//var that_timer = this;
var root = this;
var bool_fn = isExist(opt.func);
root.vars = {};
root.vars.timeout_id = null;
root.vars.step      = -1;
root.vars.state     = -1;
root.vars.speed     = isExist(opt.speed) && opt.speed>50 ? opt.speed : 50;
root.cb_func = {};
//root.cb_func.start = bool_fn && isExist(opt.func.start) ? opt.func.start : function () {};
root.cb_func.run   = bool_fn && isExist(opt.func.run)   ? opt.func.run   : function () {};
//root.cb_func.pause = bool_fn && isExist(opt.func.pause) ? opt.func.pause : function () {};
//root.cb_func.stop  = bool_fn && isExist(opt.func.stop)  ? opt.func.stop  : function () {};

this.start = function() 
	{
	root.pause();
	root.vars.state = 0;
//	root.cb_func.start();
	}
this.run = function(opt)
	{
	root.pause();
	root.vars.state = 1;
	root.vars.state = root.cb_func.run();
	if (root.vars.state==1)
		{
		root.vars.timeout_id = setTimeout(function(){root.run();}, root.vars.speed);
		}
//	alert(['run',root.vars.id])
	}
this.pause = function()
	{
//alert(root.vars.id)
	if (root.vars.timeout_id!=null)
		{
		clearTimeout(root.vars.timeout_id);
		}
	root.vars.state = 2;
	}
this.stop  = function()
	{
	root.pause();
	root.vars.state = -1;
//	root.cb_func.stop();
	}
}


// --- datatransfer class ---
function classDataTransfer(opt)
{
//var that_timer = this;
var root = this;
var bool_fn = isExist(opt.func);
root.vars = {};
root.vars.saved_data = 0;
root.vars.saved_interval = 0;
root.vars.data       = 0;
root.vars.time_start = 0;
root.vars.time = 0;
root.vars.data_per_second = '';
root.vars.el = null;

this.add = function(n)
	{
	var t;
	root.vars.data += n;
	t  = root.getTime() - root.vars.time_start;
	t /= 1000;
	t  = t>0 ? t : 1;
	root.vars.time = t;
	root.vars.data_per_second = Math.floor(root.vars.data / t);
//alert(root.vars.data)
	root.printDataTransfer();
	}

this.addLoadedFileSize = function(url)	// URL.createObjectURL(blob)	// tady si nejsem jisty, zda to obrazek nestahuje duplicitne z url, ale veme ho z kese
	{
	fetch(url).then(resp => resp.blob())
	  .then(blob => {
		root.add(blob.size);
	    });
	}

this.formatBytes = function(bytes, decimals)
	{
	var i, k, dm, size_list, out, n;
	if (bytes === 0) return '0 B';
	k  = 1024;
	dm = decimals < 0 ? 0 : decimals;
	size_list = ['B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
	i  = Math.floor(Math.log(bytes) / Math.log(k));
	i = i<size_list.length ? i : size_list.length - 1;
//	alert([i, bytes, parseFloat((bytes / Math.pow(k, i)).toFixed(dm))])
	n   = Math.pow(10, dm);
	out = bytes / Math.pow(k, i);
	out = Math.floor(out*n)/n;
	return out + ' ' + size_list[i];
	}

this.formatTime = function(seconds, decimals)
	{
	var time_list, time_after, i, i_end, out, next, dm, n;
	time_list       = [60, 60, 60, 24, 365];
	time_list_after = ['s', 'min', 'h', 'days', 'years'];
	dm    = decimals < 0 ? 0 : decimals;
	next  = Math.floor(seconds);
	i_end = time_list.length - 1;
	for (i=0; Math.floor(next)>time_list[i+1] && i<i_end; i++)
		{
		next = next / time_list[i];
		}
	n   = Math.pow(10, dm);
	out = next;
	out = Math.floor(out*n)/n;
	out = out + ' ' + time_list_after[i];
//	out = i==0 || i==1 ? out[i] : out[i]+' '+out[i-1]; // format 1s OR 1min OR 1h 1min OR 1day 1h (two last)
	return out;
	}

this.printDataTransfer = function()
	{
	root.vars.el.innerHTML = root.formatBytes((root.vars.data_per_second<root.vars.data ? root.vars.data_per_second : root.vars.data) * 1, 2) + '/s ('+root.formatBytes(root.vars.data * 1, 2)+', '+root.formatTime(root.vars.time, 2)+')';
	}

this.getTime = function()
	{
	return new Date().getTime();
	}

this.init = function(opt)
	{
	root.vars.el = isExist(opt.el) ? opt.el : null;
	root.vars.time_start = root.getTime();
	root.printDataTransfer();
	}
this.init(opt);
}


// https://receive-smss.com/sms/420703412817/