/**
 * Prints out the thrown exception in a more readable manner for a person using
 * a web browser.
 *
 * @param	SpoonException $exception
 */
function exceptionHandler($exception)
{
    // fetch trace stack
    $trace = $exception->getTrace();
    // specific name
    $name = method_exists($exception, 'getName') ? $exception->getName() : get_class($exception);
    // spoon type exception
    if (method_exists($exception, 'getName') && strtolower(substr($exception->getName(), 0, 5)) == 'spoon' && $exception->getCode() != 0) {
        $documentation = '&raquo; <a href="http://www.spoon-library.com/exceptions/detail/' . $exception->getCode() . '">view documentation</a>';
    }
    // request uri?
    if (!isset($_SERVER['HTTP_HOST'])) {
        $_SERVER['HTTP_HOST'] = '';
    }
    if (!isset($_SERVER['REQUEST_URI'])) {
        $_SERVER['REQUEST_URI'] = '';
    }
    if (!isset($_SERVER['REQUEST_METHOD'])) {
        $_SERVER['REQUEST_METHOD'] = '';
    }
    // user agent
    $userAgent = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '<i>(Unknown)</i>';
    // generate output
    $output = '
	<html>
		<head>
			<title>' . $name . '</title>
		</head>
		<body style="background-color: #F2F2F2; color: #0000000, font-family: Verdana, Tahoma, Arial; font-size 10px; margin: 0; padding: 0;">
			<table width="100%">
				<tr>
					<td style="vertical-align: top; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">&nbsp;</td>
					<td style="width: 550px">
						<table width="550px;">
							<tr>
								<td style="background-color: #EEEEEE; border: 1px solid #B2B2B2;">
									<h1 style="font-size: 12px; margin: 5px 5px 12px 5px; padding: 0 0 5px 0; color: #000000; font-family: Verdana, Tahoma, Arial; border-bottom: 1px solid #999999;">' . $name . ' &raquo; Main</h1>
									<table width="550px">
										<tr>
											<th width="110px" style="vertical-align: top; text-align: left; font-weight: 700; padding: 0 0 0 10px; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">Message</th>
											<td style="vertical-align: top; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">' . $exception->getMessage() . '</td>
										</tr>
										<tr>
											<th width="110px" style="vertical-align: top; text-align: left; font-weight: 700; padding: 0 0 0 10px; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">File</th>
											<td style="vertical-align: top; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">' . dimCommonPathPrefix($exception->getFile()) . '</td>
										</tr>
										<tr>
											<th width="110px" style="vertical-align: top; text-align: left; font-weight: 700; padding: 0 0 0 10px; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">Line</th>
											<td style="vertical-align: top; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">' . $exception->getLine() . '</td>
										</tr>
										<tr>
											<th width="110px" style="vertical-align: top; text-align: left; font-weight: 700; padding: 0 0 0 10px; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">Date</th>
											<td style="vertical-align: top; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">' . date('r') . '</td>
										</tr>
										<tr>
											<th width="110px" style="vertical-align: top; text-align: left; font-weight: 700; padding: 0 0 0 10px; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">URL</th>
											<td style="vertical-align: top; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">' . "\n";
    // request URL
    $output .= '							<a href="http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] . '">http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] . '</a>' . "\n";
    $output .= '						</td>
										</tr>
										<tr>
											<th width="110px" style="vertical-align: top; text-align: left; font-weight: 700; padding: 0 0 0 10px; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">Referring URL</th>
											<td style="vertical-align: top; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">' . "\n";
    // referring URL
    if (isset($_SERVER['HTTP_REFERER']) && $_SERVER['HTTP_REFERER'] != '') {
        $output .= '						<a href="' . $_SERVER['HTTP_REFERER'] . '">' . $_SERVER['HTTP_REFERER'] . '</a>' . "\n";
    } else {
        $output .= '						<i>(Unknown)</i>' . "\n";
    }
    $output .= '						</td>
										</tr>
										<tr>
											<th width="110px" style="vertical-align: top; text-align: left; font-weight: 700; padding: 0 0 0 10px; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">Request Method</th>
											<td style="vertical-align: top; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">' . $_SERVER['REQUEST_METHOD'] . '</td>
										</tr>
										<tr>
											<th width="110px" style="vertical-align: top; text-align: left; font-weight: 700; padding: 0 0 0 10px; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">User-agent</th>
											<td style="vertical-align: top; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">' . $userAgent . '</td>
										</tr>';
    // no documentation ?
    if (isset($documentation)) {
        $output .= '				<tr>
											<th width="110px" style="vertical-align: top; text-align: left; font-weight: 700; padding: 0 0 0 10px; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">Documentation</th>
											<td style="vertical-align: top; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">' . $documentation . '</td>
										</tr>';
    }
    // we know about the last error
    if (error_get_last() !== null) {
        // define message
        $error = error_get_last();
        // show output
        $output .= '				<tr>
											<th width="110px" style="vertical-align: top; text-align: left; font-weight: 700; padding: 0 0 0 10px; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">PHP error</th>
											<td style="vertical-align: top; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">' . $error['message'] . '</td>
										</tr>';
    }
    $output .= '				</table>
								</td>
							</tr>
							<tr>
								<td style="vertical-align: top; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">&nbsp;</td>
							</tr>
							<!-- stack -->
							<tr>
								<td style="background-color: #EEEEEE; border: 1px solid #B2B2B2;">
									<h1 style="font-size: 12px; margin: 5px 5px 12px 5px; padding: 0 0 5px 0; color: #000000; font-family: Verdana, Tahoma, Arial; border-bottom: 1px solid #999999;">' . $name . ' &raquo; Trace</h1>
									<table width="550px;">' . "\n";
    // trace has items
    if (count($exception->getTrace()) != 0) {
        // fetch entire stack
        $entireTraceStack = $exception->getTrace();
        // loop elements
        foreach ($entireTraceStack as $traceStack) {
            // open defintion list
            $output .= '			<tr>
											<td style="vertical-align: top; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">
												<table width="550px;" style="border-top: 1px dotted; padding-top: 1ex;">
													<tr>
														<th width="110px" style="vertical-align: top; text-align: left; font-weight: 700; padding: 0 0 0 10px; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">File</th>
														<td style="vertical-align: top; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">' . (isset($traceStack['file']) ? dimCommonPathPrefix($traceStack['file']) : '<i>(Unknown)</i>') . '
														</td>
													</tr>
													<tr>
														<th width="110px" style="vertical-align: top; text-align: left; font-weight: 700; padding: 0 0 0 10px; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">Line</th>
														<td style="vertical-align: top; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">' . (isset($traceStack['line']) ? $traceStack['line'] : '<i>(Unknown)</i>') . '
														</td>
													</tr>';
            // class & function
            if (isset($traceStack['class'])) {
                $docUrl = 'http://www.google.com/search?btnI=&ie=utf-8&sourceid=navclient&q=' . urlencode(sprintf('site:php.net/manual OR site:www.spoon-library.com/docs class "%s"', $traceStack['class']));
                $link = sprintf('<a href="%s">%s</a>', htmlspecialchars($docUrl), htmlspecialchars($traceStack['class']));
                $output .= '					<tr>
														<th width="110px" style="vertical-align: top; text-align: left; font-weight: 700; padding: 0 0 0 10px; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">Class</th>
														<td style="vertical-align: top; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">' . $link . '</td>
													</tr>';
            }
            if (isset($traceStack['function'])) {
                $docUrl = isset($traceStack['class']) ? 'http://www.google.com/search?btnI=&ie=utf-8&sourceid=navclient&q=' . urlencode(sprintf('site:php.net/manual OR site:www.spoon-library.com/docs "%s::%s"', $traceStack['class'], $traceStack['function'])) : 'http://www.google.com/search?btnI=&ie=utf-8&sourceid=navclient&q=' . urlencode(sprintf('site:php.net/manual OR site:www.spoon-library.com/docs "%s"', $traceStack['function']));
                $link = sprintf('<a href="%s">%s</a>', htmlspecialchars($docUrl), htmlspecialchars($traceStack['function']));
                $output .= '					<tr>
														<th width="110px" style="vertical-align: top; text-align: left; font-weight: 700; padding: 0 0 0 10px; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">Function</th>
														<td style="vertical-align: top; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">' . $link . '</td>
													</tr>';
            }
            // function arguments
            if (isset($traceStack['args']) && count($traceStack['args']) != 0) {
                // argument title
                $output .= '					<tr>
														<th width="110px" style="vertical-align: top; text-align: left; font-weight: 700; padding: 0 0 0 10px; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">Argument(s)</th>
														<td style="vertical-align: top; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">
															<pre style="font-family: Courier; margin-bottom: 10px;">' . exceptionHandlerDumper($traceStack['args']) . '</pre>
														</td>
													</tr>';
            }
            // close defintion list
            $output .= '					</table>
											</td>
										</tr>';
        }
    } else {
        $output .= '				<tr>
											<td style="vertical-align: top; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">No trace available.</td>
										</tr>';
    }
    // output the superglobal variables, if any
    $hasVars = false;
    foreach (array('GET', 'POST', 'COOKIE', 'FILES') as $superGlobal) {
        $hasVars |= count($GLOBALS['_' . $superGlobal]);
    }
    if ($hasVars) {
        $output .= '				</table>
									</td>
								<tr>
								<tr>
									<td style="vertical-align: top; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">&nbsp;</td>
								</tr>
								<!-- variables -->
								<tr>
									<td style="background-color: #EEEEEE; border: 1px solid #B2B2B2;">
										<h1 style="font-size: 12px; margin: 5px 5px 12px 5px; padding: 0 0 5px 0; color: #000000; font-family: Verdana, Tahoma, Arial; border-bottom: 1px solid #999999;">' . $name . ' &raquo; Variables</h1>
										<table width="550px;">' . "\n";
        foreach (array('GET', 'POST', 'COOKIE', 'FILES') as $superGlobal) {
            if (!empty($GLOBALS['_' . $superGlobal])) {
                $output .= '				<tr>
													<th width="110px" style="vertical-align: top; text-align: left; font-weight: 700; padding: 0 10px 0 10px; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">$_' . $superGlobal . '</th>
													<td style="vertical-align: top; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">
														<pre style="font-family: Courier; margin-bottom: 10px;">' . exceptionHandlerDumper($GLOBALS['_' . $superGlobal]) . '</pre>
													</td>
												</tr>' . "\n";
            }
        }
    }
    // continue output generation
    $output .= '				</table>
								</td>
							</tr>
						</table>
					</td>
					<td style="vertical-align: top; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">&nbsp;</td>
				</tr>
			</table>
		</body>
	</html>
	';
    // obfuscate
    if (method_exists($exception, 'getObfuscate') && count($exception->getObfuscate()) != 0) {
        $output = str_replace($exception->getObfuscate(), '***', $output);
    }
    // custom callback?
    if (Spoon::getExceptionCallback() != '') {
        // function
        if (!strpos(Spoon::getExceptionCallback(), '::')) {
            // function actually has been defined
            if (function_exists(Spoon::getExceptionCallback())) {
                call_user_func_array(Spoon::getExceptionCallback(), array($exception, $output));
            } else {
                exit('The exception callback function (' . Spoon::getExceptionCallback() . ') could not be found.');
            }
        } else {
            // method
            $method = explode('::', Spoon::getExceptionCallback());
            // 2 parameters and exists
            if (count($method) == 2 && is_callable(array($method[0], $method[1]))) {
                call_user_func_array(array($method[0], $method[1]), array($exception, $output));
            } else {
                exit('The exception callback function (' . Spoon::getExceptionCallback() . ') cound not be found.');
            }
        }
    } else {
        // on CLI we have no use for 2000 lines long report, show short info
        if (Spoon::inCli()) {
            echo $name . "\n";
            echo 'Message: ' . $exception->getMessage() . "\n";
            echo 'File: ' . $exception->getFile() . "\n";
            echo 'Line: ' . $exception->getLine() . "\n";
        } elseif (Spoon::getDebug()) {
            echo $output;
        } else {
            echo Spoon::getDebugMessage();
        }
    }
    // mail it?
    if (Spoon::getDebugEmail() != '') {
        // e-mail headers
        $headers = "MIME-Version: 1.0\n";
        $headers .= "Content-type: text/html; charset=iso-8859-15\n";
        $headers .= "X-Priority: 3\n";
        $headers .= "X-MSMail-Priority: Normal\n";
        $headers .= "X-Mailer: SpoonLibrary Webmail\n";
        $headers .= "From: Spoon Library <*****@*****.**>\n";
        // send email
        @mail(Spoon::getDebugEmail(), 'Exception Occured', $output, $headers);
    }
    // stop script execution
    exit;
}