<?php
/**
 * A class for establishing an error handling environment.
 *
 * This class converts php errors into error exceptions and provides a global
 * handler for uncatched exceptions.
 */
class environment
{
    /**
     * @var boolean The exception template.
     */
    protected static $template;
    
    ////////////////////////////////////////////////////////////////////////////
    // Construct and destruct functions.

    ////////////////////////////////////////////////////////////////////////////
    // Overload functions.

    ////////////////////////////////////////////////////////////////////////////
    // Interface functions.

    /**
     * Loads the error handling environment.
     *
     * @param integer (optional) $report The error reporting code.
     * @param string (optional) $template The exception template.
     * @param callback (optional) $exception The exception handler callback.
     * @param callback (optional) $error The error handler callback.
     * @throws logicexception If the exception template file is missing.
     */
    public static function load($report = -1, $template = null, $exception = 'environment::handle_exception', $error = 'environment::handle_error')
    {
        set_exception_handler($exception);
        set_error_handler($error, $report);
        
        if ($template !== null)
        {
            if (!is_file($template))
            {
                throw new logicexception('Exception template file ' . var_export($template, true) . ' is missing.');
            }
        }
        
        self::$template = $template;
    }

    /**
     * Unloads the error handling environment.
     */
    public static function unload()
    {
        restore_error_handler();
        restore_exception_handler();
        self::$template = null;
    }

    /**
     * Handles an error by converting it into an exception.
     * 
     * @param integer $code The error code.
     * @param string $message The error message.
     * @param string $file The file the error occured in.
     * @param integer $line The line the error occured on.
     * @throws errorexception/invalidargumentexception.
     */
    public static function handle_error($code, $message, $file, $line)
    {
        if (preg_match('~^Argument [0-9]+ passed to [a-z]+~i', $message))
        {
            throw new invalidargumentexception(substr($message, 0, -12) . '.', $code);
        }
        
        throw new errorexception($message, 0, $code, $file, $line);
    }

    /**
     * Handles an exception.
     * 
     * @param exception $exception The exception.
     */
    public static function handle_exception(exception $exception)
    {
        if (self::$template !== null)
        {
            while (ob_get_level())
            {
                ob_end_clean();
            }
            
            include self::$template;
        }
        
        self::unload();
        exit;
    }
    
    ////////////////////////////////////////////////////////////////////////////
    // Internal functions.
}
