function DebugReq() {}

DebugReq.timeout = 5000; //5 seconds

DebugReq.makeRequest = function(p_url, p_busyReq, p_progId, p_successCallBack, p_errorCallBack, p_pass, p_object) {
	//p_url: the web service url
	//p_busyReq: is a request for this object currently in progress?
	//p_progId: element id where progress HTML should be shown
	//p_successCallBack: callback function for successful response
	//p_errorCallBack: callback function for erroneous response
	//p_pass: string of params to pass to callback functions
	//p_object: object of params to pass to callback functions
	if (p_busyReq) {
		return;
	}
	var req = DebugReq.getRequest();
	if (req != null) {
		p_busyReq = true;
		DebugReq.showProgress(p_progId);
		req.onreadystatechange = function() {
			if (req.readyState == 4) {
				p_busyReq = false;
				window.clearTimeout(toId);
				if (req.status == 200) {
					p_successCallBack(req,p_pass,p_object);
				} else {
					p_errorCallBack(req,p_pass,p_object);
				}
			}
		}
		req.open('GET', p_url, true);
		req.setRequestHeader('If-Modified-Since', 'Sat, 1 Jan 2000 00:00:00 GMT');
		req.send(null);
		var toId = window.setTimeout( function() {if (p_busyReq) req.abort();}, DebugReq.timeout );
	}
}

DebugReq.getRequest = function() {
	var xmlHttp;
	try { xmlHttp = new ActiveXObject('MSXML2.XMLHTTP'); return xmlHttp; } catch (e) {}
	try { xmlHttp = new ActiveXObject('Microsoft.XMLHTTP'); return xmlHttp; } catch (e) {}
	try { xmlHttp = new XMLHttpRequest(); return xmlHttp; } catch(e) {}
	return null;
}

DebugReq.showProgress = function(p_id) {
	$Debugger.AppendRow(DebugReq.getProgressHtml());
}

DebugReq.getProgressHtml = function() {
	return 'Loading ...';
}

DebugReq.getErrorHtml = function(p_req) {
	//TODO: implement accepted way to handle request error
	return "<p>" + "(" + p_req.status + ") " + p_req.statusText + "</p>"
}

// Debugger
function Debugger($row_separator, $errors_count, $fatal_error, $sql_count) {
	this.RowSeparator = $row_separator;
	this.IsFatalError = $fatal_error;
	this.ErrorsCount = parseInt($errors_count);
	this.SQLCount = parseInt($sql_count);
	this.IsQueried = false;
	this.IsVisible = false;
	this.DebuggerDIV = document.getElementById('debug_layer');
	this.DebuggerTable = document.getElementById('debug_table');
	this.RowCount = 0;
	this.busyRequest = false;

//	window.$Debugger = this; // this should be uncommented in case if debugger variable is not $Debugger
	this.AddEvent(window, 'scroll', function (ev) { window.$Debugger.Resize(ev); });
	this.AddEvent(window, 'resize', function (ev) { window.$Debugger.Resize(ev); });
//	this.AddEvent(window, 'keydown', function (ev) { window.$Debugger.KeyDown(ev); }); // don't work in IE
	document.onkeydown = function(ev) { window.$Debugger.KeyDown(ev); }
}

Debugger.prototype.SetOpacity = function(opacity)
{
	this.DebuggerToolbar.style.opacity = (opacity / 100);
	this.DebuggerToolbar.style.MozOpacity = (opacity / 100);
	this.DebuggerToolbar.style.KhtmlOpacity = (opacity / 100);
	this.DebuggerToolbar.style.filter = "alpha(opacity=" + opacity + ")";
}

Debugger.prototype.ToolbarClick = function ($button) {
	switch ($button.id) {
		case 'dbg_ReloadFrame':
			self.location.reload();
			break;
		
		case 'dbg_ShowDebugger':
			this.Toggle();
			break;
	}
}

Debugger.prototype.AddToolbar = function($var_name) {
	var $span = document.createElement('SPAN');
	$span.style.position = 'absolute';
	document.body.style.textAlign = 'left';

	var $toolbar_content = '<td class="dbg-button" id="dbg_ReloadFrame" onclick="' + $var_name + '.ToolbarClick(this);">Reload Frame</td>';
	
	if (this.ErrorsCount > 0) {
		$toolbar_content += '<td class="dbg-separator"></td><td class="dbg-button debug_error" style="font-weight: bold;" id="dbg_ShowDebugger" onclick="' + $var_name + '.ToolbarClick(this);">Show Debugger (' + this.ErrorsCount + ' errors)</td>';
	}
	else {
		$toolbar_content += '<td class="dbg-button" id="dbg_ShowDebugger" onclick="' + $var_name + '.ToolbarClick(this);">Show Debugger</td>';
	}
	
	if (this.SQLCount > 0) {
		$toolbar_content += '<td class="dbg-separator"></td><td>' + this.SQLCount + ' sqls</td>';
	}
	
	$span.innerHTML = '<table cellpadding="0" cellspacing="3" class="dbg-toolbar"><tr>' + $toolbar_content + '</tr></table>';
	
	this.DebuggerToolbar = $span;
	this.SetOpacity(20);
	$span.onmouseover = function() {
		$Debugger.SetOpacity(100);
	}
	$span.onmouseout = function() {
		$Debugger.SetOpacity(20);
	}

	var $body = document.getElementsByTagName('BODY')[0];
	$body.insertBefore($span, $body.firstChild);
}

Debugger.prototype.AppendRow = function($html) {
	this.RowCount++;
	var $tr = document.createElement('TR');
	this.DebuggerTable.appendChild($tr);
	$tr.className = 'debug_row_' + (this.RowCount % 2 ? 'odd' : 'even');
	$tr.id = 'debug_row_' + this.RowCount;
	var	$td = document.createElement('TD');
	$td.className = 'debug_cell';
	$td.innerHTML = $html;
	$tr.appendChild($td);
}

Debugger.prototype.RemoveRow = function($row_index) {
	this.DebuggerTable.deleteRow($row_index);
	this.RowCount--;
}

Debugger.prototype.Clear = function() {
	if (!this.IsQueried) return false;

	this.IsQueried = false;
	while (this.DebuggerTable.rows.length) {
		this.RemoveRow(0);
	}
}

Debugger.prototype.KeyDown = function($e) {
	var $KeyCode = this.GetKeyCode($e);
	if ($KeyCode == 123 || $KeyCode == 27) {// F12 or ESC
		this.Toggle($KeyCode);
		this.StopEvent($e);
	}
}

Debugger.prototype.OpenDOMViewer = function() {
	var $value = document.getElementById('dbg_domviewer').value;
	DOMViewerObj = ($value.indexOf('"') != -1) ? document.getElementById( $value.substring(1,$value.length-1) ) : eval($value);
	window.open(this.DOMViewerURL);
	return false;
}

Debugger.prototype.GetKeyCode = function($e) {
	$e = ($e) ? $e : event;
	var target = ($e.target) ? $e.target : $e.scrElement;
	var charCode = ($e.charCode) ? $e.charCode : (($e.which) ? $e.which : $e.keyCode);
	return charCode;
}

Debugger.prototype.StopEvent = function($e) {
	$e = ($e) ? $e : event;
	$e.cancelBubble = true;
	if ($e.stopPropagation) $e.stopPropagation();
}

Debugger.prototype.Toggle = function($KeyCode) {
	if(!this.DebuggerDIV) return false;
	this.IsVisible = this.DebuggerDIV.style.display == 'none' ? false : true;
	if (!this.IsVisible && $KeyCode == 27) {
		return false;
	}

	this.Resize(null);
	if (!this.IsQueried) {
		this.Query();
	}

	this.DebuggerDIV.style.display = this.IsVisible ? 'none' : 'block';
}

Debugger.prototype.Query = function() {
	DebugReq.makeRequest(this.DebugURL, this.busyRequest, '', this.successCallback, this.errorCallback, '', this);
}

Debugger.prototype.successCallback = function(p_req, p_pass, p_object) {
	var contents = p_req.responseText;

	contents = contents.split(p_object.RowSeparator);
	if (contents.length == 1) {
		alert('error: '+p_req.responseText);
		p_object.IsQueried = true;
		return ;
	}

	for (var $i = 0; $i < contents.length - 1; $i++) {
		p_object.AppendRow(contents[$i]);
	}

	p_object.Refresh();
}

Debugger.prototype.errorCallback = function(p_req, p_pass, p_object) {
	alert('AJAX ERROR: '+DebugReq.getErrorHtml(p_req));
	p_object.Refresh();
}

Debugger.prototype.Refresh = function() {
	// progress mether row
	this.RemoveRow(0);
	this.IsQueried = true;
	this.DebuggerDIV.scrollTop = this.IsFatalError ? 10000000 : 0;
	this.DebuggerDIV.scrollLeft = 0;
}

Debugger.prototype.Resize = function($e) {
	if (!this.DebuggerDIV) return false;
	var $pageTop = document.all ? document.body.offsetTop + document.body.scrollTop : window.scrollY;

	this.DebuggerDIV.style.top = $pageTop + 'px';
	this.DebuggerDIV.style.height = GetWindowHeight() + 'px';
	return true;
}

function GetWindowHeight() {
	var currWinHeight;
		
//	if (document.body.clientHeight) {
//		currWinHeight = document.body.clientHeight;	

	if (window.innerHeight) {//FireFox with correction for status bar at bottom of window
		currWinHeight = window.innerHeight;
	} else if (document.documentElement.clientHeight) {//IE 7 with correction for address bar
		currWinHeight = document.documentElement.clientHeight;
	} else if (document.body.offsetHeight) {//IE 4+
		currWinHeight = document.body.offsetHeight + 10;
	}
	return currWinHeight - 10; // 10 - horizontal scrollbar height
}


/*function GetWinHeight() {
	if (window.innerHeight) return window.innerHeight;
	else if (document.documentElement.clientHeight) return document.documentElement.clientHeight;
	else if (document.body.offsetHeight) return document.body.offsetHeight;
	else return _winHeight;
}*/

Debugger.prototype.SetClipboard = function(copyText) {
	if (window.clipboardData) {
		// IE send-to-clipboard method.
		window.clipboardData.setData('Text', copyText);
	}
	else if (window.netscape) {
		// You have to sign the code to enable this or allow the action in about:config by changing user_pref("signed.applets.codebase_principal_support", true);
		netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');

		// Store support string in an object.
		var str = Components.classes['@mozilla.org/supports-string;1'].createInstance(Components.interfaces.nsISupportsString);
		if (!str) {
			return false;
		}
		str.data = copyText;

		// Make transferable.
		var trans = Components.classes['@mozilla.org/widget/transferable;1'].createInstance(Components.interfaces.nsITransferable);
		if (!trans) {
			return false;
		}

		// Specify what datatypes we want to obtain, which is text in this case.
		trans.addDataFlavor('text/unicode');
		trans.setTransferData('text/unicode', str, copyText.length * 2);

		var clipid = Components.interfaces.nsIClipboard;
		var clip = Components.classes['@mozilla.org/widget/clipboard;1'].getService(clipid);
		if (!clip) {
			return false;
		}

		clip.setData(trans, null, clipid.kGlobalClipboard);
	}
}

Debugger.prototype.ShowProps = function($Obj, $Name) {
	var $ret = '';
	for ($Prop in $Obj) {
		$ret += $Name + '.' + $Prop + ' = ' + $Obj[$Prop] + "\n";
	}
	return alert($ret);
}

Debugger.prototype.editFile = function($fileName, $lineNo) {
	if (!document.all) {
		alert('Only works in IE');
		return;
	}

	if (!this.EditorPath) {
		alert('Editor path not defined!');
		return;
	}

	var $launch_object = new ActiveXObject('LaunchinIE.Launch');
	var $editor_path = this.EditorPath;
	$editor_path = $editor_path.replace('%F', $fileName);
	$editor_path = $editor_path.replace('%L',$lineNo);
	$launch_object.LaunchApplication($editor_path);
}

Debugger.prototype.ToggleTraceArgs = function($arguments_layer_id) {
	var $arguments_layer = document.getElementById($arguments_layer_id);
	$arguments_layer.style.display = ($arguments_layer.style.display == 'none') ? 'block' : 'none';
}

Debugger.prototype.AddEvent = function (el, evname, func) {
	var $status = false;
	if (document.all) {
		$status = el.attachEvent('on' + evname, func);
	} else {
		$status = el.addEventListener(evname, func, true);
	}
}