<?php
/**
 * class.debug.php
 */
class Debug
{
    private static $instance;
    public static function getInstance ()
    {
        if (null === self::$instance) {
            self::$instance = new self();
        }
        return self::$instance;
    }
    private function __construct ()
    {
        set_error_handler('Debug::ErrorHandler');
        set_exception_handler('Debug::ExceptionHandler');
    }
    public static function ErrorHandler ($code, $string, $file, $line)
    {
        $result = "<table cellpadding='5' border='1' style='margin: 15px; font-family: Trebuchet MS; font-color: #000; font-size: 9pt;'>";
        $result .= "<tr><th colspan='2'>Error handler</td></tr>";
        $result .= "<tr><td>Code:</td><td>$code</td></tr>";
        $result .= "<tr><td>Error:</td><td>$string</td></tr>";
        $result .= "<tr><td>File:</td><td>$file</td></tr>";
        $result .= "<tr><td>Line:</td><td>$line</td></tr>";
        print $result;
        print self::getBacktrace();
        return true;
    }
    public static function ExceptionHandler ($e)
    {
        $result = "<table cellpadding='5' border='1' style='margin: 15px; font-family: Trebuchet MS; font-color: #000; font-size: 9pt;'>";
        $result .= "<tr><th colspan='2'>Exception handler</td></tr>";
        $result .= "<tr><td>Code:</td><td>" . $e->getCode() . "</td></tr>";
        $result .= "<tr><td>Message:</td><td>" . $e->getMessage() . "</td></tr>";
        $result .= "<tr><td>File:</td><td>" . $e->getFile() . "</td></tr>";
        $result .= "<tr><td>Line:</td><td>" . $e->getLine() . "</td></tr>";
        $result .= "<tr><td>Code:</td><td>";
        $result .= self::getCode($e->getFile(), $e->getLine()) . "</td></tr>";
        print $result;
        return true;
    }
    private static function getBacktrace ($depth = 1)
    {
        $trace = debug_backtrace();
        for ($i = 0; $i < $depth; $i ++) {
            array_shift($trace);
        }
        $result = "<table border='1' cellpadding='5' style='margin: 15px; font-family: Trebuchet MS; font-color: #000; font-size: 9pt;'>";
        $result .= "<tr><th colspan='3'>Backtrace</td></tr>";
        foreach ($trace as $level => $data) {
            $result .= "<tr><td rowspan='3'>#" . $level . "</td><td>";
            if (isset($data['class'])) {
                $result .= $data['class'] . $data['type'];
            }
            if (isset($data['function'])) {
                $result .= $data['function'] . "()";
            }
            $result .= "</td>";
            $result .= sprintf("<td>%s:%d</td>\n", basename($data['file']), $data['line']);
            $result .= "</tr>";
            if (isset($data['args']) && count($data['args']) > 0) {
                $result .= "<tr><td valign='top'>Arguments:<br /></td><td>";
                foreach ($data['args'] as $key => $argument) {
                    $result .= "[$key] " . htmlspecialchars((is_array($argument) ? 'Array()' : $argument)) . "<br />";
                }
                $result .= "</td></tr>";
            }
            $result .= "<tr><td valign='top'>Code<br /></td>";
            $result .= "<td>" . self::getCode($data['file'], $data['line']) . "</td></tr>";
        }
        $result .= "</table>";
        return $result;
    }
    private static function getCode ($file, $line)
    {
        $i = 1;
        $count = '';
        $code = '';
        $result = "<table celpadding='3' cellspacing='0' style='border: 1px solid #666; font-family: Trebuchet MS; font-color: #000; font-size: 9pt;'>";
        $result .= "<tr><td colspan='2' style='font-family: Courier New; background-color: #666; color: #fff;'><b>CODE</b> <span style='color: #FFCC00;'>" . basename($file) . "</span></td></tr>";
        if ($handle = fopen($file, 'r'))
            do {
                $count .= (($i == $line) ? "<span style='color: #FFCC00; font-weight: bold;'>$i</span>" : $i) . PHP_EOL;
                $code .= fgets($handle);
                $i ++;
            } while (! feof($handle));
        $result .= "<tr><td width='35' style='font-family: Courier New; background-color: #666; color: #fff;'>" . nl2br($count) . "</td>";
        $result .= "<td style='font-family: Courier New;'>" . highlight_string($code, true) . "</td></tr></table>";
        fclose($handle);
        return $result;
    }
}
?>