/**
 * A rootImgUrl változó a képek rootja. A c6.js használata előtt be kell állítani.
 */
if(typeof rootImgUrl == 'undefined') {
	window.alert("A 'rootImgUrl' változó nincs beállítva (webx.js)");
}

var webx = {
	online: true,
	idWidgetSpin: 0,
	idPanelSpin: 0,
	drag: { 
		x0: -1,
		y0: -1,
		disabled: false,
		virt: null,
		widget: null,
		tab: null
	},
	setup: {
		animVirt: (getCookie('wxc_av', 0) != 0),
		opacityDrag: (getCookie('wxc_od', is.ie ? 0 : 1) != 0)
	},
	exhibition: null,
	flContainer: null,
	tabOptions: null,
	globalOptions: null,
	console: null,
	buttons: {
		wgEdit: new WebxButton("edit", "Beállítások", "btn", webxEdit, "%img%/webx/webx-wg-edit.gif", null, null, null, webxHeadButtonOver, webxHeadButtonOut),
		wgMin: new WebxButton("min", "Kicsinyítés / Nagyítás", "btn", webxMinMax, "%img%/webx/webx-wg-min.gif", null, null, null, webxHeadButtonOver, webxHeadButtonOut),
		wgClose: new WebxButton("close", "Bezárás", "btn", webxClose, "%img%/webx/webx-wg-close.gif", null, null, null, webxHeadButtonOver, webxHeadButtonOut),
		wgRefresh: new WebxButton("refresh", "Frissítés", "btn", webxRefresh, "%img%/webx/webx-wg-refresh.gif", null, null, null, webxHeadButtonOver, webxHeadButtonOut),

		tabClose: new WebxButton("close", "Panel bezárása", "close", function() { webx.closePanel(webx.searchTab(this).webxTab.id); }, "%img%/webx/webx-tab-close.gif"),
		tabOptions: new WebxButton("options", "A panel beállításai", "options", webxTabOptionsOpenClose, "%img%/webx/webx-tab-options.gif"),

		extrClose: new WebxButton("close", "Bezárás", null, null, "%img%/webx/webx-tab-close.gif"),

		exhClose: new WebxButton("close", "Bezárás", "wx_exh_btn", function() { webx.closeExhibition(); }, "%img%/webx/webx-tab-close.gif"),

		tabOptClose: new WebxButton("close", "Bezárás", null, function() { webx._tabEditClose(); }, "%img%/webx/webx-tab-close.gif"),

		globalOptClose: new WebxButton("close", "Bezárás", null, function() { webx._globalOptionsClose(); }, "%img%/webx/webx-tab-close.gif"),

		console: new WebxButton("console", "Konzol", "wx_console_btn", webxOpenConsole, "%img%/webx/spacer.gif", "%img%/webx/webx-console-over.gif"),

		comOpenClose: new WebxButton("openclose", "Kinyitás / Bezárás", null, null, "%img%/webx/wcom-openclose.gif"),
		comDelete: new WebxButton("delete", "Törlés", null, null, "%img%/webx/wcom-delete.gif"),
		comEdit: new WebxButton("edit", "Szerkesztés", null, null, "%img%/webx/wcom-edit.gif"),
		comRedcross: new WebxButton("redcross", "Új...", null, null, "%img%/webx/wcom-redcross.gif"),
		comGoUp: new WebxButton("goup", "Föl", null, null, "%img%/webx/wcom-goup.gif"),
		comGoDown: new WebxButton("godown", "Le", null, null, "%img%/webx/wcom-godown.gif")
	},
	urls: {
/* appRoot - Az application root. Bizonyos linkekben a következő regexp kifejezés: /^%root%/ lecserélődik erre. Lásd.: webx.urlConsolidator() */
		appRoot: "/c6-java",
/* modulesRoot - A modulok root-ja. A /^%modules%/ regexp lecserélődik erre, ugyanazokon a helyeken, ahol az ''appRoot'' is érvényesül. */
		modulesRoot: "/webx/moduledir",
		desktop: "%root%/webx.da?method=loadUser",
		moduledir: "%modules%/root.json",
		widgetSave: "%root%/webx.da?method=saveWidget",
		widgetDelete: "%root%/webx.da?method=deleteWidget",
		widgetUpdate: "%root%/webx.da?method=updateWidgets",
		panelSave: "%root%/webx.da?method=savePanel",
		panelDelete: "%root%/webx.da?method=deletePanel",
		extractRSS: "%root%/wxhelper.da?method=findRSS",
		rss2json: "%root%/wxhelper.da?method=getRSS&url="
	},
	desktopId: "desktop",
	titleId: "webx_title",
	moduleDirId: "moduledir",
	tabsId: "tabs",
	newTabId: "newtab",
	widgetIdPrefix: "widget",
	panelIdPrefix: "panel",
	tabIdPrefix: "tab",
	tabOptionsId: "taboptions",
//	rssExtractorId: "newrss",

	init: function() {
		this.console = document.getElementById("wxconsole");
		if(window.console) wxlog.firebug = true;

		this.initDesktop();
		this.initModuleDir();

		document.body.appendChild(this.flContainer = webxJsonML([ "div", { id: "flcontainer" } ]));
		document.body.appendChild(this.buttons.console.create());
	},

	/**
	 * Néhány kulcsszót lecserél az input szövegben. 
	 * A következő helyeken cserélődik kötelezően: modulkönyvtárak (moduledir) URL-je, widgetek content és editor URL-jei és widget, module dir ikonok URL-jei.
	 * 
	 * %root%, %modules% <- lásd webx.urls
	 * %img%  ez pedig a rootImgUrl globális változóra cserélődik le.
	 */
	urlConsolidator: function(url) {
		if(!url) return "";
		return url.replace(/^%root%/, this.urls.appRoot).replace(/^%modules%/, this.urls.modulesRoot).replace(/^%img%/, rootImgUrl);
	},

	_statusCheck: function() {

	},

	_periodic: function() {
		setTimeout("webx._periodic()", 1000);
	},

	createWidget: function(wdescr, isFloat) {
		// Param init
//		wxlog.log("wdescr0: " + wdescr.toJSONString());
		wdescr = wdescr.clone(true);
//		wxlog.log("wdescr1: " + wdescr.toJSONString());
		var dirty = false;
		if(!wdescr.params) wdescr.params = new Object();
		with(wdescr) {
			if(!params.closeable) params.closeable = true;
			if(!params.refreshable) params.refreshable = false;
			if(!params.fastClose) params.fastClose = false;
			if(!params.look) params.look = 'wlook8';
		}
		if(!wdescr.id) {
			wdescr.id = ++this.idWidgetSpin;
			dirty = true;
		} else if(wdescr.id > this.idWidgetSpin) {
			this.idWidgetSpin = wdescr.id;
		}

		var divw = document.createElement("DIV");
		divw.className = isFloat ? "wx_flwidget" : "wx_widget wx_" + wdescr.params.look;
		divw.id = this.widgetIdPrefix + wdescr.id;
		divw.webxWidget = wdescr;
		divw.webxManager = null;
		divw.webxSaveable = false;

		var hd = this._createHead(divw);
		divw.appendChild(hd);
		divw.webxHead = hd;

		if(wdescr.editor) {
			var dive = document.createElement("DIV");
			dive.className = "wx_weditor";
			dive.innerHTML = "Loading...";
			divw.webxEditor = dive;
			divw.appendChild(dive);
		} else {
			divw.webxEditor = null;
		}

		var divp = document.createElement("DIV");
		divp.className = "wx_wpane";
		divp.innerHTML = "Loading...";
		divw.webxPane = divp;
		divw.appendChild(divp);
		divw.webxDirty = dirty;

		this.loadWidget(divw);

		if(isFloat) {
			var z = 10;
			for(var w0 = this.flContainer.firstChild; w0 != null; w0 = w0.nextSibling) {
				var z1 = new Number(w0.style.zIndex);
				if(z1 >= z) z = z1 + 1;
			}
			divw.style.zIndex = z;
			this.flContainer.appendChild(divw);
		}

		return divw;
	},

	loadWidget: function(widget) {
		var wdescr = widget.webxWidget;
		var cr = null;
		var er = null;
		var cdata = null;
		var cfinished = false;
		var edata = null;
		var efinished = false;

		if(widget.webxManager != null && !widget.webxManager.refresh) {
			// bug
			wxlog.log("Frissítheő widget, frissítést nem támogató managerrel!");
			return;
		}

		function fin() {
//			wxlog.log("fin: " + cfinished + ' - ' + efinished + " ('" + wdescr.title + "')");
			if(cfinished && efinished) {
				if(widget.webxManager != null) {
					widget.webxManager.refresh(cdata);
				} else {
					try {
						eval("var m=new " + wdescr.type + "(widget,cdata,edata)");
					} catch(e) {
						if(is.ie) {
							wxlog.error("Widget finish error ('" + wdescr.title + "'): " + (e.number & 0xFFFF) + " / " + e.description);
						} else {
							wxlog.error("Widget finish error ('" + wdescr.title + "'): " + e);
							wxlog.dir(e);
							throw e;
						}
					}
					widget.webxManager = m;
				}
				cfinished = efinished = false; // Only ONE shot!
			}
		}

		function response(r, type) {
			if(type == "application/json") {
				eval("var d=" + r.responseText);
				return d;
			}
			return r.responseText;
		}

		try {
			if(wdescr.content.type != "empty") {
				cr = new XMLHttpRequest();
				var url = this.urlConsolidator(wdescr.content.ref);
				cr.open("GET", url, true);
				wxlog.log("loading: " + url);
				cr.onreadystatechange = function() {
//					wxlog.log("loading: " + cr.readyState);
					if(cr.readyState == 4) {
						wxlog.log("loaded: " + cr.status);
						if(cr.status == 200 || cr.status == 0 /* local */) {
							cdata = response(cr, wdescr.content.type);
						} else {
							wxlog.error("http error (content): " + cr.status + ', url: ' + url);
						}
						cfinished = true;
						fin();
					}
				}
				cr.send(null);
			} else {
				cfinished = true;
			}

			if(widget.webxManager == null && wdescr.editor && wdescr.editor.type != "empty") {
				er = new XMLHttpRequest();
				var url = this.urlConsolidator(wdescr.editor.ref);
				er.open("GET", url, true);
				wxlog.error("loading editor: " + url);
				er.onreadystatechange = function() {
//					wxlog.log("loading: " + er.readyState);
					if(er.readyState == 4) {
						wxlog.log("loaded: " + er.status);
						if(er.status == 200 || er.status == 0 /* local */) {
							edata = response(er, wdescr.editor.type);
						} else {
							wxlog.error("http error (editor): " + er.status);
						}
						efinished = true;
						fin();
					}
				}
				er.send(null);
			} else {
				efinished = true;
			}
		} catch(e) {
			wxlog.dir(e);
			wxlog.error("error: " + e);
		}

		fin();
	},

	saveWidget: function(widget, exceptDirty) {
		if(this.online && widget.webxSaveable && (exceptDirty || widget.webxDirty)) {
			wxlog.log("save... ");
			try {
				var sr = new XMLHttpRequest();
				var url = this.urlConsolidator(this.urls.widgetSave);
				sr.open("POST", url, true);
				sr.setRequestHeader("Content-type", "application/json;charset=utf-8");
				sr.onreadystatechange = function() {
//					wxlog.log("saving: " + sr.readyState);
					if(sr.readyState == 4) {
						wxlog.log("saved: " + sr.status);
						if(sr.status == 200 || sr.status == 0 /* local */) {
							wxlog.log("widget saved: " + sr.responseText);
							widget.webxDirty = false;
						} else {
							wxlog.error("http error (widget save): " + sr.status);
						}
					}
				}

				var p = this.searchColumn(widget);
				var d = {
					panelId: p.panel.webxPanel.id,
					columnIndex: p.columnIndex,
					index: widget.webxIndex,
					descriptor: widget.webxWidget
				};
				var post = d.toJSONString();
				wxlog.debug("saving widget: " + post);
				sr.send(post);
			} catch(e) {
				wxlog.dir(e);
				wxlog.error("widget save error: " + e);
			}
		}
	},

	deleteWidget: function(widget) {
		var fl = this.isFloatWidget(widget);

		widget.parentNode.removeChild(widget);

		// Mentsük el a változást.
		if(this.online && !fl) {
			wxlog.log("save... ");
			try {
				var sr = new XMLHttpRequest();
				var url = this.urlConsolidator(this.urls.widgetDelete + "&id=" + widget.webxWidget.id);
				sr.open("GET", url, true);
				sr.onreadystatechange = function() {
//					wxlog.log("loading: " + sr.readyState);
					if(sr.readyState == 4) {
						wxlog.log("loaded: " + sr.status);
						if(sr.status == 200 || sr.status == 0 /* local */) {
							wxlog.log("widget deleted: " + sr.responseText);
						} else {
							wxlog.error("http error (widget delete): " + sr.status);
						}
					}
				}

				sr.send(null);
			} catch(e) {
				wxlog.dir(e);
				wxlog.error("widget delete error: " + e);
			}
		}
	},

	/**
	 * Be: colObj1, colObj2, ...
	 */
	saveColumnOrders: function() {
		var cmd = new Array();
		for(var i = 0; i < arguments.length; i++) {
			var pan = arguments[i].panel;
			var cidx = arguments[i].columnIndex;
			var idx = 0;
			for(var w = pan.webxColumns[cidx].firstChild; w != null; w = w.nextSibling) {
				if(w.webxWidget) {
					if(w.webxIndex != idx) {
						w.webxIndex = idx;
						cmd[cmd.length] = {
							id: w.webxWidget.id,
							panelId: pan.webxPanel.id,
							columnIndex: cidx,
							index: idx
						};
					}
					idx++;
				}
			}
		}

		if(this.online && cmd.length != 0) {
			wxlog.log("save... ");
			try {
				var sr = new XMLHttpRequest();
				var url = this.urlConsolidator(this.urls.widgetUpdate);
				sr.open("POST", url, true);
				sr.onreadystatechange = function() {
//					wxlog.log("saving: " + sr.readyState);
					if(sr.readyState == 4) {
						wxlog.log("saved: " + sr.status);
						if(sr.status == 200 || sr.status == 0 /* local */) {
							wxlog.log("widgets order saved: " + sr.responseText);
						} else {
							wxlog.error("http error (widgets save): " + sr.status);
						}
					}
				}

				var post = cmd.toJSONString();
				wxlog.log("saving widgets: " + post);
				sr.send(post);
			} catch(e) {
				wxlog.dir(e);
				wxlog.error("widget order saving error: " + e);
			}
		}
	},

	addWidgetToPanel: function(widget) {
		var p = this.getActivePanel();
		var col = p.webxColumns[0];

		var wLast = col.lastChild;
		while(wLast != null && !wLast.webxWidget) {
			wLast = wLast.previousSibling;
		}

		widget.webxIndex = (wLast == null) ? 0 : wLast.webxIndex + 1;
		widget.webxDirty = true;
		widget.webxSaveable = true;

		col.appendChild(widget);
		this.saveWidget(widget);
	},

	_createHead: function(widget) {
		var wdescr = widget.webxWidget;
		var divh = document.createElement("DIV");
		divh.className = 'wx_whead';
		divh.onmousedown = webxDragStart;
//		CaptureEvent(divh, "mousedown", webxDragStart, true);

		if(wdescr.params.closeable) {
			var bc = this.buttons.wgClose.create();
			divh.appendChild(bc);
			var bm = this.buttons.wgMin.create()
			divh.appendChild(bm);
		}
		if(wdescr.editor) {
			var be = this.buttons.wgEdit.create();
			divh.appendChild(be);
		}
		if(wdescr.params.refreshable) {
			var br = this.buttons.wgRefresh.create();
			divh.appendChild(br);
		}

		var imgi = document.createElement("IMG");
		var im = this.urlConsolidator(wdescr.icon);
		imgi.src = im == "" ? rootImgUrl + "/spacer.gif" : im;
		imgi.className = "icon";
		divh.appendChild(imgi);
		divh.webxIcon = imgi;

		var tit = this._createTitle(widget);
		divh.appendChild(tit);
		divh.webxTitle = tit;

		return divh;
	},

	_createTitle: function(widget) {
		var wdescr = widget.webxWidget;
		var tit;
		var s = wdescr.title;
		if(wdescr.titleLink) {
			tit = document.createElement("A");
			tit.href = wdescr.titleLink;
			// Hogy ne lhessen dreggelni a widgetet.
			tit.onmouseover = webxHeadButtonOver;
			tit.onmouseout = webxHeadButtonOut;
		} else {
			tit = document.createElement("SPAN");
		}
		if(wdescr.title2) s += ' <span>' + wdescr.title2 + '</span>';
		tit.innerHTML = s;
		tit.className = "title";
		return tit;
	},

	updateTitle: function(widget) {
		var tit = this._createTitle(widget);
		widget.webxHead.replaceChild(tit, widget.webxHead.webxTitle);
		widget.webxHead.webxTitle = tit;
		this.saveWidget(widget);
	},

	updateIcon: function(widget) {
		var im = this.urlConsolidator(widget.webxWidget.icon);
		widget.webxHead.webxIcon.src = im == "" ? rootImgUrl + "/spacer.gif" : im;
		this.saveWidget(widget);
	},

	setIcon: function(widget, icon) {
		if(!icon) icon = null;
		if(widget.webxWidget.icon != icon) {
			widget.webxWidget.icon = icon;
			widget.webxDirty = true;
			this.updateIcon(widget);
		}
	},

	setTitle: function(widget, title, titleLink, title2) {
		var d = false;
		if(widget.webxWidget.title != title) {
			widget.webxWidget.title = title;
			d = true;
		}
		if(titleLink) {
			if(widget.webxWidget.titleLink != titleLink) {
				widget.webxWidget.titleLink = titleLink;
				d = true;
			}
		} else if(widget.webxWidget.titleLink) {
			delete widget.webxWidget.titleLink;
			d = true;
		}
		if(title2) {
			if(widget.webxWidget.title2 != title2) {
				widget.webxWidget.title2 = title2;
				d = true;
			}
		}
		else if(widget.webxWidget.title2) {
			delete widget.webxWidget.title2;
			d = true;
		}
		widget.webxDirty = d;
		if(d) this.updateTitle(widget);
	},

	setWidgetMinimized: function(widget, isMin) {
		var btn = webx.searchWgHeadButton(widget, "min");
		if(btn) {
			var look = widget.webxWidget.params.look;
			var fl = this.isFloatWidget(widget);
			widget.className = btn.webxSelect(isMin) ? (fl ? 'wx_flwidgetoff' : 'wx_widgetoff wx_' + look) : (fl ? 'wx_flwidget' : 'wx_widget wx_' + look);
		}
	},

	setWidgetLookAndFeel: function(widget, look) {
		var btn = webx.searchWgHeadButton(widget, "min");
		if(btn) {
			widget.webxWidget.params.look = look;
			var fl = this.isFloatWidget(widget);
			widget.className = btn.webxSelected ? (fl ? 'wx_flwidgetoff' : 'wx_widgetoff wx_' + look) : (fl ? 'wx_flwidget' : 'wx_widget wx_' + look);
			widget.webxDirty = true;
			this.saveWidget(widget);
		}
	},

	savePanel: function(panel, exceptDirty) {
		if(this.online && (exceptDirty || panel.webxDirty)) {
			wxlog.log("save panel... ");
			try {
				var sr = new XMLHttpRequest();
				var url = this.urlConsolidator(this.urls.panelSave);
				sr.open("POST", url, true);
				sr.setRequestHeader("Content-type", "application/json;charset=utf-8");
				sr.onreadystatechange = function() {
//					wxlog.log("saving: " + sr.readyState);
					if(sr.readyState == 4) {
						wxlog.log("loaded: " + sr.status);
						if(sr.status == 200 || sr.status == 0 /* local */) {
							wxlog.log("panel saved: " + sr.responseText);
							panel.webxDirty = false;
						} else {
							wxlog.error("http error (panel save): " + sr.status);
						}
					}
				}

				var post = panel.webxPanel.toJSONString();
				wxlog.log("saving panel: " + post);
				sr.send(post);
			} catch(e) {
				wxlog.dir(e);
				wxlog.error("panel save error: " + e);
			}
		}
	},

	_createTab: function(pelement) {
		var tdescr = pelement.webxPanel;
		var tab = [ "li", { "class": "tab", id: this.tabIdPrefix + tdescr.id, webxTab: { id: tdescr.id, panel: pelement } },
			[ "u" ],
			[ "a", { element: null, href: 'javascript:nop();', onclick: function() { webx.showPanel(divt.webxTab.id); } }, tdescr.name ],
			[ "div",
				[ "webx:button", { "webx:ref": "tabClose" } ],
				[ "webx:button", { "webx:ref": "tabOptions" } ]
			],
			[ "s" ]
		];

		var divt = webxJsonML(tab);
		divt.webxTabTitle = tab[3][1].element;
		delete tab;
		delete tdescr;
		return divt;
	},

	setPanelTitle: function(panel, t) {
		t = Sarissa.escape(t);
		if(panel.webxPanel.name != t) {
			panel.webxPanel.name = t;
			document.getElementById(this.tabIdPrefix + panel.webxPanel.id).webxTabTitle.innerHTML = t;
			panel.webxDirty = true;
		}
		this.savePanel(panel);
	},

	_createColumn: function(panel, idx) {
		var td = document.createElement("TD");
		td.className = "wx_panelcolumn";
		td.webxColumnIdx = idx;
		panel.webxColumnParent.appendChild(td);
		panel.webxColumns[idx] = td;
		return td;
	},

	_setupColumnWidth: function(panel) {
		with(panel) {
			var w = Math.floor(100 / webxPanel.columnCount) + "%";

			for(var i = 0; i < webxPanel.columnCount; i++) {
				webxColumns[i].style.width = w;
			}
		}
	},

	setColumnsCount: function(panel, cnt) {
		var c0 = panel.webxPanel.columnCount;
		if(c0 == cnt) return false;

		if(c0 > cnt) {
			function reord(chk) {
				var td0 = panel.webxColumns[0];
				for(var i = cnt; i < c0; i++) {
					var td = panel.webxColumns[i];

					var e1 = null;
					for(var e = td.firstChild; e != null; e = e1) {
						e1 = e.nextSibling;
						if(e.webxWidget) {
							if(chk) return true;
							e.webxIndex = -1;
							td0.appendChild(e);
						}
					}

					if(!chk) {
						td.parentNode.removeChild(td);
						delete panel.webxColumns[i];
					}
				}
				return false;
			}

			var ro = reord(true);
			if(ro && !window.confirm("A kért oszlopok száma kevesebb, mint amennyi oszlop most a panelon van. A kitörlésre kerülő oszlopok tartalma az első oszlopba fog átkerülni.\nBiztosan szeretnéd a műveletet végrehajtani?")) {
				return false;
			}
			panel.webxDirty = true;
			reord(false);
			if(ro) this.saveColumnOrders({ panel: panel, columnIndex: 0 });
		} else {
			panel.webxDirty = true;
			for(var i = c0; i < cnt; i++) {
				this._createColumn(panel, i);
			}
		}
		
		panel.webxPanel.columnCount = cnt;
		this._setupColumnWidth(panel);

		this.savePanel(panel);

		return true;
	},

	createPanel: function(tdescr, columns, show) {
		var dirty = false;
		if(!tdescr) {
			var id = ++this.idPanelSpin;
			var n = "Új panel " + id;
			tdescr = { name: n, id: id, columnCount: 3 };
			dirty = true;
		}
		if(!tdescr.id) {
			tdescr.id = ++this.idPanelSpin;
			dirty = true;
		} else if(tdescr.id > this.idPanelSpin) {
			this.idPanelSpin = tdescr.id;
		}
		if(!columns) columns = new Array();

		var tab = document.createElement("TABLE");
		tab.webxPanel = tdescr;
		tab.webxColumns = new Array();
		tab.id = this.panelIdPrefix + tdescr.id;
		tab.className = "wx_paneloff";
		tab.webxDirty = dirty;

		var tb = document.createElement("TBODY");
		tab.appendChild(tb);
		var tr = document.createElement("TR");
		tb.appendChild(tr);
		tab.webxColumnParent = tr;

		for(var i = 0; i < tdescr.columnCount; i++) {
			var td = this._createColumn(tab, i);

			// widgetek
			var col = columns[i];
			if(col) {
				for(var j = 0; j < col.length; j++) {
					var w = this.createWidget(col[j]);
					w.webxSaveable = true;
					w.webxIndex = j;
					td.appendChild(w);
					this.saveWidget(w);
				}
			}
		}
		this._setupColumnWidth(tab);

		document.getElementById(this.desktopId).appendChild(tab);
		document.getElementById(this.tabsId).insertBefore(this._createTab(tab), document.getElementById(this.newTabId));
		if(show) this.showPanel(tdescr.id);

		this.savePanel(tab);

//		return tab;
	},

	/* Ha az id nincs megadva, vagy null, akkor az első panel fog megjelenítődni. */
	showPanel: function(id) {
		// Először lezárjuk a panel editort, ha nyitott.
		webx._tabEditClose();
		// Panel megjelenítése.
		var desktop = document.getElementById(this.desktopId);
		for(var p = desktop.firstChild; p != null; p = p.nextSibling) {
			if(p.webxPanel) {
				if(!id) id = p.webxPanel.id;
				if(p.webxPanel.id == id) {
					p.className = "wx_panel";
					document.getElementById(this.tabIdPrefix + id).className = "select";
				} else {
					p.className = "wx_paneloff";
					document.getElementById(this.tabIdPrefix + p.webxPanel.id).className = "tab";
				}
			}
		}
	},

	getActivePanel: function() {
		var desktop = document.getElementById(this.desktopId);
		for(var p = desktop.firstChild; p != null; p = p.nextSibling) {
			if(p.webxPanel && p.className == "wx_panel") {
				return p;
			}
		}
		return null;
	},

	closePanel: function(id) {
		var desktop = document.getElementById(this.desktopId);
		var c = 0;
		for(var p = desktop.firstChild; p != null; p = p.nextSibling) {
			if(p.webxPanel) c++;
		}
		if(c < 2) {
			alert("Az utolsó panelt nem lehet bezárni.");
			return;
		} else if(!window.confirm("FIGYELEM! A Panel (fül) megszüntetésével, minden benne található ablak, azok beállításai és tartalmai is elvesznek!\nBiztos bezárod?")) {
			return;
		}

		// Tab törlése.
		var tab = document.getElementById(this.tabIdPrefix + id);
		tab.parentNode.removeChild(tab);

		// Panel törlése.
		var panel = document.getElementById(this.panelIdPrefix + id);
		desktop.removeChild(panel);

		this.showPanel();

		// Mentsük el a változást.
		if(this.online) {
			wxlog.log("save panel... ");
			try {
				var sr = new XMLHttpRequest();
				var url = this.urlConsolidator(this.urls.panelDelete + "&id=" + id);
				sr.open("GET", url, true);
				sr.onreadystatechange = function() {
//					wxlog.log("loading: " + sr.readyState);
					if(sr.readyState == 4) {
						wxlog.log("loaded: " + sr.status);
						if(sr.status == 200 || sr.status == 0 /* local */) {
							wxlog.log("panel deleted: " + sr.responseText);
						} else {
							wxlog.log("http error (panel delete): " + sr.status);
						}
					}
				}

				sr.send(null);
			} catch(e) {
				wxlog.dir(e);
				wxlog.log("panel delete error: " + e);
			}
		}
	},

	_createModuleDir: function(element, descr) {
		Sarissa.clearChildNodes(element);
		var tips = new Array();

		for(var i = 0; i < descr.length; i++) {
			var d = descr[i];
			var item;
			if(d.type == "title") {
				item = document.createElement("DIV");
				item.className = "wx_md_title";
				item.innerHTML = d.text;
			} else {
				item = document.createElement("A");
				item.className = "wx_md_" + d.type;
				item.href = "javascript:nop()";
				item.webxModule = d;
				if(d.tip) {
					tips[tips.length] = { element: item, tip: d.tip };
				}

				var img = document.createElement("IMG");
				item.appendChild(img);
				item.webxIcon = img;

				var span = document.createElement("SPAN");
				span.innerHTML = d.text;

				if(d.type == "dir") {
					item.onclick = webxMod_DirClick;
					img.src = rootImgUrl + "/webx/webx-moduledir.gif";
					d.opened = false;
					d.loaded = false;
					d.loading = false;
				} else {
					eval("item.onclick=" + d.action);
					img.src = d.img ? this.urlConsolidator(d.img) : rootImgUrl + "/webx/spacer.gif";
				}

				item.appendChild(span);
			}
			element.appendChild(item);

			if(d.type == "dir") {
				var dir = document.createElement("DIV");
				dir.className = "wx_md_emptydir";
				dir.innerHTML = "Lóding...";
				dir.style.display = "none";
				element.appendChild(dir);
				item.webxChilds = dir;
			}
		}

		if(tips.length > 0) {
			var t = new TipManager(tips, 800);
			t.createTip = function(txt) {
				var tt = document.createElement("DIV");
				tt.className = "tip_modules";
				tt.innerHTML = "<div>" + txt + "</div>";
				return tt;
			}
		}
	},

	_loadModuleDir: function(element, pdescr) {
		try {
			var mdr = new XMLHttpRequest();
			var url = this.urlConsolidator(pdescr.ref);
			mdr.open("GET", url, true);
			mdr.onreadystatechange = function() {
//				wxlog.log("module dir loading: " + mdr.readyState);
				if(mdr.readyState == 4) {
					wxlog.log("module dir loaded: " + mdr.status + " - h: " + mdr.getAllResponseHeaders());
					if(mdr.status == 200 || mdr.status == 0 /* local */) {
						eval("var d=" + mdr.responseText);
						webx._createModuleDir(element, d);
						pdescr.loading = false;
						pdescr.loaded = true;
					} else {
						wxlog.error("http error (content): " + mdr.status + " url: '" + url + "'");
						pdescr.loading = false;
					}
				}
			}
			mdr.send(null);
		} catch(e) {
			pdescr.loading = false;
			wxlog.error("load error (module dir): " + e);
		}
	},

	createExhibition: function(widget) {
		this.closeExhibition();

		var dd = [ "div", { "class": "wx_exhibition", "webxExhibition": widget },
					[ "webx:button", { "webx:ref": "exhClose" } ],
					[ "a", { "class": "wx_exh_apply", href: "javascript:nop()", onclick: apply }, "Hozzáadom a panelhez" ]
				];

		function apply() {
			if(webx.exhibition) {
				webx.addWidgetToPanel(webx.exhibition.webxExhibition);
				webx.closeExhibition();
			}
		}

		var divx = webxJsonML(dd);
		divx.appendChild(widget);
		this.exhibition = divx;
		document.body.appendChild(divx);

		return divx;
	},

	closeExhibition: function() {
		if(this.exhibition) {
			this.exhibition.parentNode.removeChild(this.exhibition);
			this.exhibition = null;
		}
	},

	initDesktop: function(_url) {
		try {
			var dr = new XMLHttpRequest();
			var url;
			if(_url) {
				url = _url;
			} else {
				url = this.urls.desktop;
				if(this.online) url += "&rnd=" + new Date().getTime();
			}
			dr.open("GET", this.urlConsolidator(url), true);
			dr.onreadystatechange = function() {
//				wxlog.log("desktop loading: " + dr.readyState);
				if(dr.readyState == 4) {
					wxlog.log("desktop loaded: " + dr.status);
					if(dr.status == 200 || dr.status == 0 /* local */) {
						wxlog.log("desktop loaded: " + url);

						var js = dr.responseText;
						eval("var ddescr=" + js);

						// title
						document.getElementById(webx.titleId).innerHTML = ddescr.title + " webközpontja";

						var pans = ddescr.panels;
						for(var i = 0; i < pans.length; i++) {
							var p = pans[i];
							webx.createPanel(p.panel, p.columns, i == 0);
						}
					} else {
						wxlog.error("http error (desktop): " + dr.status + "h: " + dr.getAllResponseHeaders());
					}
				}
			}
			dr.send(null);
		} catch(e) {
			wxlog.error(e);
			wxlog.log("desktop load error: " + e);
		}
	},

	initModuleDir: function() {
		var md = document.getElementById(this.moduleDirId);

		var ca = document.createElement("A");
		ca.className = "wx_md_close";
		ca.href = "javascript:webxMDClose(false)";
		ca.innerHTML = "ablak bezárása";
		md.appendChild(ca);

		var fdiv = document.createElement("DIV");
		fdiv.className = "wx_md_emptydir";
		fdiv.innerHTML = "Lóding...";
		md.appendChild(fdiv);

		this._loadModuleDir(fdiv, { ref: this.urls.moduledir });
	},

	_globalOptionsClick: function(btn) {
		if(this.globalOptions != null) return;

		var pan = [
			"div", { "class": "wx_fpan" },
				[ "div", { "class": "wx_fpan_head" },
					[ "webx:button", { "webx:ref": "globalOptClose" } ],
					"Globális beállítások"
				],
				[ "h1", "Hatások:" ],
				[ "table", { align: "center" },
					[ "tr",
						[ "td", { style: "text-align: right;" },
							[ "input", { type: "checkbox", checked: webx.setup.animVirt, defaultChecked: webx.setup.animVirt, onclick: anim } ]
						],
						[ "td", "animálódó hátterek" ]
					],
					[ "tr",
						[ "td", { style: "text-align: right;" },
							[ "input", { type: "checkbox", checked: webx.setup.opacityDrag, defaultChecked: webx.setup.opacityDrag, onclick: opacity } ]
						],
						[ "td", "mozgatáskor áttetsző ablakok" ]
					]
				]
			];

		this.globalOptions = webxJsonML(pan);
		var pos = GetBounds(btn);
		document.body.appendChild(this.globalOptions);
		with(this.globalOptions.style) {
			left = (pos.x - 100) + "px";
			top = (pos.y + pos.h + 5) + "px";
		}
		delete pan;

		function anim() {
			webx.setup.animVirt = this.checked;
			setCookie("wxc_av", webx.setup.animVirt ? 1 : 0, 180);
		}

		function opacity() {
			webx.setup.opacityDrag = this.checked;
			setCookie("wxc_od", webx.setup.opacityDrag ? 1 : 0, 180);
		}
	},

	_globalOptionsClose: function() {
		if(this.globalOptions != null) {
			this.globalOptions.parentNode.removeChild(this.globalOptions);
			this.globalOptions = null;
		}
	},

	/**
	 * Tab opciók
	 */
	_tabEditClick: function(element) {
		if(this.tabOptions != null) return;

		var tab = webx.searchTab(element);
		var panel = tab.webxTab.panel;

		var selectedCol = new Object();

		var intitle = [ "input", { "class": "txt", type: "text", value: panel.webxPanel.name, element: null } ];
		var cols = [ "tr" ];
		for(var i = 1; i <= 5; i++) {
			var d = [
				"td",
					[ "a", { href: "javascript:nop()", "class" : "wx_fpan_btn", onclick: columns, webxCols: i }, i ]
				];
			if(i == panel.webxPanel.columnCount) {
				d[1][1].className = "wx_fpan_btnon";
				d[1][1].element = selectedCol;
			}
			cols[cols.length] = d;
		}
		var pan = [
			"div", { "class": "wx_fpan" },
				[ "div", { "class": "wx_fpan_head" },
					[ "webx:button", { "webx:ref": "tabOptClose" } ],
					"Tábla opciók"
				],
				[ "h1", "A fül neve:" ],
				[ "form", { onsubmit: title },
					[ "table", { align: "center" },
						[ "tr",
							[ "td",
								intitle
							],
							[ "td",
								[ "input", { type: "button", "class": "btn", onclick: title, value: "Módosít" } ]
							]
						]
					]
				],
				[ "h1", "Oszlopok száma:" ],
				[ "table", { align: "center" },
					cols
				]
			];

		this.tabOptions = webxJsonML(pan);
		var inputtitle = intitle[1].element;
		delete pan;
		delete intitle;
		delete cols;

		var pos = GetBounds(tab);
		document.body.appendChild(this.tabOptions);
		with(this.tabOptions.style) {
			left = pos.x + "px";
			top = (pos.y + pos.h + 5) + "px";
		}

		function columns() {
			if(webx.setColumnsCount(panel, this.webxCols)) {
				this.className = "wx_fpan_btnon";
				selectedCol.element.className = "wx_fpan_btn";
				selectedCol.element = this;
			}
		}

		function title() {
			var t = new String(inputtitle.value).trim();
			if(t == "") {
				inputtitle.value = panel.webxPanel.name;
			} else {
				webx.setPanelTitle(panel, t);
			}
			return false;
		}
	},

	_tabEditClose: function() {
		if(this.tabOptions != null) {
			this.tabOptions.parentNode.removeChild(this.tabOptions);
			this.tabOptions = null;
		}
	},

	/**
	 * RSS extractor (egy funkció mind felett, könnyű lesz fél év után belenyúlni...)
	 */
	rssExtractor: function() {
		var panres = [ "div", { "class": "newrss_res", element: null } ];
		var inurl = [ "input", { type: "text", "class": "txt", element: null } ];
		var pan =
			[ "div", { "class": "wx_fpan" }, 
				[ "div", { "class": "wx_fpan_head" },
					[ "webx:button", { "webx:ref": "extrClose", onclick: close } ],
					"RSS takarmányok."
				],
				[ "div", { style: "font-size: 10px; padding: 2px;" }, "Adj meg / másolj be egy általad ismert RSS/ATOM linket, vagy bármilyen webcímet (a rendszer megpróbál RSS forrást találni)" ],
				[ "form", { onsubmit: load },
					[ "table",
						[ "tr",
							[ "td", "URL:" ],
							[ "td", inurl ],
							[ "td", [ "input", { type: "button", value: "Beolvas", "class": "btn", onclick: load } ] ]
						]
					]
				],
				panres
			];

		var dive = webxJsonML(pan);
		var divres = panres[1].element;
		var inputurl = inurl[1].element;
		delete pan;
		delete panres;
		delete inurl;

		function close() {
			dive.parentNode.removeChild(dive);
		}

		function print(d) {
			wxlog.dir(d);
			if(d) {
				if(d.message) {
					divres.innerHTML = "<b>Hiba:</b> " + d.message;
				} else if(d.length == 0) {
					divres.innerHTML = "<b>Nem találtam RSS takarmányt.</b>";
				} else {
					Sarissa.clearChildNodes(divres);
					for(var i = 0; i < d.length; i++) {
						var d1 = d[i];
						var dr = [ "A", { href: "javascript:nop()", onclick: extract, webxRSS: d1 },
							[ "H2", d1.title ],
							[ "H3", d1.url ]
						];
						divres.appendChild(webxJsonML(dr));
					}
				}
			} else {
				divres.innerHTML = "<b>Nem értelmezhető válasz!</b>";
				wxlog.error("Ismeretlen RSS extractum.");
				wxlog.dir(d);
			}
		}

		function load() {
			wxlog.log("load rss extract...");
			try {
				var sr = new XMLHttpRequest();
				var url = webx.urls.extractRSS;
				if(webx.online) url += "&url=" + escape(inputurl.value);
				sr.open("GET", webx.urlConsolidator(url), true);
				sr.onreadystatechange = function() {
		//			wxlog.log("loading: " + sr.readyState);
					if(sr.readyState == 4) {
						wxlog.log("loaded: " + sr.status);
						if(sr.status == 200 || sr.status == 0 /* local */) {
							wxlog.log("rss extract loaded: " + sr.responseText);
							eval('var d=' + sr.responseText);
							print(d);
						} else {
							wxlog.error("http error (rss extract): " + sr.status + ", url: " + url);
						}
					}
				}
				sr.send(null);
			} catch(e) {
				wxlog.dir(e);
				wxlog.error("rss extract error: " + e);
			}

			return false;
		}

		function extract() {
			var icon = this.webxRSS.icon ? this.webxRSS.icon : "img/webx-icon-rss.gif";
			var url = webx.online ? webx.urls.rss2json + escape(this.webxRSS.url) : this.webxRSS.url;
			var descr = {
				icon: icon,
				title: "", // this.webxRSS.title
				type: "TFeed",
				content: { type: "application/json", ref: url },
				editor: { type: "empty" },
				params: { refreshable: true }
			};

			var w = webx.createWidget(descr);
			var exh = webx.createExhibition(w);
			var pos = GetBounds(dive);
			with(exh.style) {
				left = (pos.x + pos.w + 6) + "px";
				top = pos.y + "px";
			}
		}

		document.body.appendChild(dive);
		return dive;
	},

	searchWidget: function(element) {
		while(element != null && !element.webxWidget) {
			element = element.parentNode;
		}
		return element;
	},

	getWidgetById: function(id) {
		return document.getElementById(this.widgetIdPrefix + id);
	},

	searchWgHeadButton: function(widget, bid) {
		for(var b = widget.webxHead.firstChild; b != null; b = b.nextSibling) {
			if(b.webxButton && b.webxButton.id == bid) {
				return b;
			}
		}
		return null;
	},

	searchTab: function(element) {
		while(element != null && !element.webxTab) {
			element = element.parentNode;
		}
		return element;
	},

	searchPanel: function(element) {
		while(element != null && !element.webxPanel) {
			element = element.parentNode;
		}
		return element;
	},

	/**
	 * Speciálisabb, mint a többi searchXXX, mert egy objektumot ad vissza, ami tartalmazza az oszlop indexét és a panel node-ot.
	 * { panel: <panel node>, columnIndex: <n> }
	 */
	searchColumn: function(element) {
		var panel = this.searchPanel(element);

		if(panel != null) {
			while(element.parentNode !== panel.webxColumnParent) {
				element = element.parentNode;
			}

			var idx = 0;
			for(idx = 0; idx < panel.webxPanel.columnCount; idx++) {
				if(element === panel.webxColumns[idx]) break;
			}

			return { panel: panel, columnIndex: idx };
		}

		return null;
	},

	isFloatWidget: function(element) {
		while(element != null) {
			if(element === this.flContainer) return true;
			element = element.parentNode;
		}
		return false;
	},

	getTabByPoint: function(x, y) {
		for(var t = document.getElementById(this.tabsId).firstChild; t != null; t = t.nextSibling) {
			var pos = GetBounds(t);
			if(t.webxTab && OverElement(t, x, y)) {
				return t;
			}
		}
		return null;
	}
}

function webxDragMouseMove(e) {
	if(!e) e = event;

	var x = e.clientX + document.body.parentNode.scrollLeft;
	var y = e.clientY + document.body.parentNode.scrollTop;
	var fl = webx.isFloatWidget(webx.drag.widget);

	var x1 = x - webx.drag.x0;
	var y1 = y - webx.drag.y0 - (fl ? 0 : 7);

	with(webx.drag.widget) {
		style.left = x1 + 'px';
		style.top = y1 + 'px';
		x1 += offsetWidth / 2;
	}

	if(!fl) {
		// Tab
		var t = webx.getTabByPoint(x, y);
		if(t != null && t.webxTab.panel != webx.getActivePanel()) {
			if(webx.drag.tab != t) {
				if(webx.drag.tab != null) {
					webx.drag.tab.className = "tab";
				}
				webx.drag.tab = t;
				t.className = "hover";
				webx.drag.virt.parentNode.removeChild(webx.drag.virt);
			}
		} else {
			if(webx.drag.tab != null) {
				webx.drag.tab.className = "tab";
				webx.drag.tab = null;
			}

			// Column
			var p = webx.getActivePanel();
			var c;
			for(var i = p.webxPanel.columnCount - 1; i >= 0; i--) {
				c = p.webxColumns[i];
				var pos = GetBounds(c);
				if(x1 > pos.x) {
					break;
				}
			}

			// Widget
			var w;
			for(w = c.lastChild; w != null; w = w.previousSibling) {
				if(w.webxWidget && w != webx.drag.widget) {
					var pos = GetBounds(w);
//					wxlog.log('pos: ' + pos.y + ' - ' + y0);
					if(pos.y < y1) {
						break;
					}
				}
			}

			if(w == null) {
				w = c.firstChild;
			} else {
				w = w.nextSibling;
			}

			if(w == null) {
				c.appendChild(webx.drag.virt);
//				wxlog.log("append");
			} else if(w != webx.drag.virt) {
				c.insertBefore(webx.drag.virt, w);
//				wxlog.log("insert");
			}
		}
	}

	DiscardEvent(e);
}

function webxDragEnd(e) {
	wxlog.log("end drag...");
	if(!e) e = event;

	with(webx.drag) {
		if(widget) {
			var fl = webx.isFloatWidget(widget);

			with(widget.style) {
				if(!fl) {
					position = '';
					width = '';
//					height = '';
					left = '';
					top = '';
					zIndex = '';
				}
				if(is.ie) filter = "";
				else opacity = '';
			}

			var origP = webx.searchColumn(widget);
			var newP;
			if(tab) {
				tab.webxTab.panel.webxColumns[0].appendChild(widget);
				tab.className = "tab";
				widget.webxIndex = -1;
				newP = { panel: tab.webxTab.panel, columnIndex: 0 };
			} else if(virt) {
				virt.parentNode.replaceChild(widget, virt);
				widget.webxIndex = -1;
				newP = webx.searchColumn(widget);
			}

			// Ha nem mozdult el, vagy floating widget, akkor ne mentsük el.
			if(newP) {
				if(newP.panel === origP.panel && newP.columnIndex == origP.columnIndex) webx.saveColumnOrders(origP);
				else webx.saveColumnOrders(origP, newP);
			}

			virt = widget = tab = null;
			x0 = y0 = -1;
		}
	}

	ReleaseEvent(document.body, "mousemove", webxDragMouseMove, true);
	ReleaseEvent(document.body, "mouseup", webxDragEnd, true);

	DiscardEvent(e);
}

function webxDragStart(e) {
	wxlog.log("start drag...");
	if(!e) e = event;

	if(webx.drag.disabled || webx.drag.widget) return;

	var w = webx.searchWidget(this);
	var pos = GetBounds(w);
	var fl = webx.isFloatWidget(w);
	if(!fl) {
		// Ha nem lebegő, akkor lássuk, mozgatható-e.
		var w0 = w;
		do {
			w0 = w0.parentNode;
			if(w0 == null) return;
		} while(!w0.webxPanel);

		with(w.style) {
			width = (pos.w - 4) + 'px'; // border
//			height = (pos.h - 4) + 'px'; // border
			left = pos.x + 'px';
			top = (pos.y - 7) + 'px'; // margin
			position = 'absolute';
			zIndex = 100;
			if(webx.setup.opacityDrag) {
				if(is.ie) filter = "progid:DXImageTransform.Microsoft.Alpha(opacity=85,finishOpacity=40,startX=30,startY=0,finishX=60,finishY=90,style=1)";
				else opacity = .75;
			}
		}
	} else {
		// lebegő
		with(w.style) {
			// z-indexet be kell újra rendezni a floatok között.
			var z = zMax = new Number(zIndex);
			for(var w0 = webx.flContainer.firstChild; w0 != null; w0 = w0.nextSibling) {
				var z0 = new Number(w0.style.zIndex);
				if(z0 > zMax) zMax = z0;
				if(z0 > z) {
					w0.style.zIndex = z0 - 1;
				}
			}
			zIndex = zMax;

			if(webx.setup.opacityDrag) {
				if(is.ie) filter = "progid:DXImageTransform.Microsoft.Alpha(opacity=85,finishOpacity=40,startX=30,startY=0,finishX=60,finishY=90,style=1)";
				else opacity = .75;
			}
		}
	}

	with(webx.drag) {
		widget = w;
		if(!fl) {
			virt = document.createElement("DIV");
			virt.className = webx.setup.animVirt ? "webx_virtual" : "webx_virtual_noanim";
			virt.style.height = (pos.h - 4) + 'px'; 
			w.parentNode.insertBefore(virt, w);
		}

		x0 = (e.clientX + document.body.parentNode.scrollLeft) - pos.x;
		y0 = (e.clientY + document.body.parentNode.scrollTop) - pos.y;

//		wxlog.log("head: " + x0 + ';' + y0 + ' -- ' + document.body.parentNode.scrollLeft + "," + document.body.parentNode.scrollTop);
	}

	CaptureEvent(document.body, "mousemove", webxDragMouseMove, true);
	CaptureEvent(document.body, "mouseup", webxDragEnd, true);

	DiscardEvent(e);
}

function webxHeadButtonOver() {
//	wxlog.log("button over: ");
	webx.drag.disabled = true;
}

function webxHeadButtonOut() {
//	wxlog.log("button out: ");
	webx.drag.disabled = false;
}

function webxEdit() {
	var w = webx.searchWidget(this);
	var sel = !this.webxSelected;
	if(w.webxManager.editorVisible) {
		w.webxManager.editorVisible(sel);
	}
	w.webxEditor.className = this.webxSelect(sel) ? 'wx_weditoron' : 'wx_weditor';
}

function webxMinMax() {
	webx.setWidgetMinimized(webx.searchWidget(this), !this.webxSelected);
}

/* a ''this'' nem az aktív element */
function webxMinMaxAll(isMin) {
	var panel = webx.getActivePanel();
	for(var c = 0; c < panel.webxPanel.columnCount; c++) {
		var col = panel.webxColumns[c];
		for(var w = col.firstChild; w != null; w = w.nextSibling) {
			if(w.webxWidget) webx.setWidgetMinimized(w, isMin);
		}
	}
}

function webxRefresh() {
	var w = webx.searchWidget(this);
	webx.loadWidget(w);
}

// Widget close buttonjának lenyomása. this = a klikkelt <img> element.
function webxClose() {
	var w = webx.searchWidget(this);

	// a close buttonra nem jön mouseout
	webx.drag.disabled = false;

	for(var wp = w.parentNode; wp != null; wp = wp.parentNode) {
		if(wp.webxPanel || wp == webx.flContainer) {
			// Panelon elhelyezkedő widget, vagy lebegő widget
			if(w != null && (w.webxWidget.params.fastClose || window.confirm("FIGYELEM! Az ablak bezárásával minden benne található adat el fog veszni!\nBiztos bezárod?"))) {
				webx.deleteWidget(w);
			}
			return true;
		} else if(wp.webxExhibition) {
			// Exhibition-ben elheyezkedő widget.
			webx.closeExhibition();
			return true;
		}
	}

	wxlog.error("Widget hibás helyen, DOM fában.");
}

function WebxButton(_id, _title, _class, _action, _img, _img_over, _img_sel, _img_sover, _over, _out) {
	var imgRe = new RegExp('^(.*)(.gif|.jpg|.jpeg|.png)$');
	if(!_img_over) _img_over = _img.replace(imgRe, '$1-over$2');
	if(!_img_sel) _img_sel = _img.replace(imgRe, '$1-sel$2');
	if(!_img_sover) _img_sover = _img.replace(imgRe, '$1-sover$2');

	this.id = _id;
	this.title = _title;
	this.className = _class;
	this.img = _img;
	this.img_over = _img_over;
	this.img_sel = _img_sel;
	this.img_sover = _img_sover;
	this.action = _action;
	this.over = _over;
	this.out = _out;
}

WebxButton.prototype.create = function() {
	this.img = webx.urlConsolidator(this.img);
	this.img_over = webx.urlConsolidator(this.img_over);
	this.img_sel = webx.urlConsolidator(this.img_sel);
	this.img_sover = webx.urlConsolidator(this.img_sover);

	var b = document.createElement("IMG");
	b.src = this.img;
	if(this.title) b.title = this.title;
	if(this.className) b.className = this.className;
	b.onmouseover = function() {
		this.webxOvered = true;
		this.webxRefresh();
		if(this.webxButton.over) this.webxButton.over(this);
	};
	b.onmouseout = function() {
		this.webxOvered = false;
		this.webxRefresh();
		if(this.webxButton.out) this.webxButton.out(this);
	};
	if(this.action) b.onclick = this.action;
	b.webxButton = this;
	b.webxOvered = false;
	b.webxSelected = false;
	b.webxSelect = function(sel) {
		this.webxSelected = sel;
		this.webxRefresh();
		return sel;
	}
	b.webxRefresh = function() {
		var im = this.webxSelected ? (this.webxOvered ? this.webxButton.img_sover : this.webxButton.img_sel) : (this.webxOvered ? this.webxButton.img_over : this.webxButton.img);
		this.src = im;
	}

	return b;
}

/**
 * Look & feel editor.
 */
function webxCreateLookEditor(element, className) {
	if(!className) className = "wx_edit_looks";
	var widget = webx.searchWidget(element);

	function click() {
		webx.setWidgetLookAndFeel(widget, this.webxLook);
	}

	for(var i = 0; i < 15; i++) {
		var al = [ "A", { href: "javascript:nop()", "class": className + " wx_edit_look" + i, webxLook: "wlook" + i, onclick: click } ];
		element.appendChild(webxJsonML(al));
	}
}

/**
 * Module dirrel kapcsolatos funkciók
 */
function webxMDClose(openClose) {
	var md = document.getElementById(webx.moduleDirId);
	var cls = openClose ? (md.className == "wx_mdoff" ? "wx_md" : "wx_mdoff") : "wx_mdoff";
	md.className = cls;
}

// Új RSS feed
function webxMod_NewFeed() {
	var x = webx.rssExtractor();
	var pos = GetBounds(this);
	with(x.style) {
		left = (pos.x + pos.w + 6) + "px";
		top = pos.y + "px";
	}
}

function webxMod_DirClick() {
	var descr = this.webxModule;
	if(descr.opened) {
		this.webxChilds.style.display = "none";
		this.webxIcon.src = rootImgUrl + "/webx/webx-moduledir.gif";
		descr.opened = false;
	} else {
		if(!descr.loaded) {
			webx._loadModuleDir(this.webxChilds, descr);
		}
		this.webxChilds.style.display = "";
		this.webxIcon.src = rootImgUrl + "/webx/webx-moduledir-over.gif";
		descr.opened = true;
	}
}

function webxMod_Widget() {
	var descr = this.webxModule;

	var w = webx.createWidget(descr.descriptor);
	var exh = webx.createExhibition(w);
	var pos = GetBounds(this);
	with(exh.style) {
		left = (pos.x + pos.w + 6) + "px";
		top = pos.y + "px";
	}
}

/**
 * Globális opciók kinyitása / bezárása. Az element paraméter a link element.
 */
function webxGlobalOptionsOpenClose(element) {
	if(webx.globalOptions) webx._globalOptionsClose();
	else webx._globalOptionsClick(element);
}

/**
 * Tab opciók kinyitása / bezárása. A this a link element.
 */
function webxTabOptionsOpenClose() {
	if(webx.tabOptions) webx._tabEditClose();
	else webx._tabEditClick(webx.searchTab(this));
}

/**
 * Konzol funkciók
 */
function webxOpenConsole() {
	if(webx.searchWidget(webx.console) != null) {
		wxlog.error("Egy konzol már létezik, ebből nem lehet még egyet megnyitni!");
		return;
	}

	var d = { icon: "%img%/webx/ikon002.gif", title: "Konzol", type: "TConsole", content: { type: "empty" } };
	var w = webx.createWidget(d);
	var exh = webx.createExhibition(w);
	var pos = GetBounds(this);
	with(exh.style) {
		left = pos.x + "px";
		top = (pos.y + pos.h + 10) + "px";
	}
}

/**
 * Lebegő ablak készítő segédfunkció. onclick és href property-kben történő hasnálatra lett kitalálva.
 *
 * @param descriptor  szabványos widget descriptor
 * @param ret  milyen return érték jön ki a funkcióból
 * @return a <code>ret</code> paraméter, kivéve, ha a <code>ret == null</code>, vagy undefined, akkor nincs return value.
 */
function webxCreateFloatWidget(descriptor, ret) {
	webx.createWidget(descriptor, true);
	if(typeof ret == 'undefined' || ret == null) return;
	return ret;
}

/**
 * JSONML funkciók, némi kiegészítéssel.
 */
function webxJsonML(jsonml) {
//	wxlog.log("JSONML: " + jsonml.toJSONString());

	var t = typeof jsonml;
	if(jsonml instanceof Array && jsonml.length > 0) {
		// Element
		var tag = jsonml[0].toUpperCase();
		var e;
		if(tag == "WEBX:BUTTON") {
			var b;
			if(jsonml[1]['webx:ref']) {
				b = webx.buttons[jsonml[1]['webx:ref']];
			} else {
				b = new WebxButton(jsonml[1]['webx:id'], jsonml[1]['webx:title'], jsonml[1]['webx:class'], jsonml[1]['webx:action'], jsonml[1]['webx:src'], jsonml[1]['webx:srcOver'], jsonml[1]['webx:srcSel'], jsonml[1]['webx:srcSOver'], jsonml[1]['webx:over'], jsonml[1]['webx:out']);
			}
			e = b.create();
		} else {
			e = document.createElement(tag);
		}
		if(jsonml.length > 1) {
			var i = 1;
			var ad = jsonml[1];
			if(typeof ad == 'object' && !(ad instanceof Array)) {
				// attr
				for(var a in ad) {
					if(a == 'element') {
						if(ad.element != null && typeof ad.element == 'object') {
							ad.element[ad.elementId ? ad.elementId : 'element'] = e;
						} else {
							ad.element = e;
						}
					} else if(a == 'elementId') {
						// Az "element" property feldolgozásánál kell.
					} if(a == 'class') {
						e.className = ad[a];
					} else if(a == 'style') {
						if(is.ie) e.style.cssText = ad[a];
						else e.setAttribute('style', ad[a]);
					} else if(!ad.constructor.prototype[a] && a.indexOf('webx:') != 0) {
//						e.setAttribute(a, ad[a]);
						e[a] = ad[a];
//						wxlog.log("attr0: " + a + ": " + e[a]);
					}
				}
				i = 2;
			}

			var e1;
			if(tag == "TABLE") {
				e1 = document.createElement("TBODY");
				e.appendChild(e1);
			} else {
				e1 = e;
			}

			for(; i < jsonml.length; i++) {
				e1.appendChild(webxJsonML(jsonml[i]));
			}
		}
		return e;
	} else if(t == "string" || t == "number" || t == "boolean") {
		// Text
		return document.createTextNode(jsonml);
	}

	var e = "Hibás jsonml! Nem megfelelö tipus: " + t;
	wxlog.error(e);
	wxlog.trace();
	throw new Error(e);
}

//
// DEBUG funkciók
//
var wxlog = {
	firebug: false,

	log: function(str) {
		if(this.firebug) console.log(str);
		else this.addLogItem(str, "log");
	},

	debug: function(str) {
		if(this.firebug) console.debug(str);
		else this.addLogItem(str, "debug");
	},

	info: function(str) {
		if(this.firebug) console.info(str);
		else this.addLogItem(str, "info");
	},

	warn: function(str) {
		if(this.firebug) console.warn(str);
		else this.addLogItem(str, "warn");
	},

	error: function(str) {
		if(this.firebug) console.error(str);
		else this.addLogItem(str, "error");
	},

	dir: function(obj) {
		if(this.firebug) console.dir(obj);
		else this.addLogItem("wxlog.dir() is not supported ", "error");
	},

	trace: function() {
		if(this.firebug) console.trace();
		else this.addLogItem("wxlog.trace() is not supported ", "error");
	},

	addLogItem: function(str, className) {
		if(webx.console) {
			var atEnd = webx.console.scrollTop + webx.console.offsetHeight >= webx.console.scrollHeight;

			var div = document.createElement("DIV");
			div.className = className;
			var txt = document.createTextNode(str);
			div.appendChild(txt);
			webx.console.appendChild(div);

			if(atEnd) {
				webx.console.scrollTop = webx.console.scrollHeight - webx.console.offsetHeight;
			}
		}
	}
}

