' . DIRECTORY_SEPARATOR;
			}
		}
		$aRpl[$_SERVER['DOCUMENT_ROOT']] = '${DocumentRoot}';
		$aRpl[str_replace('/', DIRECTORY_SEPARATOR, $_SERVER['DOCUMENT_ROOT'])] = '${DocumentRoot}';
		$aRpl[PRADO_DIR . DIRECTORY_SEPARATOR] = '${PradoFramework}' . DIRECTORY_SEPARATOR;
		if(isset($aRpl[DIRECTORY_SEPARATOR])) unset($aRpl[DIRECTORY_SEPARATOR]);
		$aRpl = array_reverse($aRpl, true);
		return str_replace(array_keys($aRpl), $aRpl, $value);
	}
	/**
	 * Displays error to the client user.
	 * THttpException and errors happened when the application is in Debug
	 * mode will be displayed to the client user.
	 * @param integer response status code
	 * @param Exception exception instance
	 */
	protected function handleExternalError($statusCode,$exception)
	{
		if(!($exception instanceof THttpException))
			error_log($exception->__toString());
		$content=$this->getErrorTemplate($statusCode,$exception);
		$serverAdmin=isset($_SERVER['SERVER_ADMIN'])?$_SERVER['SERVER_ADMIN']:'';
		$isDebug = $this->getApplication()->getMode()===TApplicationMode::Debug;
		$errorMessage = $exception->getMessage();
		if($isDebug)
			$version=$_SERVER['SERVER_SOFTWARE'].' PRADO/'.Prado::getVersion();
		else
		{
			$version='';
			$errorMessage = self::hideSecurityRelated($errorMessage, $exception);
		}
		$tokens=array(
			'%%StatusCode%%' => "$statusCode",
			'%%ErrorMessage%%' => htmlspecialchars($errorMessage),
			'%%ServerAdmin%%' => $serverAdmin,
			'%%Version%%' => $version,
			'%%Time%%' => @strftime('%Y-%m-%d %H:%M',time())
		);
		$this->getApplication()->getResponse()->setStatusCode($statusCode, $isDebug ? $exception->getMessage() : null);
		echo strtr($content,$tokens);
	}
	/**
	 * Handles error occurs during error handling (called recursive error).
	 * THttpException and errors happened when the application is in Debug
	 * mode will be displayed to the client user.
	 * Error is displayed without using existing template to prevent further errors.
	 * @param Exception exception instance
	 */
	protected function handleRecursiveError($exception)
	{
		if($this->getApplication()->getMode()===TApplicationMode::Debug)
		{
			echo "Recursive Error\n";
			echo "Recursive Error
\n";
			echo "".$exception->__toString()."
\n";
			echo "";
		}
		else
		{
			error_log("Error happened while processing an existing error:\n".$exception->__toString());
			header('HTTP/1.0 500 Internal Error');
		}
	}
	/**
	 * Displays exception information.
	 * Exceptions are displayed with rich context information, including
	 * the call stack and the context source code.
	 * This method is only invoked when application is in Debug mode.
	 * @param Exception exception instance
	 */
	protected function displayException($exception)
	{
		if(php_sapi_name()==='cli')
		{
			echo $exception->getMessage()."\n";
			echo $exception->getTraceAsString();
			return;
		}
		if($exception instanceof TTemplateException)
		{
			$fileName=$exception->getTemplateFile();
			$lines=empty($fileName)?explode("\n",$exception->getTemplateSource()):@file($fileName);
			$source=$this->getSourceCode($lines,$exception->getLineNumber());
			if($fileName==='')
				$fileName='---embedded template---';
			$errorLine=$exception->getLineNumber();
		}
		else
		{
			if(($trace=$this->getExactTrace($exception))!==null)
			{
				$fileName=$trace['file'];
				$errorLine=$trace['line'];
			}
			else
			{
				$fileName=$exception->getFile();
				$errorLine=$exception->getLine();
			}
			$source=$this->getSourceCode(@file($fileName),$errorLine);
		}
		if($this->getApplication()->getMode()===TApplicationMode::Debug)
			$version=$_SERVER['SERVER_SOFTWARE'].' PRADO/'.Prado::getVersion();
		else
			$version='';
		$tokens=array(
			'%%ErrorType%%' => get_class($exception),
			'%%ErrorMessage%%' => $this->addLink(htmlspecialchars($exception->getMessage())),
			'%%SourceFile%%' => htmlspecialchars($fileName).' ('.$errorLine.')',
			'%%SourceCode%%' => $source,
			'%%StackTrace%%' => htmlspecialchars($exception->getTraceAsString()),
			'%%Version%%' => $version,
			'%%Time%%' => @strftime('%Y-%m-%d %H:%M',time())
		);
		$content=$this->getExceptionTemplate($exception);
		echo strtr($content,$tokens);
	}
	/**
	 * Retrieves the template used for displaying internal exceptions.
	 * Internal exceptions will be displayed with source code causing the exception.
	 * This occurs when the application is in debug mode.
	 * @param Exception the exception to be displayed
	 * @return string the template content
	 */
	protected function getExceptionTemplate($exception)
	{
		$lang=Prado::getPreferredLanguage();
		$exceptionFile=Prado::getFrameworkPath().'/Exceptions/templates/'.self::EXCEPTION_FILE_NAME.'-'.$lang.'.html';
		if(!is_file($exceptionFile))
			$exceptionFile=Prado::getFrameworkPath().'/Exceptions/templates/'.self::EXCEPTION_FILE_NAME.'.html';
		if(($content=@file_get_contents($exceptionFile))===false)
			die("Unable to open exception template file '$exceptionFile'.");
		return $content;
	}
	/**
	 * Retrieves the template used for displaying external exceptions.
	 * External exceptions are those displayed to end-users. They do not contain
	 * error source code. Therefore, you might want to override this method
	 * to provide your own error template for displaying certain external exceptions.
	 * The following tokens in the template will be replaced with corresponding content:
	 * %%StatusCode%% : the status code of the exception
	 * %%ErrorMessage%% : the error message (HTML encoded).
	 * %%ServerAdmin%% : the server admin information (retrieved from Web server configuration)
	 * %%Version%% : the version information of the Web server.
	 * %%Time%% : the time the exception occurs at
	 *
	 * @param integer status code (such as 404, 500, etc.)
	 * @param Exception the exception to be displayed
	 * @return string the template content
	 */
	protected function getErrorTemplate($statusCode,$exception)
	{
		$base=$this->getErrorTemplatePath().DIRECTORY_SEPARATOR.self::ERROR_FILE_NAME;
		$lang=Prado::getPreferredLanguage();
		if(is_file("$base$statusCode-$lang.html"))
			$errorFile="$base$statusCode-$lang.html";
		else if(is_file("$base$statusCode.html"))
			$errorFile="$base$statusCode.html";
		else if(is_file("$base-$lang.html"))
			$errorFile="$base-$lang.html";
		else
			$errorFile="$base.html";
		if(($content=@file_get_contents($errorFile))===false)
			die("Unable to open error template file '$errorFile'.");
		return $content;
	}
	private function getExactTrace($exception)
	{
		$trace=$exception->getTrace();
		$result=null;
		// if PHP exception, we want to show the 2nd stack level context
		// because the 1st stack level is of little use (it's in error handler)
		if($exception instanceof TPhpErrorException)
			$result=isset($trace[0]['file'])?$trace[0]:$trace[1];
		else if($exception instanceof TInvalidOperationException)
		{
			// in case of getter or setter error, find out the exact file and row
			if(($result=$this->getPropertyAccessTrace($trace,'__get'))===null)
				$result=$this->getPropertyAccessTrace($trace,'__set');
		}
		if($result!==null && strpos($result['file'],': eval()\'d code')!==false)
			return null;
		return $result;
	}
	private function getPropertyAccessTrace($trace,$pattern)
	{
		$result=null;
		foreach($trace as $t)
		{
			if(isset($t['function']) && $t['function']===$pattern)
				$result=$t;
			else
				break;
		}
		return $result;
	}
	private function getSourceCode($lines,$errorLine)
	{
		$beginLine=$errorLine-self::SOURCE_LINES>=0?$errorLine-self::SOURCE_LINES:0;
		$endLine=$errorLine+self::SOURCE_LINES<=count($lines)?$errorLine+self::SOURCE_LINES:count($lines);
		$source='';
		for($i=$beginLine;$i<$endLine;++$i)
		{
			if($i===$errorLine-1)
			{
				$line=htmlspecialchars(sprintf("%04d: %s",$i+1,str_replace("\t",'    ',$lines[$i])));
				$source.="".$line."
";
			}
			else
				$source.=htmlspecialchars(sprintf("%04d: %s",$i+1,str_replace("\t",'    ',$lines[$i])));
		}
		return $source;
	}
	private function addLink($message)
	{
		$baseUrl='http://pradosoft.github.io/docs/manual/class-';
		return preg_replace('/\b(T[A-Z]\w+)\b/',"\${1}",$message);
	}
}