function kApplication() {
	this.Hooks = new Array ();
}

kApplication.prototype.footerInit = function () {
	if (use_popups() && window.name.match(/[\d]+$/)) {
		addEvent(
			window, 'unload',
			function() {
//				alert('unload event; unload legal: ' + unload_legal);
				if (!unload_legal && window.name != 'main') {
					// it's set in submit_kernel_form - if we are submitting form, the unload is already handled
					// if we got here, it means that we are closing window ilegally (through OS interace X button)
//						alert('closing window');
					// we need to clear temp tables then

					getFrame('head').WatchClosing(window, _DropTempUrl);
				}
			}
		);

		// we need to set unload_legal to true if we are refreshing current window, because onunload will still fire
		addEvent(document, 'keydown',
			function(e) {
				var code;
				if (!e) var e = window.event;
				if (e.keyCode) code = e.keyCode;
				else if (e.which) code = e.which;
				if (code == 116 || (e.ctrlKey && code == 82)) {
					unload_legal = true; //F5 or Ctrl+R
//					alert('[document.keydown] setting unload_legal = true');
				}
			}
		);
	}
}

kApplication.prototype.removeDebuggerStatistics = function () {
	var $debug_statistics = $('table.dbg_stats_table:first');
	if ($debug_statistics.length > 0) {
		// remove debugger short report and preceeding line break, because
		// this adds additional vertical scrollbar (no matter what document.style.overflow is)
		// when used in Opera & Google Chrome
		$debug_statistics.prev('br').remove();
		$debug_statistics.remove();
	}
}

kApplication.prototype.SetVar = function ($name, $value) {
	set_hidden_field($name, $value);
}

// hidden fields are printed in footer, that's why use this in m:OnAfterWindowLoad hook
kApplication.prototype.GetVar = function ($name) {
	return get_hidden_field($name);
}

kApplication.prototype.setHook = function ($hook_to, $do_code, $hook_mode) {
	if (!isset($hook_mode)) {
		$hook_mode = hBEFORE;
	}
	if (typeof $hook_to == 'string') {
		if ($hook_to == 'm:OnAfterWindowLoad') {
			$(document).ready($do_code);

			// call add load method here, when jquery not available
//			this.addLoadEvent($do_code);
			return ;
		}

		setArrayValue(this.Hooks, $hook_to, $hook_mode, $do_code);
	}
	else {
		var $i = 0;
		while ($i < $hook_to.length) {
			this.setHook($hook_to[$i], $do_code, $hook_mode);
			$i++;
		}
	}
}

kApplication.prototype.addLoadEvent = function (func, wnd) {
	if (!wnd) wnd = window
	var oldonload = wnd.onload;
	if (typeof wnd.onload != 'function') {
    	wnd.onload = func;
	} else {
		wnd.onload = function() {
			if (oldonload) {
	        	oldonload();
			}
			func();
		}
	}
}

kApplication.prototype.processHooks = function ($hook_to, $hook_mode, $event_params) {
	// allows to hook to any event from given prefix using "prefix:*" like $function_name
	if (!isset($event_params)) {
		$event_params = {};
	}

	if (($hook_to.indexOf('*') == -1) && ($hook_to.indexOf(':') != -1)) {
		var $do_event = new kEvent($hook_to, $event_params);
		$event_params.OriginalName = $do_event.Name;

		if (!this.processHooks($do_event.Prefix + ':*', $hook_mode, $event_params)) {
			return false;
		}
	}

	// allows to hook to specific given event from given prefix
	if (!isset($hook_mode)) {
		$hook_mode = hBEFORE;
	}

	var $i = 0;
	var $defined_hooks = getArrayValue(this.Hooks, $hook_to, $hook_mode);

	while($i < $defined_hooks.length) {
		var $do_event = new kEvent($hook_to, $event_params);
		$defined_hooks[$i]($do_event);
		if (!$do_event.status) {
			return false;
			break;
		}
		$i++;
	}
	return true;
}

// =======================================

function kEvent($name, $params) {
	if ($name.match(/([^.:]*)[.]{0,1}([^:]*):(.*)/)) {
		this.Prefix = RegExp.$1;
		this.Special = RegExp.$2;
		this.Name = RegExp.$3;
		this.Params = $params;
	}

	this.status = true;
}