	var XHR = {
		data: null,
		script: null,
		request: function(address, method, param, cache, callback) {
			K.request({
				address: address,
				method: method,
				data: param,
				cache: cache,
				retry: 5,
				onRequest: Loading,
				onSuccess: function() {
					Revert();
					if (this.responseXML) {
						XHR.data = XHR.script = null;
						var XML = this.responseXML.documentElement;
						if (XML) {
							var KNodes = XML.getElementsByTagName("k");
							for (var o = 0; o < KNodes.length;  ++ o) {
								XHR.script = getTextContent(KNodes[o].childNodes[0]);
								XHR.data = getTextContent(KNodes[o].childNodes[1]);
								eval(XHR.script);
							}
						}
					} else {
						XHR.data = this.responseText;
					}
					if (callback) {
						if (K.check.isString(callback)) {eval(callback)}
						if (K.check.isFunction(callback)) {callback()}
					}
				},
				onFailure: function() {
					Revert();
					alert("Can't connect to sever. Please try again.");
				}
			});

			function getTextContent(node) {
				if (!node) {return ""}
				if (node.text) {return node.text}
				else if (node.textContent) {return node.textContent}
				else {return ""}
			}

			function Loading() {
				var oTextarea = K("field");
				if (!oTextarea) {return}
				oTextarea.style.color = "red";
				oTextarea.store = {loading: "Đang tải",	timeout: 0};
				oTextarea.success = false;
				K.set.timeout({
					method: function() {
						var random = Math.round(6 * Math.random());
						var value = oTextarea.store.loading;
						for (var o = 0 ; o < random; ++o) {
							value += ".";
						}
						oTextarea.value = value;
					},
					delay: 100,
					until: function() {return oTextarea.success},
					release: function() {
						oTextarea.value = "";
						oTextarea.style.color = "black";
					}
				});
			}
			function Revert() {
				var oTextarea = K("field");
				if (!oTextarea) return;
				oTextarea.success = true;
			}
		}
	};

	var vnjs = {
		viewFrontPage: function() {
			XHR.request("connector.php", "POST", "action=view&object=summary");
		},
		loadData: function() {
			if (!vnjs.data || !vnjs.data.Select) {
				XHR.request("connector.php", "POST", "action=load&object=data");
			}
			K("kombai").onscroll = vnjs.onScroll;
		},
		onScroll: function() {
			var taskBar = K("task-bar");
			var top = K("kombai").scrollTop + 49;
			taskBar.transform({marginTop: top, transition: 5});
		},
		reloadData: function() {
			//remove data
			var database = K("database.js");
			K.remove.element(database);
			vnjs.data = null;
			//erase menu
			K.select({
				from: K("task-bar"),
				where: 'className == "block-content"',
				formatWith: function(row, index) {
					row.refresh = true;
					row.innerHTML = "";
					row.hasContent = null;
				}
			});
			//reload data
			document.body.appendChild(
				K.create.element({
					tagName: 'script',
					id: 'database.js',
					attribute: {
						src: "script/lib/database.js?r=" + K.get.generalId()
					}
				})
			);
		},

		viewArticle: function(id) {
			XHR.request("connector.php", "POST", "action=view&object=article&id="+id);
		},
		showPopup: function(name, background) {
			K("mask-layout").show();
			var bgMark = K("bg-mask").show();
			bgMark.opacity(64).style.backgroundColor = "black";
			if (background == true) {
				bgMark.hide();
			}
			var node = K("popup-container").first();
			while (node) {
				if (name == node.id) {
					K(node).show();
				} else {
					K(node).hide();
				}
				node = node.next();
			}
		},
		initToolbar: function() {
			K("form-editor").select({
				where: "nodeName == 'DIV' && className == 'button'",
				formatWith: function(row, index) {
					row = K({Element: row});
					row.first().onclick = function(event) {
						var command = this.getAttribute("alt");
						var value = this.getAttribute("title") || null;
						if (command) {
							if (vnjs[command] && K.check.isFunction(vnjs[command])) {
								vnjs[command](value);
							} else {
								try {document.execCommand(command, false, value);}
								catch(e) {}
							}
						}
					};
					row.onmouseover = function(event) {
						this.style.border = "1px solid rgb(204, 204, 204)";
						this.style.backgroundColor = "white";
					};
					row.onmouseout = function(event) {
						this.style.border = "1px solid rgb(245, 245, 245)";
						this.style.backgroundColor = "";
					};
				}
			});
		},
		validText: function(value) {
			if (!value || K.remove.space(value) == "") {
				alert("Một số phần (có gạch đỏ) không nên để trống");
				return false;
			}
			var error = "";
			var chaos = new Array ("'","~","@","#","$","%","^","&","*",";","/","\\","|");
			var sum = chaos.length;
			for (var i in chaos) {if (!Array.prototype[i]) {sum += value.lastIndexOf(chaos[i])}}
			if (sum) {
				alert("Một số phần không nên có những ký tự đặc biệt như kiểu này: @ # $ % ^ * ~ ");
				return false;
			}
			return true;
		},
		correctText: function(html) {
			 var elementMap = [
		        [/<(B|b|STRONG)>(.*?)<\/\1>/gm, "<strong>$2</strong>"],
		        [/<(I|i|EM)>(.*?)<\/\1>/gm, "<em>$2</em>"],
		        [/<P>(.*?)<\/P>/gm, "<p>$1</p>"],
		        [/<H1>(.*?)<\/H1>/gm, "<h1>$1</h1>"],
		        [/<H2>(.*?)<\/H2>/gm, "<h2>$1</h2>"],
		        [/<H3>(.*?)<\/H3>/gm, "<h3>$1</h3>"],
		        [/<PRE>(.*?)<\/PRE>/gm, "<pre>$1</pre>"],
		        [/<A (.*?)<\/A>/gm, "<a $1</a>"],
		        [/<IMG (.*?)>/gm, "<img $1 alt=\"Image\" />"],
		        [/<LI>(.*?)<\/LI>/gm, "<li>$1</li>"],
		        [/<UL>(.*?)<\/UL>/gm, "<ul>$1</ul>"],
		        [/<span style="font-weight: normal;">(.*?)<\/span>/gm, "$1"],
		        [/<span style="font-weight: bold;">(.*?)<\/span>/gm, "<strong>$1</strong>"],
		        [/<span style="font-style: italic;">(.*?)<\/span>/gm, "<em>$1</em>"],
		        [/<span style="(font-weight: bold; ?|font-style: italic; ?){2}">(.*?)<\/span>/gm, "<strong><em>$2</em></strong>"],
		        [/<([a-z]+) style="font-weight: normal;">(.*?)<\/\1>/gm, "<$1>$2</$1>"],
		        [/<([a-z]+) style="font-weight: bold;">(.*?)<\/\1>/gm, "<$1><strong>$2</strong></$1>"],
		        [/<([a-z]+) style="font-style: italic;">(.*?)<\/\1>/gm, "<$1><em>$2</em></$1>"],
		        [/<([a-z]+) style="(font-weight: bold; ?|font-style: italic; ?){2}">(.*?)<\/\1>/gm, "<$1><strong><em>$3</em></strong></$1>"],
		        [/<(br|BR)>/g, "<br />"],
		        [/<(hr|HR)( style="width: 100%; height: 2px;")?>/g, "<hr />"]
		    ];
			var size = elementMap.length;
			for (var i = 0; i < size; i++) {html = html.replace(elementMap[i][0], elementMap[i][1])}
			return html;
		},
		insertHTML: function(html) {
			if (document.all) {
				var range = document.selection.createRange();
				try {
					range.pasteHTML(html);
					range.collapse(false);
				} catch(e) {}
			} else {
				document.execCommand("insertHTML", false, html);
			}
		},
		quote: function() {
			var text = K.get.selection();
			if (text != "") {
				text = new String(text).replace(/\n/g, "<br />");
				vnjs.insertHTML(
					"<div style='margin: 12px 0px; padding: 3px; background: #eeeeee; border: 1px solid #b7b7b7;'>"
					+ text
					+ "</div> <br/>"
				);
			}
		},
		highlight: function() {
			var text = K.get.selection();
			if (text != "") {
				text = K({String: text}).urlEncode();
				XHR.request("connector.php", "POST", "action=highlight&data="+text);
			}
		},
		createLink: function() {
			K('create-link-popup').show();
			Kombai.archive.variable.range = K.get.range();
			Kombai.archive.variable.selection = K.get.selection();
			var idoc = K('frame-create-link').contentWindow.document;
			var iform = idoc.forms[0];
			iform.reset();
			iform['text-view'].value = Kombai.archive.variable.selection;
		},
		saveLink: function() {
			var idoc = K('frame-create-link').contentWindow.document;
			var iform = idoc.forms[0];
			var textView = iform['text-view'].value || Kombai.archive.variable.selection;
			var url = iform['url'].value;
			K.set.range({
				range: Kombai.archive.variable.range,
				selection: Kombai.archive.variable.selection
			});
			try {
				document.execCommand('createLink', false, url);
			} catch(e) {}
			K('create-link-popup').hide();
		},
		cancelCreateLink: function() {
			var idoc = K('frame-create-link').contentWindow.document;
			var iform = idoc.forms[0];
			iform.reset();
			K('create-link-popup').hide();
		},
		data: null,
		form: {
			actyon: null,
			object: null,
			target: null,
			parent: null,
			title: null,
			author: null,
			summary: null,
			extend: null,
			password: null,
			content: null
		},
		fillForm: function() {
			var Form = K("form-editor");
			Form["actyon"].value = vnjs.form.actyon;
			Form["object"].value = vnjs.form.object;
			Form["target"].value = vnjs.form.target;
			Form["parent"].value = vnjs.form.parent;
			Form["title"].value = vnjs.form.title;
			Form["author"].value = vnjs.form.author;
			Form["summary"].value = vnjs.form.summary;
			if (vnjs.form.extend == 1) {
				Form["extend"][0].checked = true;
			} else {
				Form["extend"][1].checked = true;
			}
			Form["password"].value = vnjs.form.password;
			K("content-editable").innerHTML = vnjs.form.content;
		},
		createArticle : function(target, parent) {
			vnjs.showPopup("editor");
			var Form = K("form-editor");
			Form.reset();
			Form["actyon"].value = "create";
			Form["object"].value = "article";
			Form["target"].value = target ? target : null;
			Form["parent"].value = parent ? parent : null;
			var All = Form.first().childNodes;
			for (var o = 0; o < All.length; o ++) {
				if (K.check.isElement(All[o])) {
					All[o].style.display = "none";
					if ((/acticle/).test(All[o].className)) {
						All[o].style.display = "block";
					}
				}
			}
		},
		createComment : function(parent) {
			vnjs.showPopup("editor");
			var Form = K("form-editor");
			Form.reset();
			Form["actyon"].value = "create";
			Form["object"].value = "comment";
			Form["parent"].value = parent ? parent : null;
			var All = Form.first().childNodes;
			for (var o = 0; o < All.length; o ++) {
				if (K.check.isElement(All[o])) {
					All[o].style.display = "none";
					if ((/comment/).test(All[o].className)) {
						All[o].style.display = "block";
					}
				}
			}
		},
		preEditArticle: function() {
			vnjs.showPopup("editor");
			var Form = K("form-editor");
			Form.reset();
			var All = Form.first().childNodes;
			for (var o = 0; o < All.length; o ++) {
				if (K.check.isElement(All[o])) {
					All[o].style.display = "none";
					if ((/acticle/).test(All[o].className)) {
						All[o].style.display = "block";
					}
				}
			}
		},
		preEditComment: function() {
			vnjs.showPopup("editor");
			var Form = K("form-editor");
			Form.reset();
			var All = Form.first().childNodes;
			for (var o = 0; o < All.length; o ++) {
				if (K.check.isElement(All[o])) {
					All[o].style.display = "none";
					if ((/comment/).test(All[o].className)) {
						All[o].style.display = "block";
					}
				}
			}
		},
		preLog: function(action, object, target) {
			vnjs.showPopup("login");
			var Form = K("form-login");
			Form.reset();
			Form["actyon"].value = action;
			Form["object"].value = object;
			Form["target"].value = target;
		},
		logAction: function() {
			var Form = K("form-login");
			var Action = Form["actyon"].value
			var Object = Form["object"].value;
			var Target = Form["target"].value;
			var User = Form["user"].value;
			var Password = Form["password"].value || null;
			if (K.check.isString(User) && K.check.isString(Password)) {
				if (Action && Action == "login") {
					XHR.request(
						"connector.php",
						"POST",
						"action=" + Action +
						"&user=" + K({String: User}).urlEncode() +
						"&password=" + K({String: Password}).urlEncode()
					);
				} else {
					XHR.request(
						"connector.php",
						"POST",
						"action=" + Action +
						"&object=" + Object +
						"&id=" + Target +
						"&user=" + K({String: User}).urlEncode() +
						"&password=" + K({String: Password}).urlEncode()
					);
				}
				vnjs.cancelLog();
			} else {
				alert("Người dùng hoặc mật khẩu không nên để rỗng");
			}
		},
		cancelLog: function() {
			K("mask-layout").hide();
			var Form = K("form-login");
			Form.reset();
		},
		submitForm: function() {
			var Form = K("form-editor");
			var Action = Form["actyon"].value;
			var Object = Form["object"].value;
			var Target = Form["target"].value;
			var Parent = Form["parent"].value;
			var Title = Form["title"].value;
			var Author = Form["author"].value;
			var Summary = Form["summary"].value;
			Summary = K.remove.space(Summary);
			var Extend = Form["extend"][0].checked ? 1 : 0;
			var Password = Form["password"].value;
			Password = Password ? Password : K.get.generalId();
			var Content = K("content-editable").innerHTML;
			Content = vnjs.correctText(Content);
			if (Action && Object && Object == "article" && Target != null && Content
				&& vnjs.validText(Title) && vnjs.validText(Author)) {
				if (Summary.length < 8 || Summary.length > 512) {
					alert("Phần tóm tắt quá ngắn hoặc quá dài");
				} else {
					XHR.request(
						"connector.php",
						"POST",
						"action=" + Action +
						"&object=" + Object +
						"&target=" + Target +
						"&parent=" + Parent +
						"&title=" + K({String: Title}).urlEncode() +
						"&author=" + K({String: Author}).urlEncode() +
						"&summary=" + K({String: Summary}).urlEncode() +
						"&extend=" + Extend +
						"&password=" + K({String: Password}).urlEncode() +
						"&content=" + K({String: Content}).urlEncode()
					);
					vnjs.cancelSubmit();
				}
			} else if (Action && Object && Object == "comment"
					   && vnjs.validText(Author) && Content) {
				XHR.request(
					"connector.php",
					"POST",
					"action=" + Action +
					"&object=" + Object +
					"&target=" + Target +
					"&parent=" + Parent +
					"&author=" + K({String: Author}).urlEncode() +
					"&password=" + K({String: Password}).urlEncode() +
					"&content=" + K({String: Content}).urlEncode()
				);
				vnjs.cancelSubmit();
			}
		},
		cancelSubmit: function() {
			K("mask-layout").hide();
			K("form-editor").reset();
			K("content-editable").innerHTML = "<br/>";
		},
		getVnChar: function(text) {
			var code = [
				["a", "à|á|ạ|ả|ã|â|ầ|ấ|ậ|ẩ|ẫ|ă|ằ|ắ|ặ|ẳ|ẵ"],
				["e", "è|é|ẹ|ẻ|ẽ|ê|ề|ế|ệ|ể|ễ"],
				["i", "ì|í|ị|ỉ|ĩ"],
				["o", "ò|ó|ọ|ỏ|õ|ô|ồ|ố|ộ|ổ|ỗ|ơ|ờ|ớ|ợ|ở|ỡ"],
				["u", "ù|ú|ụ|ủ|ũ|ư|ừ|ứ|ự|ử|ữ"],
				["y", "ỳ|ý|ỵ|ỷ|ỹ"],
				["d", "đ"],
				["", "`|!|@|#|\\$|%|\\^|&|\\*|\\(|\\)|\\[|\\]|\\{|\\}"]
			];
			for (var j = 0; j < code.length; j++) {text = text.replace(new RegExp(code[j][1], "gi"), code[j][0])}
			return text ? text.toLowerCase() : "";
		},
		search: function(object, event) {
			//handler  event when key press in field search;
			var event = event || window.event;
			if (event.keyCode == 13) {return;}
			//store key word
			vnjs.search.value = object.value;
			if (vnjs.search.storeTimeout) {
				clearTimeout(vnjs.search.storeTimeout);
			}
			vnjs.search.storeTimeout = setTimeout(vnjs.renderResult, 500);
		},
		renderResult: function() {
			var template = ':. <a href=javascript:vnjs.viewArticle("{id}"); onmousedown=event.cancelBubble=true; ) >{title}</a>';
			var keyWord = vnjs.getVnChar(vnjs.search.value);
			var result = K("result");
			result.innerHTML = "";
			vnjs.data.Select({
				where: "code like '%" + keyWord + "%'",
				limit: 64,
				formatWith: function(row, index) {
					var newRow = K.create.element({
						tagName: "div",
						innerHTML: template.replace("{id}", row.id*1).replace("{title}",  row.title)
					});
					newRow.index = row.id;
					K(newRow).initDragDrop({
						onDrag: function() {
							var self = this.self;
							var event = this.event;
							document.body.appendChild(self);
							self.id = "m.o.b.i.l.e";
							self.style.position = "absolute";
							self.style.top = event.clientY - 7 + "px";
							self.style.left = event.clientX + 7 + "px";
						},
						onDrop:	function() {
							var self = this.self;
							self.removeAttribute("id");
							self.style.position = "static";
							K("result").appendChild(self);
						}
					});
					result.appendChild(newRow);
				}
			});
		},
		itemTemplate: null,
		showMenu: function(item, event, target, parent) {
			var group = K(item).select({where: "className == 'group-content'"})[0];
			K.remove.timeout(item.out);
			K(group).show();
			item.style.background = "#d5eaff";
			if (item.directShow == undefined) {item.directShow = 1}
			var P = {
				offsetWidth: item.offsetWidth,
				width: group.offsetWidth,
				x: K.get.X(item),
				maxWidth: K.get.windowWidth()
			}
			//left  to right
			if (item.directShow == 1) {
				var sum = P.x + P.width + 2*P.offsetWidth;
				if (P.maxWidth > sum) {
					group.style.left = P.offsetWidth - 5 + "px";
				} else {
					item.directShow = -1;
					group.style.left = - P.width + 5 + "px";
				}
			}
			//right to left
			if (item.directShow == -1) {
				if (P.x > P.width) {
					group.style.left = - P.width + 5 + "px";
				} else {
					item.directShow = 1;
					group.style.left = P.offsetWidth - 5 + "px";
				}
			}
			group.style.top = "-5px";
			//load template for item
			if (vnjs.itemTemplate == null && parent == 1000000000) {
				vnjs.itemTemplate = K(item.parentNode).last().innerHTML;
			}
			var blockItem = group.last();
			if (blockItem.hasContent == undefined  && vnjs.data != null) {
				//update menu
				if (blockItem.refresh) {
					blockItem.innerHTML = "";
					blockItem.refresh = null;
				}
				//create menu item
				vnjs.data.Select({
					where: "tag == " + target + " && re == " + parent,
					formatWith: function(row, index) {
						var subItem = K.create.element({
							tagName: "div",
							className: "menu-item",
							innerHTML: vnjs.itemTemplate
											.replace("{title}", ".: " + row.title)
											.replace("{target}", row.tag)
											.replace("{parent}", row.id)
						});
						subItem.index = row.id;
						subItem.local = row.tag;
						K(subItem).last().onclick = function() {
							vnjs.viewArticle(row.id);
						};
						subItem.onmouseover = function(event) {
							vnjs.showMenu(this, event, row.tag, row.id);
						};
						subItem.onmouseout = function(event) {
							vnjs.hideMenu(this, event);
						};
						//ondrop in item.
						subItem.onmouseup = function(event) {
							var mobile = K("m.o.b.i.l.e");
							if (K.check.isElement(mobile) && mobile.index != this.index) {
								XHR.request(
									"connector.php",
									"POST",
									"action=move&object=article"
									+ "&local=" + this.local
									+ "&id=" + mobile.index
									+ "&parent=" + this.index
								);
								mobile.id = null;
								mobile.style.position = "static";
								K("result").appendChild(mobile);
							}
						};
						blockItem.hasContent = true;
						blockItem.appendChild(subItem);
						subItem.directShow = item.directShow;
					}
				});
				if (!blockItem.hasContent && parent != 1000000000) {group.hide()}
			}
		},
		hideMenu: function(item, event) {
			var group = K(item).select({where: "className == 'group-content'"})[0];
			item.out = setTimeout(function(){K(group).hide();item.style.background = 'white'} , 200);
		},
		dropOnRootMenu: function(event, local) {
			var event = event || window.event;
			event.cancelBubble = true;
			var mobile = K('m.o.b.i.l.e');
			if (K.check.isElement(mobile)) {
				XHR.request(
					'connector.php',
					'POST',
					'action=move&object=article'
					+ '&local=' + local
					+ '&id=' + mobile.index
					+ '&parent=1000000000'
				);
				mobile.id = null;
				mobile.style.position = "static";
				K('result').appendChild(mobile);
			}
		}
	};

