<?php
/**
 * @copyright NetMonsters <team@netmonsters.ru>
 * @link http://netmonsters.ru
 * @package Majestic
 * @subpackage exception
 * @since 2010-02-26
 * @version SVN: $Id$
 * @filesource $URL$
 */

class ErrorHandler
{

    static public function init()
    {
        set_error_handler(array('ErrorHandler', 'error_handler'));
    }

    static public function error_handler($errno, $errstr, $errfile, $errline)
    {
        ob_clean();
        throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
        return false;
    }

    static protected function getSource($file, $hiline)
    {
        $code = array();
        $i = 0;
        foreach (file($file) as $line) {
            $i++;
            if ($i >= $hiline - 10 && $i <= $hiline + 10) {
                if ($i == $hiline) {
                    $code[] = '<tr class="error"><th>' . $i . '</th><td><span class="specific">' . htmlentities($line, ENT_QUOTES, 'UTF-8') . '</span></td></tr>';
                } else {
                    $code[] = '<tr><th>' . $i . '</th><td>' . htmlentities($line, ENT_QUOTES, 'UTF-8') . '</td></tr>';
                }
            }
            if ($i > $hiline + 10) {
                break;
            }
        }
        return implode('', $code);
    }

    static protected function wrapArray($array, $name)
    {
        if (!$array) {
            return '<p>No ' . $name . ' data</p>';
        }
        $text = '<table class="req"><thead><tr><th>Variable</th><th>Value</th></tr></thead><tbody>';
        foreach ($array as $key => $value) {
            if (is_array($value) || is_object($value)) {
                $value = print_r($value, true);
            }
            $value = ($value) ? htmlentities($value, ENT_QUOTES, 'UTF-8') : '&nbsp;';
            $text .= '<tr><td>' . $key . '</td><td class="code"><div>' . $value . '</div></td></tr>';
        }
        $text .= '</tbody></table>';
        return $text;
    }

    static protected function wrapTrace($trace)
    {
        return '<code>' . nl2br($trace) . '</code>';
    }

    /**
     * @param Exception $exception
     */
    static public function showDebug($exception)
    {
        ob_clean();
        $class = get_class($exception);

        $method = Env::Server('REQUEST_METHOD', '');
        $uri = Env::getRequestUri();
        $source = self::getSource($exception->getFile(), $exception->getLine());
        $time = date('r', Env::Server('REQUEST_TIME', time()));

        $trace = nl2br($exception->getTraceAsString());

        $get = self::wrapArray(Env::Get(), 'GET');
        $post = self::wrapArray(Env::Post(), 'POST');
        $session = self::wrapArray(Session::get(), 'SESSION');
        $files = self::wrapArray(Env::Files(), 'FILES');
        $cookies = self::wrapArray(Env::Cookie(), 'COOKIE');
        $server = self::wrapArray(Env::Server(), 'SERVER');

        $message = <<<EOD
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
     <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
     <title>{$class} at {$uri}</title>
     <style type="text/css">
        html * { padding:0; margin:0; }
        body * { padding:10px 20px; }
        body * * { padding:0; }
        body { font:small sans-serif; }
        body>div { border-bottom:1px solid #ddd; }
        h1 { font-weight:normal; }
        h2 { margin-bottom:.8em; }
        h2 span { font-size:80%; color:#666; font-weight:normal; }
        h3 { margin:1em 0 .5em 0; }
        h4 { margin:0 0 .5em 0; font-weight: normal; }
        table { border:1px solid #ccc; border-collapse: collapse; width:100%; background:white; }
        tbody td, tbody th { vertical-align:top; padding:2px 3px; }
        thead th { padding:1px 6px 1px 3px; background:#fefefe; text-align:left; font-weight:normal; font-size:11px; border:1px solid #ddd; }
        tbody th { width:12em; text-align:right; color:#666; padding-right:.5em; }
        table.vars { margin:5px 0 2px 40px; }
        table.vars td, table.req td { font-family:monospace; }
        table td.code { width:100%; }
        table td.code div { overflow:hidden; }
        table.source th { color:#666; }
        table.source td { font-family:monospace; white-space:pre; border-bottom:1px solid #eee; }
        ul.traceback { list-style-type:none; }
        ul.traceback li.frame { margin-bottom:1em; }
        div.context { margin: 10px 0; }
        div.context ol { padding-left:30px; margin:0 10px; list-style-position: inside; }
        div.context ol li { font-family:monospace; white-space:pre; color:#666; cursor:pointer; }
        div.context ol.context-line li { color:black; background-color:#ccc; }
        div.context ol.context-line li span { float: right; }
        div.commands { margin-left: 40px; }
        div.commands a { color:black; text-decoration:none; }
        #summary { background: #ffc; }
        #summary h2 { font-weight: normal; color: #666; }
        #explanation { background:#eee; }
        #source{ background:#f6f6f6; }        
        #traceback { background:#eee; }
        #requestinfo { background:#f6f6f6; padding-left:120px; }
        #summary table { border:none; background:transparent; }
        #requestinfo h2, #requestinfo h3 { position:relative; margin-left:-100px; }
        #requestinfo h3 { margin-bottom:-1em; }
        .error { background: #ffc; }
        .specific { color:#cc3300; font-weight:bold; }
        h2 span.commands { font-size:.7em;}
        span.commands a:link {color:#5E5694;}
        pre.exception_value { font-family: sans-serif; color: #666; font-size: 1.5em; margin: 10px 0 10px 0; }
    </style>
</head>
<body>
    <div id="summary">
      <h1>{$class} at {$uri}</h1>
      <pre class="exception_value">{$exception->getMessage()}</pre>
      <table class="meta">
        <tbody>
            <tr><th>Request Method:</th><td>{$method}</td></tr>
            <tr><th>Exception Type:</th><td>{$class}</td></tr>
            <tr><th>Exception Message:</th><td><pre>{$exception->getMessage()}</pre></td></tr>
            <tr><th>Exception Location:</th><td>{$exception->getFile()}, line {$exception->getLine()}</td></tr>
            <tr><th>Server time:</th><td>{$time}</td></tr>
        </tbody>
      </table>
    </div>

    <div id="source">
        <h2>Context</h2>
        <p>In file <code>{$exception->getFile()}</code>, error at line <strong>{$exception->getLine()}</strong></p>
        <h3>{$exception->getMessage()}</h3>
        <table class="source cut-top">
            <tbody>{$source}</tbody>
        </table>
    </div>
    
    <div id="traceback">
        <h2>Traceback</h2>
        <div id="browserTraceback"><code>{$trace}</code></div>
    </div>

    <div id="requestinfo">
        <h2>Request information</h2>
        <h3 id="get-info">GET</h3>
        {$get}
        <h3 id="post-info">POST</h3>
        {$post}
        <h3 id="session-info">SESSION</h3>
        {$session}
        <h3 id="files-info">FILES</h3>
        {$files}
        <h3 id="cookie-info">COOKIES</h3>
        {$cookies}
        <h3 id="meta-info">SERVER</h3>
        {$server}
        <h3 id="settings-info">Settings</h3>
        <p>todo</p>
    </div>
    
    <div id="explanation">
        <p>You're seeing this error because you have defined constant <code>DEBUG = True</code> in your config file. Change that to <code>False</code>, and it will display a standard 500 page.</p>
    </div>    
</body>
</html>
EOD;
        return $message;
    }
}