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

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

function isString(item) {return typeof item=='string' && item!=null;}
function isFunction(item) {return typeof item=='function' && item!=null;}
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') && data!==null && data.length;}

function escapeRegexp(str)
	{
	if (!(isString(str)))
		{str = '' + 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 escapeHtml(str)
	{
	if (!(isString(str)))
		{str = '' + str;}
	var map = { "&": "&amp;", "<": "&lt;", ">": "&gt;", "\"": "&quot;", "'":  "&apos;" };
	return str.replace(/[&<>"']/g, function(m) { return map[m]; });
	}
function removeHtml(str)
	{
	if (!(isString(str)))
		{str = '' + str;}
	return str.replace(/<.*?>/g, '');
	}


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;
	}


function base64Encode(str) {
        var CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
        var out = "", i = 0, len = str.length, c1, c2, c3;
        while (i < len) {
            c1 = str.charCodeAt(i++) & 0xff;
            if (i == len) {
                out += CHARS.charAt(c1 >> 2);
                out += CHARS.charAt((c1 & 0x3) << 4);
                out += "==";
                break;
            }
            c2 = str.charCodeAt(i++);
            if (i == len) {
                out += CHARS.charAt(c1 >> 2);
                out += CHARS.charAt(((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4));
                out += CHARS.charAt((c2 & 0xF) << 2);
                out += "=";
                break;
            }
            c3 = str.charCodeAt(i++);
            out += CHARS.charAt(c1 >> 2);
            out += CHARS.charAt(((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4));
            out += CHARS.charAt(((c2 & 0xF) << 2) | ((c3 & 0xC0) >> 6));
            out += CHARS.charAt(c3 & 0x3F);
        }
        return out;
    }


// --- Web Services ---

// --- cooldown class ---
function classCooldown(opt)
{
//var that_timer = this;
var root = this;
this.name = 'classCooldown';
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;
	if (root.vars.el)
		{
		root.vars.el.innerHTML = root.vars.cooldown;
		}
	el = xapp.vars.el_list['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)
		{
		if (isFunction(root.receive))
			{
			root.receive(root.vars.type);
			}
		else	{
			alert('root.receive is not function for ' + root.name);
			}
		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.name   = isExist(opt.name) ? opt.name : root.name;
	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.data_per_second = '';
root.vars.dataJson = 0;
root.vars.dataJson_per_second = '';
root.vars.time_start = 0;
root.vars.time = 0;
root.vars.el = null;

this.add = function(n, str)
	{
	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)
xapp.log('data transfer ' + t + 's: '+ n + 'b ' + str)
	root.printDataTransfer();
	}
this.addJson = function(n)	// pro srovnani, kdyby byla data posilana pomoci json
	{
	root.vars.dataJson += n;
	root.vars.dataJson_per_second = Math.floor(root.vars.dataJson / root.vars.time);
	root.printDataTransfer();
	}
this.addJsonByArray = function(arr)	// pro srovnani, kdyby byla data posilana pomoci json
	{
	root.addJson(JSON.stringify(arr).length);
	}

this.addLoadedFileSize = function(url)	// URL.createObjectURL(blob)	// tady si nejsem jisty, zda to obrazek/soubor nestahuje duplicitne z url a nebo ho ziska z cache, takze mozna u smajliku tohle zakazat
	{
	fetch(url).then(resp => resp.blob())
	  .then(blob => {
		root.addJson(blob.size);
		root.add(blob.size, 'file ' + url);
	    });
	}

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()
	{
	if (isExist(root.vars.el))
		{
		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)+')'+
'| JSON: '+
root.formatBytes((root.vars.dataJson_per_second<root.vars.dataJson ? root.vars.dataJson_per_second : root.vars.dataJson) * 1, 2) + '/s ('+
root.formatBytes(root.vars.dataJson * 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);
}

var WS;

WS = {};
WS.vars = {};

WS.xhrError   = function (type, event, msg)
	{
xapp.log('xhr error:  ' + (isExist(event) ? ' '+event.target.src : '') + (isExist(msg)? ' '+msg : ''));
//	alert("Error loading " +  (isExist(event)? ' '+event.target.src : '') + (isExist(msg)? ' '+msg : ''));
	};

WS.xhrSuccess = null;

WS.open = function(prefix, xappReceive)
	{
//	WS.xhrError   = xapp.fn_error;
	var el_list, url, xhr, img, id;

	WS.xhrSuccess = xappReceive;

	id  = 0;
	img = new Image();
//	img.src = 'data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw=='; // transparent gif 1x1
	img.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAQAAACR313BAAAAE0lEQVR42mN8958BD2AclR5i0gDiAhzzPiVBowAAAABJRU5ErkJggg==)'; // png
	img.title = '*'+id+'*';
	img.alt   = id+'.gif';
	WS.vars.file_list = {};
	WS.vars.file_list.smiley = [];	// id={id:'id', img:new Image(), need:[]} // elements which need image for back render
	WS.vars.file_list.smiley[id] = {'id':id, 'need':[], 'img':img};
	el_list = {};
	el_list['data_reader']   = $('#'+prefix+'data_reader');	// pro iframe requesty
	el_list['data_transfer'] = $('#'+prefix+'data_transfer');
	WS.vars.el_list = el_list;
	WS.dataTransfer = new classDataTransfer({el: el_list['data_transfer']});
//	WS.vars.user_session = 'wh=~holy~c8e210bf279c92755986830950322a9e';
	WS.urlSessionCreate('holy', 'c8e210bf279c92755986830950322a9e');
	url = {};

	url['chat'] = 'http://localhost/js-xchat-mobile2/';
//	url['chat'] = 'https://mlich.zam.slu.cz/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'] + 'smileys/';
	url['room_talk'   ] = url['ws'] + 'room_talk.html'   + '?'+WS.vars.user_session+url['ws_opt'];
	url['room_message'] = url['ws'] + 'room_message.html'+ '?'+WS.vars.user_session+url['ws_opt'];
	url['room_enter'  ] = url['ws'] + 'room_enter.html'  + '?'+WS.vars.user_session+url['ws_opt'];
	url['room_info'   ] = url['ws'] + 'room_info.html'   + '?'+WS.vars.user_session+url['ws_opt'];
	url['room_users'  ] = url['ws'] + 'room_users.html'  + '?'+WS.vars.user_session+url['ws_opt'];
	url['chat_rooms'  ] = url['ws'] + 'chat_rooms.html'  + '?'+WS.vars.user_session+url['ws_opt'];
	url['chat_login'  ] = url['ws'] + 'chat_login.html'  + '?'+url['ws_opt'];
	url['user_smileys'] = url['ws'] + 'user_smileys.html'+ '?'+WS.vars.user_session+url['ws_opt'];
	url['smiley_downloader'] = '';
	WS.vars.url = url;
//alert(JSON.stringify(url))
	xhr = {};
	// xml request / iframe request (iframeXhrCreate() / requestByXmlCreate() / scriptTagXhrCreate() / objectTagXhrCreate())
	// !!! nastav si spravnou url['chat']
	xhr['room_talk']    = WS.requestByXmlCreate('room_talk'   , WS.xhrSuccess , WS.xhrError);
	xhr['room_message'] = WS.requestByXmlCreate('room_message', WS.xhrSuccess , WS.xhrError);
	xhr['user_smileys'] = WS.requestByXmlCreate('user_smileys', WS.xhrSuccess , WS.xhrError);
	xhr['room_users']   = WS.requestByXmlCreate('room_users'  , WS.xhrSuccess , WS.xhrError);
//	xhr['chat_rooms']   = WS.requestByXmlCreate('chat_rooms'  , WS.xhrSuccess , WS.xhrError);
	xhr['chat_login']   = WS.requestByXmlCreate('chat_login'  , WS.xhrSuccess , WS.xhrError);
	xhr['smiley_downloader'] = null;
/*
	xhr['room_talk']    = WS.requestByIframeCreate('room_talk'   , WS.xhrSuccess , WS.xhrError);
	xhr['room_message'] = WS.requestByIframeCreate('room_message', WS.xhrSuccess , WS.xhrError);
	xhr['user_smileys'] = WS.requestByIframeCreate('user_smileys', WS.xhrSuccess , WS.xhrError);
	xhr['room_users']   = WS.requestByIframeCreate('room_users'  , WS.xhrSuccess , WS.xhrError);
//	xhr['chat_rooms']   = WS.requestByIframeCreate('chat_rooms'  , WS.xhrSuccess , WS.xhrError);
	xhr['chat_login']   = WS.requestByIframeCreate('chat_login'  , WS.xhrSuccess , WS.xhrError);
	xhr['smiley_downloader'] = null;
*/
//	xhr['smiley_downloader']   = WS.requestByXmlForSmileyCreate('smiley_downloader'  , WS.smileyXhrSuccess, WS.xhrError);
/*
//	xhr['smiley_downloader']   = WS.requestByIframeCreate('smiley_downloader'  , WS.smileyXhrSuccess, xapp.fn_error);	// z nejakeho duvodu selze XML request (zkousim na localhost), proto iframe. Az se mi podari zjistit proc, tak to vymenim.
	xhr['room_users']   = WS.requestByIframeCreate('room_users'  , WS.xhrSuccess , WS.xhrError);
	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']   = xmlXhrCreate('chat_login'  , xapp.receiveScreen , xapp.fn_error);
*/
//	xhr['chat_rooms']  = xmlXhrCreate('chat_rooms' , xapp.receiveScreen , xapp.fn_error);
//	xhr['room_enter']  = xmlXhrCreate('room_enter' , xapp.receiveScreen , xapp.fn_error);
//	xhr['room_info']   = xmlXhrCreate('room_info' , xapp.receiveScreen , xapp.fn_error);
//	xhr['room_info'] = xmlXhrCreate('xr_session', xapp.receiveSession, fn_error);
	WS.vars.xhr = xhr;
	WS.smileyDataGet(0, null);
	}

WS.close = function()
	{
	WS.vars.user_session = null;
	WS.vars.url = null;
	WS.vars.xhr = null;
	}

WS.urlSessionCreate = function(nick, psw)
	{
	WS.vars.user_session = 'wh=~'+nick+'~'+psw;
	}

WS.send = function(type, url_params)
	{
	return WS.receiveByType(type, url_params);
	}

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

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

WS.receiveByType = function(type, url_params)
	{
	var new_xhr;
	if (type=='smiley_downloader')
	// u kazdeho smajliku musi byt samostatny request
		{
		new_xhr = WS.requestByXmlForSmileyCreate(type, WS.smileyXhrSuccess, WS.xhrError);
		}
	if (!WS.vars.url[type] || (!WS.vars.xhr[type] && !new_xhr))
		{
		alert('Neexistuje type "' + type+'" '+[new Boolean(WS.vars.url[type]), new Boolean(WS.vars.xhr[type]), new Boolean(new_xhr)]);
		return false;
		}
	return WS.receiveText(new_xhr ? new_xhr : WS.vars.xhr[type], WS.vars.url[type], url_params);	//, opt.fn_success, opt.fn_error
	}

/*
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;
	}


*/

WS.requestByIframeCreate = function(type, fn_success, fn_error)
	{
	var div, iframe, myXhrObj;
	myXhrObj = {};
	myXhrObj.url  = null;
	myXhrObj.type = type;
//	div = $('#xr_'+type);
	div    = WS.vars.el_list['data_reader'];
	iframe = document.createElement('IFRAME');
	iframe.onload  = function (event)
		{
		var doc, body, req_charset, doc_charset;
		doc     = event.target.contentWindow.document;
		content = doc.body.innerHTML;	// <body>content</body>
		fn_success(type, content, myXhrObj);
		}
	iframe.onerror = function (event) {fn_error(type, event);}
	div.appendChild(iframe);
	myXhrObj.open = function (method, url, asyn, user, psw)	// 'GET', url, false
		{
//xapp.log('xhr open iframe')
//alert('iframe xhrObj.open '+url)
//		if (typeof url=='undefined')
//			{alert[url, myXhrObj.type]}
		myXhrObj.url = url;
		iframe.src = url;	// GET
		}
	myXhrObj.send = function () {};
	return myXhrObj;
	}
//	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);


WS.requestByXmlXhrCreate = function() {
    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

WS.requestByXmlCreate = function (type, fn_success, fn_error)
	{
	var myXhrObj, req;
	myXhrObj = {};
	myXhrObj.url  = null;
	myXhrObj.type = type;
	req = WS.requestByXmlXhrCreate();
	if (req.overrideMimeType)
		{
		req.overrideMimeType('text\/plain; charset=utf-8');
		}

	req.onreadystatechange = function()
		{
//		var content, exception;
		if (req.readyState == 4)
			{
//			success = false;
//		        try	{
//				if (req.status == 200) 
//					{
//					WS.dataTransfer.add(req.responseText.length, type+' 200');	//xhr.getResponseHeader('Content-Length')
//					fn_success(type, req.responseText);
//					}
//				else 	{
//					fn_error(type, null, "Status error " + myXhrObj.url);	//fn_error();
//					}
//				}
//			catch (exception)	// exception or error
//				{
//				if (!exception.message && req.responseText)
//					{
//					WS.dataTransfer.add(req.responseText.length, type+' local');	//xhr.getResponseHeader('Content-Length')
//					fn_success(type, req.responseText);	// only localhost
//					}
//				else 	{
//					fn_error(type, null, "Server Error "+(exception.message ? exception.message : '') +' '+ myXhrObj.url);	//fn_error("Server Error")
//					}
//				}
			if (req.status == 200 || myXhrObj.url.match(/^[^/]*\/\/localhost/))
				{
				WS.dataTransfer.add(req.responseText.length, type + ' '+myXhrObj.url);	//xhr.getResponseHeader('Content-Length')
				fn_success(type, req.responseText, myXhrObj);	// only localhost
				}
			}
		} 
	myXhrObj.req  = req;
	myXhrObj.open = function (method, url, asyn, user, psw)	// 'GET', url, false
		{
//		if (typeof url=='undefined')
//			{alert[url, myXhrObj.type]}
//xapp.log('xhr open xml '+url)
		myXhrObj.url = url;
//		xhrObj.req.open(method, url, asyn);
		myXhrObj.req.open('POST', url, asyn, user, psw);
		}
	myXhrObj.send = function (params)
		{
		this.req.send(params?params:null);
		};
	return myXhrObj;
	}

WS.requestByXmlForSmileyCreate = function(type, fn_success, fn_error)	// cele tohle mam jen kvuli tomu, abych mohl do datatransfer pridat velikost obrazku a sledovat tak pocet prenesenych dat
	{
/*
	var xhrObj, req;
	req = new XMLHttpRequest();
	req.onreadystatechange = function()
		{
		var content;
//alert(req.readyState)
		if (req.readyState == 4)
			{
		        try	{
				if (req.status == 200) 
					{
					WS.dataTransfer.add(req.responseText.length);	//xhr.getResponseHeader('Content-Length')
					fn_success(type, req.responseText);
					}
				else 
					{
					fn_error(type, null, "Status error " + xhrObj.url);	//fn_error();
					}
				}
			catch (exception)	// exception or error
				{
				if (req.responseText)
					{
					WS.dataTransfer.add(req.responseText.length);	//xhr.getResponseHeader('Content-Length')
					fn_success(type, req.responseText);	// only localhost
					}
				else 	{
					fn_error(type, null, "Server Error "+exception.message + xhrObj.url);	//fn_error("Server Error")
					}
				}
			}
		} 
	xhrObj = {};
	xhrObj.req  = req;
	xhrObj.open = function (method, url, asyn, user, psw)	// 'GET', url, false
		{
		xhrObj.url = url;
		req.open('POST', url, asyn);
		//XHR binary charset opt by Marcus Granado 2006 [http://mgran.blogspot.com]
		req.overrideMimeType('text\/plain; charset=x-user-defined');
//		req.overrideMimeType('text\/plain; charset=utf-8');
		}
	xhrObj.send = function (params)
		{
		req.send(params?params:null);
		};
	return xhrObj;
*/

	var myXhrObj, req;
	myXhrObj = WS.requestByXmlCreate(type, fn_success, fn_error);
	req      = myXhrObj.req;
	myXhrObj.open = function (method, url, asyn, user, psw)	// 'GET', url, false
		{
//xapp.log('xhr open xml smiley '+url)
		myXhrObj.url = url;
		req.open('POST', url, asyn);
		//XHR binary charset opt by Marcus Granado 2006 [http://mgran.blogspot.com]
		req.overrideMimeType('text\/plain; charset=x-user-defined');
		}
	return myXhrObj;
	}

/*
WS.smileyDownload = function(id)
	{
	var file, path, url, img;
	file = id + '.gif';
	path = ''+id
	path = path.replace(/.*?(\d\d|\d)$/, '$1');	// uprava path pro smajliky, ktere maji id>99 (161->61)
	url  = WS.vars.url['img_smiley'] + path + '/' + file;

	reader = new FileReader();
//	reader.onload = function (event)
//		{
//		var img;
		img        = new Image();      
		img.onload = function(event)
			{
			WS.vars.files.smiley[id] = {'id':id, 'img':this}	//	var w = this.width; var h = this.height;
//var img = document.createElement('img'); 
//img.src = this.src;
//document.getElementsByTagName('body')[0].appendChild(img); 
			}
		img.src    = url;
//		img.src    = event.target.result;
//		}
//
//	reader.readAsDataURL(url);
//	reader.readAsDataURL(url);

	}
*/

WS.smileyDownload = function(id)
	{
	var file, path, url, img, type;
	file = id + '.gif';
	path = ''+id
	path = path.replace(/.*?(\d\d|\d)$/, '$1');	// uprava path pro smajliky, ktere maji id>99 (161->61)
	url  = WS.vars.url['img_smiley'] + path + '/' + file;
	url  = url + '#'+id;
	type = 'smiley_downloader';
	WS.vars.url[type] = url;
	return WS.receiveByType(type);
	}

WS.smileyXhrSuccess = function (type, binary_data, xhr)
	{
//alert(data);
	var img, base64_data;
	var id, i, i_end, item;
//var 		id       = WS.vars.url['smiley_downloader'].replace(/^.*?(\d+)$/,'$1');
//if (id==1)
//	{alert([id, JSON.stringify(binary_data)]);}
	img = new Image();      
//	img.crossOrigin = 'Anonymous';
//	img.onload = function(event)	// kdyz se pouzije src=base64, onload se nespousti!!!
//		{
//var img = document.createElement('img'); img.src = this.src; document.getElementsByTagName('body')[0].appendChild(img);	// test show image
//		}
//	base64_data = btoa(unescape(encodeURIComponent(binary_data)));	// for utf8 string
	base64_data = base64Encode(binary_data);
//alert(base64_data)
	img.src     = 'data:image/gif;base64,' + base64_data;
	id       = xhr.url.replace(/^.*?(\d+)$/,'$1');
//alert(id)
	item     = WS.vars.file_list.smiley[id];
	item.img = img;	//	var w = this.width; var h = this.height;
	// add src to all older smiley
/*
	i_end    = item.need.length;
//alert(i_end)
	for (i=0; i<i_end; ++i)
		{
		if (item.need[i] && item.need[i].nodeName==="IMG")
			{
			item.need[i].src   = this.src;
			item.need[i].title = '*'+id+'*';
			item.need[i].alt   = id+'.gif';
			item.need[i] = null;
			}
		}
*/
	return img.src;
	}

WS.smileyDataGet = function(id_smiley, el, bool)
	{
	var item, list;
	list = WS.vars.file_list.smiley;
//if (bool) alert(JSON.stringify([list[id_smiley]]))
	if (list[id_smiley])
		{
//alert(JSON.stringify(list[id_smiley]))
		item = list[id_smiley];
//if (bool) alert(JSON.stringify([list[id_smiley], isExist(item.img), isExist(item.img) && item.img.src]))
		if (isExist(item.img) && item.img.src)
			{
			return item.img.src;
			}
		if (isExist(el))
			{
			item.need[item.need.length] = el;
			}
		return false;
		}
	list[id_smiley] = {'id':id_smiley, 'need':[], 'xhr':null};
//alert(list[id_smiley].need)
	if (isExist(el))
		{
		list[id_smiley].need[list[id_smiley].need.length] = el;
		}
	if (!list[id_smiley].xhr)
		{
		list[id_smiley].xhr = WS.smileyDownload(id_smiley);
		}
	return false;
	}

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

WS.decode = function(content)
	{
	return JSON.parse(content);
	}

WS.decodeByContentType = 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_talk')	// html/text to array
		{
//alert(content)
		content.replace(/(.+?)<br[^>]*>/g, function(match, content0, offset, input_string)
			{
//alert(content0)
//			out[out.length] = content0;

			var row, bool_system, x;
			row = [];
			row[0] = content0.indexOf(' class="systemtext"')>=0 ? '1' : '0';	// system message? 
			bool_system = row[0] == '1';
//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] = bool_system	// 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] = bool_system
					? 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] = bool_system	// 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[05]!==content0)
//				{
				out[out.length] = row;
//				}

		        return "";
			});
//alert([content.length, JSON.stringify(out).length]);
WS.dataTransfer.addJsonByArray(out);
		return out;
		}
	else {if (type=='room_users')	// html/text to array
		{
		content.replace(/<p>(.+?)<\/p>/g, function(match, content0, offset, input_string)
			{
			var row;
			row = [];
			row[0] = content0.replace(/.*userPopup\('([^']*).*$/g, '$1');		// name
			if (row[0]!==content0)	// nepokracuj, kdyz selze reg. vyraz pro parsovani name
				{
				row[1] = content0.replace(/.* ([^"]*)\" onclick="userPopup.*/g, '$1');	// time
				row[2] = content0.indexOf('alt="M')>=0					// gender
						? 'm'
						: 'z';
				row[3] = content0.indexOf('alt="MC"')>=0 || content0.indexOf('alt="C"')>=0	// certifikovany
						? 'c'
						: '';
				row[4] = content0.indexOf('alt="star"')>=0	// star level
						? content0.replace(/^.*?\/star\/([^.]+?)\..*$/g, '$1')
						: '';
				out[out.length] = row;
				}
		        return "";
			});
//alert(out[0]);
//alert([content.length, JSON.stringify(out).length]);
WS.dataTransfer.addJsonByArray(out);
		return out;
		}
	else {if (type=='user_smileys')// html/json to array
		{
		if (content=='')
			{return false;}
		content = content.replace(/^.*?<body[^>]*>(.*)$/gm, '$1').replace('</body>', '');	// pro xml request z html stranky/iframe
WS.dataTransfer.addJson(content.length);
		return WS.decode(content);
		}
	else {if (type=='chat_login')// html/json to array
		{
		if (content=='')
			{return false;}
		content = content.replace(/^.*?<body[^>]*>(.*)$/gm, '$1').replace('</body>', '');	// pro xml request z html stranky/iframe
WS.dataTransfer.addJson(content.length);
		return WS.decode(content);
		}
		}}}
	return false;
	}



// ---



var xapp;
xapp = {};
xapp.vars = {};
xapp.WS   = null;

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.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 'user_smileys':
			i_end = content.length;
			smiley_list = {};
			str   = '';
			for (i=0; i<i_end; i++)
				{
				smiley_list[content[i][0]] = content[i];
//alert('con'+content[i][0])
				str += ""+'<span class="smiley" onclick="xapp.messageAdd(\'smiley\','+content[i][0]+')">'+xapp.smileyCreateImg(content[i][0])+'</span>';	// name
				}
//alert(JSON.stringify(smiles_list))
			xapp.vars.smiley_list = smiley_list;
//alert(str)
			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_talk':
			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" title="'+escapeHtml(content[i][1])+'"><span class="time">'+escapeHtml(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.smiley_list, id);
//					title = bool ? xapp.vars.smiley_list[id][1] : id;
//					file  = bool ? xapp.vars.smiley_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] = '';	// color
				content[i][4] = '';	// name2 TO
//alert([content[i][1], me, name2])
				str += "\n"+'<div class="msg '+(me==name ? 'sended' : (me==name2 ? 'receivedme' : 'received'))+'" title="'+escapeHtml(removeHtml(content[i][1]))+'">' + content[i].join(' ') + '</div>';
				}
			return str;
			break;
		default: break;
		}
	return false;
	}

xapp.send = function()
	{
	var cooldowner_list, msg, el, url_params;
	el  = xapp.vars.el_list['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_talk'].pause3s();
	url_params = xapp.encode(msg);
	url_params = 'msg='+escapeUrl(url_params);
	xapp.receive('room_message', url_params);
	el.focus();
	return false;
	}

xapp.wsReceive = function(type, content)
	{
//xapp.log('end download ' + type);
	switch (type)
		{
		case 'room_talk'   : return xapp.drawScreen(type, content); break;
		case 'room_users'  : return xapp.drawUsers(type, content); break;
		case 'user_smileys': 
WS.dataTransfer.addJson(content.length);
					return xapp.drawSmileys(type, content); break;
		case 'room_message': return xapp.receiveMsgSended(type, content); break;
		case 'chat_login'  : return xapp.drawUsers(type, content); break;
		default: return false; break;
		}
	return false;
	}

xapp.wsDownload = function(type)
	{
//xapp.log('start download ' + type);
	return WS.receiveByType(type);
	}

xapp.smileyTitleOrId = function(title, id)
	{
	return !isExist(title) && isExist(xapp.vars.smiley_list[id]) && isExist(xapp.vars.smiley_list[id][1]) ? xapp.vars.smiley_list[id][1] : '*'+id+'*';	// title or id
	}

xapp.smileyCreateImg = function(id)
	{
//throw new Error('smileyCreateImg '+id);
//console.warn('smileyCreateImg '+id);
	var title, data;
//	var file, id99;
//	file  = id;
//	file  = file + '.gif';
//	id99  = (''+id).replace(/.*?(\d\d|\d)$/, '$1');
//	url   = xapp.vars.url['img_smiley'] + id99 + '/' + file;
	data  = xapp.WS.smileyDataGet(id, null);
	if (data!==false)
		{
		title = xapp.smileyTitleOrId(null, id);
//alert([id, title, data])
		}
	else	{
		title = ''; // smileyUpdate checking title==''
		}
//+xapp.WS.smileyDataGet(0, null)+
//alert([id, '<img src="" alt="'+escapeHtml(id)+'" title="'+escapeHtml(title)+'">'])
	return '<img src="'+(data?data:'')+'" alt="'+escapeHtml(id+'.gif')+'" title="'+escapeHtml(title)+'">';
	}

/*
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;
		WS.dataTransfer.addLoadedFileSize(url, 'smiley '+id);
		}
	}
*/

xapp.smileyUpdate = function(el)
	{
	var data;
	if (!isExist(el.title) || isExist(el.title) && el.title=='')
		{
		id   = el.alt.replace(/\..*$/,'');
//alert([id, el.alt]);
		data = xapp.WS.smileyDataGet(id, null, true);
//alert([id, data])
		if (data!==false)
			{
			el.src   = data;
			el.title = xapp.smileyTitleOrId(id);
			}
		}
	}

xapp.smileysUpdate = function(type)
	{
	var i, i_end, list, el, id, data;
	el    = xapp.vars.el_list['user_smileys'];
	list  = el ? el.getElementsByTagName('IMG') : [];
	i_end = list.length;
	for (i=0; i<i_end; i++)
		{
		xapp.smileyUpdate(list[i]);
		}
	el    = xapp.vars.el_list['room_talk'];
	list  = el ? el.getElementsByTagName('IMG') : [];
	i_end = list.length;
	for (i=0; i<i_end; i++)
		{
		xapp.smileyUpdate(list[i]);
		}
	}

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_talk'].start();
	}


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_list['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.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
	if (isArray(list))
		{
//		alert([list, list.length])
		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_list['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.WS.decodeByContentType(type, content);
	str = arr!==false ? xapp.format(type, arr) : xapp.format('plain', content);
	if (str=='')
		{return;}
	if (isExist(xapp.vars.el_list[type]))
		{
		xapp.vars.el_list[type].innerHTML = str;
		}
	}


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

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

xapp.drawName = function(type, content)
	{
	if (isExist(type) && isExist(content))
		{
		xapp.vars.user_name = content;
		}
	if (isExist(xapp.vars.el_list[type]))
		{
		xapp.vars.el_list[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_list;
	root    = xapp;
	el_list = root.vars.el_list;
	root.classAdd(el_list['room_users']  , 'js_d-none');
	root.classAdd(el_list['user_smileys'], 'js_d-none');
	root.classAdd(el_list['chat_settings'],'js_d-none');
	}

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

xapp.tabsButtonsShow = function (active)
	{
	}

xapp.tabsChange = function (active)
	{
	var root, i, i_end, j, sett, icon_list, panel_list, el_list, icon_actived, icons_visible, panels_visible, active_id;
	root  = xapp;
	sett  = root.vars.tabs;
	icon_list  = sett.el_list['nav_tabs_icons'];
//alert(list.length)
	panel_list = sett.el_list['nav_tabs_panels'];
	if (icon_list.length!=panel_list.length || icon_list.length==0 || panel_list.length==0)
		{
		alert('Chyba. ikony a panely nemaji shodny pocet nebo maji nulovy pocet, ' + icon_list.length +'/' + panel_list.length);
		}
	active_id        = sett.cmd[active] ? sett.cmd[active] : sett.cmd['room_talk'];
	if (active=='user_smileys' || active=='room_refresh' || active=='room_users')
		{
		active_id = sett.cmd['room_talk'];
		}
	else	{
		active_id = sett.cmd[active] ? sett.cmd[active] : sett.cmd['room_talk'];
//alert(active)
		}
	sett.icon_actived = active_id;
	icon_actived      = active_id;
	icons_visible  = sett.icons_visible;
	panels_visible = sett.panels_visible;
	i_end = icon_list.length;
	for (i=0; i<i_end; i++)		// LI(A) hide, A noactive, DIV hide (clear all)
		{
		root.classAdd(icon_list[i].parentNode, 'js_d-none');
		root.classRemove(icon_list[i], 'js_active');
		root.classAdd(panel_list[i], 'js_d-none');
		} 
	i_end = icons_visible.length;
	for (i=0; i<i_end; i++)		// LI(A) show (show icon)
		{
		j = icons_visible[i];
		if (icon_list[j])
			{
			root.classRemove(icon_list[j].parentNode, 'js_d-none');
			}
		} 
		j = icon_actived;	// A.active, DIV show (active icon + open tab panel)
		if (icon_list[j])
			{
			root.classAdd(icon_list[j], 'js_active');
			root.classRemove(panel_list[j], 'js_d-none');
			}
	// panely trvale visible
	i_end = panels_visible.length;
	for (i=0; i<i_end; i++)		// div show permanent (open permanent panel)
		{
		j = panels_visible[i];
		if (panel_list[j])
			{
			root.classRemove(panel_list[j], 'js_d-none');
			}
		} 
//	j = panel_visible[i];
//	if (list[j])
//		{
//		root.classAdd(list[j], 'active');
//		}
	// toggle subpanel in  'room_talk'
	if (active=='user_smileys' || active=='room_refresh' || active=='room_users')
		{
		el_list = root.vars.el_list;
		if (active=='room_users')
			{
			root.classToggle(el_list[active].parentNode.parentNode, 'js_room_users_actived');
			return;
			}
		root.classToggle(el_list[active]  , 'js_d-none');
		}

	}

xapp.log = function(str)
	{
//alert(JSON.stringify(xapp.vars.el_list))
	var el = xapp.vars.el_list['log'];
	if (!el) {return;}
	el.innerHTML = '<div style="font-size:60%; line-height:0.6rem;">'+str+'</div>' + el.innerHTML;
	}

xapp.cmd = function(cmd, options)
	{
	var active;
	switch (cmd)
		{
		case 'toggle_tabs':
			active = options.nodeName && options.nodeName=='A' ? options.href : (typeof options=='string' ? options : '');
			active = active.replace(/^.*#/,'');	// #text -> text, http://localhost...#text -> text
			xapp.tabsChange(active);
			break;
		default: break;
		}
	}

xapp.init = function()
	{
	var xhr, el_list, url, timer_list, type, chat, id, prefix;

	prefix = 'x_';

	xapp.WS = WS;
	xapp.WS.open(prefix, xapp.wsReceive);

	xapp.vars.user_list = [];
	xapp.vars.smiley_list = {};
	xapp.vars.xhr_list = {};
	xapp.vars.el_prefix  = prefix;
	xapp.vars.el_list  = {};
	xapp.vars.timer_list = {};
	xapp.vars.new_msg = {'type':1, 'whisper':false, 'from': xapp.vars.user_name, 'to':'', 'text':''};
	chat = {};
	chat.whisper = false;
	chat.user = {'name':'holy'};
	chat.msg_time_sended = xapp.getTime();	// afk, last message
	chat.cooldown_list = {};
	chat.cooldown_list['room_talk']  = {0: 17, 2: 30, 5: 60, 10: 120, 15: 180};	// dynamicky refresh podle afk
	chat.cooldown_list['room_users'] = {0: 34, 2: 60, 5: 60, 10: 120, 15: 180};	// dynamicky refresh podle afk
	chat.cooldown_list['smileys_update'] = {0: 3, 2: 6, 5: 60};
	xapp.vars.chat = chat;

	el_list   = [];
	type = 'nav_tabs_icons';  el_list[type] = $$('#'+prefix+type+'>ul>li>a');
	type = 'nav_tabs_panels'; el_list[type] = $$('#'+prefix+type+'>div.panel');
	xapp.vars.tabs = {
		'el_list': el_list,
		'icons_visible' : [1, 2, 3, 6, 8],
		'icon_actived'  : 1,
		'panels_visible': [0],
		'cmd': {
			'chat_status'  : 0,
			'room_talk'    : 1,
			'room_users'   : -1,
			'user_smileys' : -1,
			'chat_rooms'   : 4,
			'chat_settings': 5,
			'chat_nav'     : 6,
			'user_signin'  : 7,
			'user_signout' : 8
			}
		};
	xapp.cmd('toggle_tabs', 'room_talk');


	el_list = {};
	el_list['chat']         = $('#'+prefix+'chat');
	el_list['message_text'] = $('#'+prefix+'message_text');
	el_list['data_reader']  = $('#'+prefix+'data_reader');
	el_list['name']         = $('#'+prefix+'message_to');

	

//	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_talk'    ; el_list[type] = $('#'+prefix+type+'_subpanel'); el_list[type+'_cooldown'] = $('#'+prefix+type+'_cooldown');
	type = 'room_message' ; el_list[type] = $('#'+prefix+type+'_subpanel');
	type = 'room_users'   ; el_list[type] = $('#'+prefix+type+'_subpanel'); el_list[type+'_cooldown'] = $('#'+prefix+type+'_cooldown');
	type = 'room_refresh' ; el_list[type] = $('#'+prefix+type+'_subpanel');
	type = 'user_smileys' ; el_list[type] = $('#'+prefix+type+'_subpanel');
	type = 'chat_rooms'   ; el_list[type] = $('#'+prefix+type+'_panel');
	type = 'chat_settings'; el_list[type] = $('#'+prefix+type+'_panel');
	type = 'user_signin'  ; el_list[type] = $('#'+prefix+type+'_panel');
	type = 'smileys_update'   ; el_list[type+'_cooldown'] = $('#'+prefix+type+'_cooldown');
	type = 'log'; el_list[type] = $('#'+prefix+type);
	xapp.vars.el_list = el_list;
//alert(JSON.stringify(el_list))

	cooldowner_list = {};
	type = 'room_users';
	cooldowner_list[type] = new classCooldown({
		name: type,
		func: {
			receive: xapp.wsDownload
			},
		type: type,
		el  : el_list[type+'_cooldown'],
		cooldown_list: xapp.vars.chat.cooldown_list[type]
		});
	type = 'room_talk';
	cooldowner_list[type] = new classCooldown({
		name: type,
		func: {
			receive: xapp.wsDownload
			},
		type: type,
		el  : el_list[type+'_cooldown'],
		cooldown_list: xapp.vars.chat.cooldown_list[type]
		});
	type = 'smileys_update';
	cooldowner_list[type] = new classCooldown({
		name: type,
		func: {
			receive: xapp.smileysUpdate
			},
		type: type,
		el  : el_list[type+'_cooldown'],
		cooldown_list: xapp.vars.chat.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);
// data transfer html page
xapp.WS.dataTransfer.addJson(document.getElementsByTagName('HTML')[0].outerHTML.length);
	xapp.WS.dataTransfer.add(document.getElementsByTagName('HTML')[0].outerHTML.length, 'base page');

//	xapp.dataTransfer.add(xapp.getLoadedFileSize(location.href));
//	xapp.dataTransfer.add(xapp.getLoadedFileSize(url['chat'] + 'convert_codepage.js'));	// pridano do onload
//	xapp.dataTransfer.add(xapp.getLoadedFileSize(url['chat'] + 'x_chat_app.js'));

 //	el['message_text'].focus();

	xapp.wsDownload('chat_login');
	xapp.wsDownload('room_users');
	xapp.wsDownload('room_talk');
	xapp.wsDownload('user_smileys');
	//xapp.btnTabShow('user_smileys');
//	xapp.btnTabShow('');
//WS.smileyDownload('161');
//WS.smileyDataGet(161, $('#sm_test'));	// test stahovani smajliku pomoci xml requestu
	};

// 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.vars.msg_;
//	xapp.vars.msg_
//	xapp.vars.msg_time_sended = xapp.getTime();	// afk, last message
//	xapp.vars.msg_text  = '';
//	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'];
l	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 
/*
	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;
*/

