<?php

	if(!class_exists('Debugger'))
	{
		function dbg_ConstOn($const_name)
		{
			return defined($const_name)&&constant($const_name);
		}
		
		function dbg_safeDefine($const_name,$const_value)
		{
			if(!defined($const_name)) define($const_name,$const_value);
		}
		
		unset($_REQUEST['debug_host']);	// this var messed up whole detection stuff :(
		
		// Detect fact, that this session beeing debugged by Zend Studio
		foreach($_REQUEST as $rq_name=>$rq_value)
		{
			if( substr($rq_name,0,6)=='debug_' )
			{
				define('DBG_ZEND_PRESENT',1);
				break;
			} 
		}
		
		dbg_safeDefine('DBG_ZEND_PRESENT',0);
		
		// set default values for debugger constants
		$dbg_constMap=Array('DBG_OPTIONS'=>0,
							'DBG_USE_HIGHLIGHT'=>1,
							'DBG_USE_SHUTDOWN_FUNC'=>DBG_ZEND_PRESENT?0:1,
							'DBG_HANDLE_ERRORS'=>DBG_ZEND_PRESENT?0:1,
							'DBG_SHOW_MEMORY_USAGE'=>1,
							'DBG_IGNORE_STRICT_ERRORS'=>1,
							'DOC_ROOT'=> str_replace('\\', '/', realpath($_SERVER['DOCUMENT_ROOT']) ), // windows hack 
							'DBG_LOCAL_BASE_PATH'=>'w:');
		
		foreach($dbg_constMap as $dbg_constName=>$dbg_constValue)
		{
			dbg_safeDefine($dbg_constName,$dbg_constValue);
		}
		
		// only for IE, in case if no windows php script editor defined
		/*if(!defined('WINDOWS_EDITOR'))
		{
			$dbg_editor = 0;
			$dbg_editors[0] = Array('editor' => 'c:\Program Files\UltraEdit\uedit32.exe', 'params' => '%F/%L');
			$dbg_editors[1] = Array('editor' => 'c:\Program Files\Zend\ZendStudio-4.0Beta\bin\ZDE.exe', 'params' => '%F');
			define('WINDOWS_EDITOR',$dbg_editors[$dbg_editor]['editor'].' '.$dbg_editors[$dbg_editor]['params']);
			unset($dbg_editors,$dbg_editor);
		}*/
	
		class Debugger 
		{
			/**
			 * Debugger data for building report
			 *
			 * @var Array
			 */
			var $Data = Array();
			var $ProfilerData = Array();
			var $ProfilerTotals = Array();
			var $RecursionStack = Array();	// prevent recursion when processing debug_backtrace() function results
			
			var $TraceNextError=false;
			
			var $Options = 0;
			var $OptionsMap = Array('shutdown_func' => 1, 'error_handler' => 2,
									'output_buffer' => 4, 'highlight_output' => 8);
			
			
			var $longErrors=Array();
			
			/**
			 * Amount of memory used by debugger itself
			 *
			 * @var Array
			 * @access private
			 */
			var $memoryUsage=Array();
			
			var $IncludesData=Array();
			var $IncludeLevel=0;
			
			function Debugger()
			{
				$this->profileStart('kernel4_startup', 'Startup and Initialization of kernel4');
				$this->profileStart('script_runtime', 'Script runtime');
				ini_set('display_errors',dbg_ConstOn('DBG_ZEND_PRESENT')?0:1);
				$this->memoryUsage['error_handling']=0; // memory amount used by error handler
				$this->appendRequest();
			}
			
			function initOptions()
			{
				
			}
			
			function mapLongError($msg)
			{
				$key=$this->generateID();
				$this->longErrors[$key]=$msg;
				return $key;
			}
			
			function setOption($name,$value)
			{
				if( !isset($this->OptionsMap[$name]) ) die('undefined debugger option: ['.$name.']<br>');
				if($value)
				{
					$this->Options|=$this->OptionsMap[$name];
				}
				else
				{
					$this->Options=$this->Options&~$this->OptionsMap[$name];
				}
			}
			
			function getOption($name)
			{
				if( !isset($this->OptionsMap[$name]) ) die('undefined debugger option: ['.$name.']<br>');
	    		return ($this->Options & $this->OptionsMap[$name]) == $this->OptionsMap[$name];
			}
			
			/**
			 * Set's flag, that next error that occurs will
			 * be prepended by backtrace results
			 *
			 */
			function traceNext()
			{
				$this->TraceNextError=true;
			}
			
			function dumpVars()
			{
				$dumpVars = func_get_args();
				foreach($dumpVars as $varValue)
				{
					$this->Data[] = Array('value' => $varValue, 'debug_type' => 'var_dump');
				}
			}
			
			function prepareHTML($dataIndex)
			{
				$Data =& $this->Data[$dataIndex];
				if($Data['debug_type'] == 'html') return $Data['html'];
				
				switch($Data['debug_type'])
				{
					case 'error':
						$fileLink = $this->getFileLink($Data['file'],$Data['line']);
						$ret = '<b class="debug_error">'.$this->getErrorNameByCode($Data['no']).'</b>: '.$Data['str'];
						$ret .= ' in <b>'.$fileLink.'</b> on line <b>'.$Data['line'].'</b>';
						return $ret;
						break;
					
					case 'var_dump':
						return $this->highlightString( print_r($Data['value'], true) );
						break;
						
					case 'trace':
						ini_set('memory_limit','500M');
						$trace =& $Data['trace'];
						
						//return 'sorry';
						//return $this->highlightString(print_r($trace,true));
						
						
						$i = 0; $traceCount = count($trace);
						$ret = '';
						while($i < $traceCount)
						{
							$traceRec =& $trace[$i];
							$argsID = 'trace_args_'.$dataIndex.'_'.$i;
							if(isset($traceRec['file']))
							{
								$func_name=isset($traceRec['class'])?$traceRec['class'].$traceRec['type'].$traceRec['function']:$traceRec['function'];
								$ret .= '<a href="javascript:toggleTraceArgs(\''.$argsID.'\');" title="Show/Hide Function Arguments"><b>Function</b></a>: '.$this->getFileLink($traceRec['file'],$traceRec['line'],$func_name);
								$ret .= ' in <b>'.basename($traceRec['file']).'</b> on line <b>'.$traceRec['line'].'</b><br>';
							}
							else 
							{
								$ret .= 'no file information available';
							}
							
							// ensure parameter value is not longer then 200 symbols
							$this->processTraceArguments($traceRec['args']);
							$args = $this->highlightString(print_r($traceRec['args'], true));
							$ret .= '<div id="'.$argsID.'" style="display: none;">'.$args.'</div>';
							$i++;
						}
						return $ret;
						break;
					
					case 'profiler':
						$profileKey = $Data['profile_key'];
						$Data =& $this->ProfilerData[$profileKey];
						$runtime = ($Data['ends'] - $Data['begins']); // in seconds
						return '<b>Name</b>: '.$Data['description'].'<br><b>Runtime</b>: '.$runtime.'s';
						break;
							
					default:
						return 'incorrect debug data';
						break;
				}
			}
			
			function processTraceArguments(&$traceArgs)
			{
				if(!$traceArgs) return '';
				foreach ($traceArgs as $argID => $argValue)
				{
					if( is_array($argValue) || is_object($argValue) )
					{
						if(is_object($argValue) && !in_array(get_class($argValue),$this->RecursionStack) )
						{	
							// object & not in stack - ok
							array_push($this->RecursionStack, get_class($argValue));
							settype($argValue,'array');
							$this->processTraceArguments($argValue);
							array_pop($this->RecursionStack);
						}
						elseif(is_object($argValue) && in_array(get_class($argValue),$this->RecursionStack) )
						{
							// object & in stack - recursion
							$traceArgs[$argID] = '**** RECURSION ***';
						}
						else
						{
							// normal array here
							$this->processTraceArguments($argValue);
						}
					}
					else
					{
						$traceArgs[$argID] = $this->cutStringForHTML($traceArgs[$argID]);
					}
				}
			}
			
			function cutStringForHTML($string)
			{
				if( strlen($string) > 200 ) $string = substr($string,0,50).' ...';
				return $string;
			}
			
			/**
			 * Format SQL Query using predefined formatting
			 * and highlighting techniques
			 *
			 * @param string $sql
			 * @return string
			 */
			function formatSQL($sql)
			{
				$sql = preg_replace('/(\n|\t| )+/is',' ',$sql);
				$sql = preg_replace('/(CREATE TABLE|DROP TABLE|SELECT|UPDATE|SET|REPLACE|INSERT|DELETE|VALUES|FROM|LEFT JOIN|INNER JOIN|LIMIT|WHERE|HAVING|GROUP BY|ORDER BY) /is', "\n\t$1 ",$sql);
				return $this->highlightString($sql);
			}
			
			function highlightString($string)
			{
				if( dbg_ConstOn('DBG_USE_HIGHLIGHT') )
				{
					$string = str_replace('\\','_no_match_string_',$string);
					$string = highlight_string('<?php '.$string.'?>', true);
					$string = str_replace('_no_match_string_','\\',$string);
					return preg_replace('/&lt;\?(.*)php (.*)\?&gt;/s','$2',$string);
				}
				else
				{
					return $string;
				}
			}
			
			function getFileLink($file, $lineno = 1, $title = '')
			{
				if(!$title) $title = $file;
				$is_mozilla=strpos(strtolower($_SERVER['HTTP_USER_AGENT']),'firefox')!==false?true:false;
				if($is_mozilla)
				{
					return '<a href="file://'.$this->getLocalFile($file).'">'.$title.'</a>';
				}
				else 
				{
					return '<a href="javascript:editFile(\''.$this->getLocalFile($file).'\','.$lineno.');" title="'.$file.'">'.$title.'</a>';		
				}
				
			}
			
			function getLocalFile($remoteFile)
			{
				return str_replace(DOC_ROOT, DBG_LOCAL_BASE_PATH, $remoteFile);	
			}
			
			function appendTrace()
			{
				$trace = debug_backtrace();
				array_shift($trace);
				$this->Data[] = Array('trace' => $trace, 'debug_type' => 'trace');
			}
			
			function appendMemoryUsage($msg, $used=null)
			{
				if (!isset($used)) $used = round(memory_get_usage()/1024);
				$this->appendHTML('<b>Memory usage</b> '.$msg.' '.$used.'Kb');
			}
			
			function appendHTML($html)
			{
				$this->Data[] = Array('html' => $html,'debug_type' => 'html');	
			}
			
			/**
			 * Change debugger info that was already generated before.
			 * Returns true if html was set.
			 *
			 * @param int $index
			 * @param string $html
			 * @param string $type = {'append','prepend','replace'}
			 * @return bool
			 */
			function setHTMLByIndex($index,$html,$type='append')
			{
				if( !isset($this->Data[$index]) || $this->Data[$index]['debug_type'] != 'html' )
				{
					return false;	
				}
				
				switch ($type)
				{
					case 'append':
						$this->Data[$index]['html'] .= '<br>'.$html;
						break;
					case 'prepend':
						$this->Data[$index]['html'] = $this->Data[$index]['html'].'<br>'.$html;
						break;
					case 'replace':
						$this->Data[$index]['html'] = $html;
						break;
				}
				return true;
			}
			
			/**
			 * Move $debugLineCount lines of input from debug output
			 * end to beginning.
			 *
			 * @param int $debugLineCount
			 */
			function moveToBegin($debugLineCount)
			{
				$lines = array_splice($this->Data,count($this->Data)-$debugLineCount,$debugLineCount);
				$this->Data = array_merge($lines,$this->Data);
			}
			
			function moveAfterRow($new_row, $debugLineCount)
			{
				$lines = array_splice($this->Data,count($this->Data)-$debugLineCount,$debugLineCount);
				$rows_before = array_splice($this->Data,0,$new_row,$lines);
				$this->Data = array_merge($rows_before,$this->Data);
			}
			
			function appendRequest()
			{
				$script = $_SERVER['SCRIPT_FILENAME'];
				$this->appendHTML('ScriptName: <b>'.$this->getFileLink($script,1,basename($script)).'</b> (<b>'.dirname($script).'</b>)');
				ob_start();
				?>
				<table border="0" cellspacing="0" cellpadding="0" class="dbg_flat_table" style="width: 100%;">
					<thead style="font-weight: bold;">
						<td width="20">Src</td><td>Name</td><td>Value</td>
					</thead>
				<?php
					foreach($_REQUEST as $key => $value)
					{
						if( !is_array($value) && trim($value) == '' )
						{
							$value = '<b class="debug_error">no value</b>';
						}
						else
						{
							$value = htmlspecialchars(print_r($value, true));
						}
						$src = isset($_GET[$key]) ? 'GE' : (isset($_POST[$key]) ? 'PO' : (isset($_COOKIE[$key]) ? 'CO' : '?') );
						echo '<tr><td>'.$src.'</td><td>'.$key.'</td><td>'.$value.'</td></tr>';
					}
				?> 
				</table>
				<?php
				$this->appendHTML( ob_get_contents() );
				ob_end_clean();
			}
			
			function appendSession()
			{
				if( isset($_SESSION)&&$_SESSION )
				{
					$this->appendHTML('PHP Session: [<b>'.ini_get('session.name').'</b>]');
					$this->dumpVars($_SESSION);
					$this->moveToBegin(2);
				}	
			}
			
			function profileStart($key, $description)
			{
				$timeStamp = $this->getMoment();
				$this->ProfilerData[$key] = Array('begins' => $timeStamp, 'ends' => 5000, 'debuggerRowID' => count($this->Data), 'description' => $description);
				$this->Data[] = array('profile_key' => $key, 'debug_type' => 'profiler');
			}
			
			function profileFinish($key)
			{
				$this->ProfilerData[$key]['ends'] = $this->getMoment();
			}
			
			function profilerAddTotal($total_key, $key=null, $value=null)
			{
				if (!isset($this->ProfilerTotals[$total_key])) {
					$this->ProfilerTotals[$total_key] = 0;
				}
				if (!isset($value)) {
					$value = $this->ProfilerData[$key]['ends'] - $this->ProfilerData[$key]['begins'];
				}
				$this->ProfilerTotals[$total_key] += $value;
			}
			
			function getMoment()
			{
				list($usec, $sec) = explode(' ', microtime()); 
	   			return ((float)$usec + (float)$sec); 
			}
			
			function generateID()
			{
				list($usec, $sec) = explode(" ",microtime());
	
				$id_part_1 = substr($usec, 4, 4);
				$id_part_2 = mt_rand(1,9);
				$id_part_3 = substr($sec, 6, 4);
				$digit_one = substr($id_part_1, 0, 1);
				if ($digit_one == 0) {
					$digit_one = mt_rand(1,9);
					$id_part_1 = ereg_replace("^0","",$id_part_1);
					$id_part_1=$digit_one.$id_part_1;
				}
				return $id_part_1.$id_part_2.$id_part_3;
			}
	
			
			function getErrorNameByCode($errorCode)
			{
				switch($errorCode)
				{
					case E_USER_ERROR:
						return 'Fatal Error';
						break;
						
					case E_WARNING:
					case E_USER_WARNING:
						return 'Warning';
						break;
						
					case E_NOTICE:
					case E_USER_NOTICE:
						return 'Notice';
						break;
					
					case E_STRICT:
					return 'PHP5 Strict';
					break;
					
					default:
						return '';
						break;
				}
			}
			
			/**
			 * Generates report
			 *
			 */
			function printReport($returnResult = false)
			{
				if( dbg_ConstOn('DBG_SKIP_REPORTING') ) return;
				
				$this->profileFinish('script_runtime');
				if( dbg_ConstOn('DBG_ZEND_PRESENT') ) return;
				dbg_safeDefine('DBG_RAISE_ON_WARNINGS',0);
				dbg_safeDefine('DBG_WINDOW_WIDTH', 700);
				
				$this->memoryUsage['debugger_start']=memory_get_usage();
				
				// show php session if any
				$this->appendSession();
				
				// ensure, that 1st line of debug output always is this one:
				$this->appendHTML('<a href="javascript:toggleDebugLayer(27);">Hide Debugger</a>');
				$this->moveToBegin(1);
				
				if ( dbg_ConstOn('DBG_SQL_PROFILE') ) {
					$this->appendHTML('<b>SQL Total time:</b> '.$this->ProfilerTotals['sql']);
				}
				
				if ( dbg_ConstOn('DBG_PROFILE_MEMORY') ) {
					$this->appendHTML('<b>Memory used by Objects:</b> '.round($this->ProfilerTotals['objects']/1024, 2).'Kb');
				}
				
				if ( dbg_ConstOn('DBG_INCLUDED_FILES') ) {
					$files = get_included_files();
					$this->appendHTML('<b>Included files:</b>');
					foreach ($files as $file)
					{
						$this->appendHTML($this->getFileLink($this->getLocalFile($file)).' ('.round(filesize($file)/1024, 2).'Kb)');
					}
				}
				
				if ( dbg_ConstOn('DBG_PROFILE_INCLUDES') ) {
					$this->appendHTML('<b>Included files statistics:</b>'.( dbg_ConstOn('DBG_SORT_INCLUDES_MEM') ? ' (sorted by memory usage)':''));
					$totals = Array( 'mem' => 0, 'time' => 0);
					$totals_configs = Array( 'mem' => 0, 'time' => 0);
					if ( dbg_ConstOn('DBG_SORT_INCLUDES_MEM') ) {
						array_multisort($this->IncludesData['mem'], SORT_DESC, $this->IncludesData['file'], $this->IncludesData['time'], $this->IncludesData['level']);
					}
					foreach ($this->IncludesData['file'] as $key => $file_name) {
						$this->appendHTML(  str_repeat('&nbsp;->&nbsp;', ($this->IncludesData['level'][$key] >= 0 ? $this->IncludesData['level'][$key] : 0)).$file_name.' Mem: '.sprintf("%.4f Kb", $this->IncludesData['mem'][$key]/1024).' Time: '.sprintf("%.4f", $this->IncludesData['time'][$key]));
						if ($this->IncludesData['level'][$key] == 0) {
							$totals['mem'] += $this->IncludesData['mem'][$key];
							$totals['time'] += $this->IncludesData['time'][$key];
						}
						else if ($this->IncludesData['level'][$key] == -1) {
							$totals_configs['mem'] += $this->IncludesData['mem'][$key];
							$totals_configs['time'] += $this->IncludesData['time'][$key];
						}
					}
					$this->appendHTML('<b>Sub-Total classes:</b> '.' Mem: '.sprintf("%.4f Kb", $totals['mem']/1024).' Time: '.sprintf("%.4f", $totals['time']));
					$this->appendHTML('<b>Sub-Total configs:</b> '.' Mem: '.sprintf("%.4f Kb", $totals_configs['mem']/1024).' Time: '.sprintf("%.4f", $totals_configs['time']));
					$this->appendHTML('<span class="error"><b>Grand Total:</b></span> '.' Mem: '.sprintf("%.4f Kb", ($totals['mem']+$totals_configs['mem'])/1024).' Time: '.sprintf("%.4f", $totals['time']+$totals_configs['time']));
					
					
				}
				
				
				$i = 0; $lineCount = count($this->Data);
				ob_start();
				?>
					<style type="text/css">
				
						.dbg_flat_table {
							border-collapse: collapse;
							width: auto;
						}
						
						.dbg_flat_table TD {
							border: 1px solid buttonface;
							padding: 4px;
						}
						
						.debug_layer_table {
							border-collapse: collapse;
							width: <?php echo DBG_WINDOW_WIDTH - 20; ?>px;
						}
						
						.debug_text, .debug_row_even TD, .debug_row_odd TD {
							color: #000000;
							font-family: Verdana;
							font-size: 11px;
							word-wrap: break-word;
						}
						
						.debug_cell {
							border: 1px solid #FF0000;
							padding: 4px;
							word-wrap: break-word;
						}
						
						.debug_row_even {
							background-color: #CCCCFF;
						}
						
						.debug_row_odd {
							background-color: #FFFFCC;
						}
						
						.debug_layer_container {
							left: 2px;
							top: 1px;
							width: <?php echo DBG_WINDOW_WIDTH; ?>px;
							z-index: +1000;
							position: absolute;
							overflow: auto;
							border: 2px solid;
							padding: 3px;
							border-top-color: threedlightshadow;
							border-left-color: threedlightshadow;
							border-right-color: threeddarkshadow;
							border-bottom-color: threeddarkshadow;
							background-color: buttonface;
						}
						
						.debug_layer {
							padding: 0px;
							width: <?php echo DBG_WINDOW_WIDTH - 20; ?>px;
						}
						
						.debug_error {
							color: #FF0000;
						}
					</style>
					<div id="debug_layer" class="debug_layer_container" style="display: none;">
						<div class="debug_layer">
							<table width="100%" cellpadding="0" cellspacing="1" border="0" class="debug_layer_table">
				<?php
				while ($i < $lineCount)
				{
					echo '<tr class="debug_row_'.(($i % 2) ? 'odd' : 'even').'"><td class="debug_cell">'.$this->prepareHTML($i).'</td></tr>';
					$i++;
				}
				?>
							</table>
						</div>
					</div>
					<script language="javascript">
						function getEventKeyCode($e)
						{
							var $KeyCode = 0;
							if($e.keyCode) $KeyCode = $e.keyCode;
							else if($e.which) $KeyCode = $e.which;
							return $KeyCode;
						}
					
						function keyProcessor($e)
						{
							if(!$e) $e = window.event;
							var $KeyCode = getEventKeyCode($e);
							if($KeyCode==123||$KeyCode==27) // F12 or ESC
							{
								toggleDebugLayer($KeyCode);
								$e.cancelBubble = true;
								if($e.stopPropagation) $e.stopPropagation();
							}
						}
						
						function toggleDebugLayer($KeyCode)
						{
							var $isVisible=false;
							var $DebugLayer = document.getElementById('debug_layer');
							if( typeof($DebugLayer) != 'undefined' )
							{
								$isVisible = ($DebugLayer.style.display == 'none')?false:true;
								if(!$isVisible&&$KeyCode==27) return false;
								
								resizeDebugLayer(null);
								$DebugLayer.style.display = $isVisible?'none':'block';
							}
						}
						
						function prepareSizes($Prefix)
						{
							var $ret = '';
							$ret = eval('document.body.'+$Prefix+'Top')+'; ';
							$ret += eval('document.body.'+$Prefix+'Left')+'; ';
							$ret += eval('document.body.'+$Prefix+'Height')+'; ';
							$ret += eval('document.body.'+$Prefix+'Width')+'; ';	
							return $ret;
						}
						
						function resizeDebugLayer($e)
						{
							if(!$e) $e = window.event;
							var $DebugLayer = document.getElementById('debug_layer');
							var $TopMargin = 1;
							if( typeof($DebugLayer) != 'undefined' )
							{
								$DebugLayer.style.top = parseInt(document.body.offsetTop + document.body.scrollTop) + $TopMargin;
								$DebugLayer.style.height = (document.body.clientHeight - $TopMargin - 5)+'px';
//								alert('LH: '+$DebugLayer.style.height);
							}
//							window.parent.status = 'OFFSET: '+prepareSizes('offset')+' | SCROLL: '+prepareSizes('scroll')+' | CLIENT: '+prepareSizes('client');
//							window.parent.status += 'DL Info: '+$DebugLayer.style.top+'; S.AH: '+screen.availHeight;
							return true;
						}
						
						function SetClipboard(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);
							}
	
						}
						
						function showProps($Obj, $Name)
						{
							var $ret = '';
							for($Prop in $Obj)
							{
								$ret += $Name+'.'+$Prop+' = '+$Obj[$Prop]+"\n";
							}
							return $ret;
						}
						
						function editFile($fileName,$lineNo)
						{
							if(!document.all)
							{
								alert('Only works in IE');
								return;
							}
							
							var $editorPath = '<?php echo defined('WINDOWS_EDITOR') ? addslashes(WINDOWS_EDITOR) : '' ?>';
							if($editorPath)
							{
								var $obj = new ActiveXObject("LaunchinIE.Launch");
								$editorPath = $editorPath.replace('%F',$fileName);
								$editorPath = $editorPath.replace('%L',$lineNo);
								$obj.LaunchApplication($editorPath);
							}
							else
							{
								alert('Editor path not defined!');	
							}
						}
						
						function toggleTraceArgs($ArgsLayerID)
						{
							var $ArgsLayer = document.getElementById($ArgsLayerID);
							$ArgsLayer.style.display = ($ArgsLayer.style.display == 'none') ? 'block' : 'none';
						}
						
						
						document.onkeydown = keyProcessor;
						window.onresize = resizeDebugLayer;
						window.onscroll = resizeDebugLayer;
						window.focus();
						if( typeof($isFatalError) != 'undefined' && $isFatalError == 1 || <?php echo DBG_RAISE_ON_WARNINGS; ?> )
						{
							toggleDebugLayer();
						}
						if( typeof($isFatalError) != 'undefined' && $isFatalError == 1)
						{
							document.getElementById('debug_layer').scrollTop = 10000000;
						}
					</script>
				<?php
				$this->memoryUsage['debugger_finish']=memory_get_usage();
				$this->memoryUsage['print_report']=$this->memoryUsage['debugger_finish']-$this->memoryUsage['debugger_start'];
				$this->memoryUsage['total']=$this->memoryUsage['print_report']+$this->memoryUsage['error_handling'];
				$this->memoryUsage['application']=memory_get_usage()-$this->memoryUsage['total'];
				if($returnResult)
				{
					$ret = ob_get_contents();
					ob_clean();
					if( dbg_ConstOn('DBG_SHOW_MEMORY_USAGE') ) $ret.=$this->getMemoryUsageReport();
					return $ret;
				}
				else
				{
					ob_end_flush();
					if( dbg_ConstOn('DBG_SHOW_MEMORY_USAGE') ) echo $this->getMemoryUsageReport();
				}
			}
			
			/**
			 * Format's memory usage report by debugger
			 *
			 * @return string
			 * @access private
			 */
			function getMemoryUsageReport()
			{
				$info=Array('<a href="javascript:self.location.reload()">printReport</a>'=>'print_report',
							'saveError'=>'error_handling',
							'Total'=>'total',
							'Application'=>'application');
				$ret=Array();
				foreach($info as $title => $value_key)
				{
					$ret[]='<tr><td>'.$title.':</td><td><b>'.$this->formatSize($this->memoryUsage[$value_key]).'</b></td></tr>';
				}
				return '<table class="dbg_flat_table">'.implode('',$ret).'</table>';
			}
			
			
			/**
			 * User-defined error handler
			 *
			 * @param int $errno
			 * @param string $errstr
			 * @param string $errfile
			 * @param int $errline
			 * @param array $errcontext
			 */
			function saveError($errno, $errstr, $errfile = '', $errline = '', $errcontext = '')
			{
				$memory_used=Array();
				$memory_used['begin']=memory_get_usage();
				
				$errorType = $this->getErrorNameByCode($errno);
				if(!$errorType)
				{
					trigger_error('Unknown error type ['.$errno.']', E_USER_ERROR);
					return false;
				}
				
				if( dbg_ConstOn('DBG_IGNORE_STRICT_ERRORS') && defined('E_STRICT') && ($errno == E_STRICT) ) return;	
				
				$long_id_pos=strrpos($errstr,'#');
				if($long_id_pos!==false)
				{
					// replace short message with long one (due triger_error limitations on message size)
					$long_id=substr($errstr,$long_id_pos+1,strlen($errstr));
					$errstr=$this->longErrors[$long_id];	
					unset($this->longErrors[$long_id]);
				}
				
				
				/*in /www/kostja/in-commerce4/kernel/kernel4/parser/construct_tags.php(177) : runtime-created function on line 
				
				[PRE-PARSED block, $line 13]: Undefined variable: IdField*/
				
				if( strpos($errfile,'runtime-created') !== false ) {
					$errfile = ' PRE-PARSED block <b>'.$this->CurrentPreParsedBlock.'</b> ';
				}
				
				if( strpos($errfile,'eval()\'d code') !== false )
				{
					$errstr = '[<b>EVAL</b>, line <b>'.$errline.'</b>]: '.$errstr;
					$tmpStr = $errfile;
					$pos = strpos($tmpStr,'(');
					$errfile = substr($tmpStr,0,$pos);
					$pos++;
					$errline = substr($tmpStr,$pos,strpos($tmpStr,')',$pos)-$pos);
				}
				// if($this->TraceNextError || $errno == E_USER_ERROR)
				if($this->TraceNextError)
				{
					$this->appendTrace();	
					$this->TraceNextError=false;
				}
				$this->Data[] = Array('no' => $errno, 'str' => $errstr, 'file' => $errfile, 'line' => $errline, 'context' => $errcontext, 'debug_type' => 'error');
				$memory_used['end']=memory_get_usage();
				$this->memoryUsage['error_handling']+=$memory_used['end']-$memory_used['begin'];
				if( substr($errorType,0,5) == 'Fatal')
				{
					echo '<script language="javascript">var $isFatalError = 1;</script>';
					exit;
				}
			}
			
			function saveToFile($msg)
			{
				$fp = fopen($_SERVER['DOCUMENT_ROOT'].'/vb_debug.txt', 'a');
				fwrite($fp,$msg."\n");
				fclose($fp);
			}
			
			/**
			 * Formats file/memory size in nice way
			 *
			 * @param int $bytes
			 * @return string
			 * @access public
			 */
			function formatSize($bytes)
			{
				if ($bytes >= 1099511627776) {
					$return = round($bytes / 1024 / 1024 / 1024 / 1024, 2);
					$suffix = "TB";
				} elseif ($bytes >= 1073741824) {
					$return = round($bytes / 1024 / 1024 / 1024, 2);
					$suffix = "GB";
				} elseif ($bytes >= 1048576) {
					$return = round($bytes / 1024 / 1024, 2);
					$suffix = "MB";
				} elseif ($bytes >= 1024) {
					$return = round($bytes / 1024, 2);
					$suffix = "KB";
				} else {
					$return = $bytes;
					$suffix = "Byte";
				}
				$return .= ' '.$suffix;
				return $return;
			}
			
		}
	
		if( !function_exists('memory_get_usage') )
		{
			function memory_get_usage(){ return -1;	}
		}
		
		$debugger = new Debugger();
		if(dbg_ConstOn('DBG_HANDLE_ERRORS')) set_error_handler( array(&$debugger,'saveError')  );
		if(dbg_ConstOn('DBG_USE_SHUTDOWN_FUNC')) {
			register_shutdown_function( array(&$debugger,'printReport') );
		}
	}
?>