<?php
/**
 * Created by PhpStorm.
 * User: crose
 * Date: 2/7/16
 * Time: 7:59 PM
 */

namespace IMATHUZH\Qfq\Core\Exception;

use IMATHUZH\Qfq\Core\Store\Store;

/**
 * Class ErrorHandler
 * @package qfq
 */
class ErrorHandler
{
    /**
     * A flag to detect if the error handler is used:
     *   0 - not used
     *   1 - suspended
     *   2 - actively used
     *
     * @var bool
     */
    private static $status = 0;

    /**
     * The list of reported errors to be restored.
     * @var string
     */
    private static $savedErrorReporting = '';

    /**
     * Set this class as the error handler and updates the list of reported errors.
     * This method does not modify static properties.
     * @return void
     */
    private static function setErrorHandler(): void
    {
        // By T3 default 'E_NOTICE' is unset. E.g. 'Undefined Index' will throw an exception.
        // QFQ like to see those 'E_NOTICE'
        error_reporting(self::$savedErrorReporting | E_NOTICE);
        set_error_handler([self::class, 'exception_error_handler']);
    }

    /**
     * Restores the error handler and the list of reported errors.
     * This method does not modify static properties.
     * @return void
     */
    private static function restoreErrorHandler(): void
    {
        restore_error_handler();
        error_reporting(self::$savedErrorReporting);
    }


    /**
     * Sets this as PHP error handler and adds E_NOTICE to the list or reported errors.
     * @return void
     */
    public static function useAsPhpErrorHandler(): void
    {
        switch (self::$status) {
            case 0:
                self::$savedErrorReporting = error_reporting();
                // fallthrough
            case 1:
                self::setErrorHandler();
                self::$status = 2;
        }
    }

    /**
     * Restores the previous error handler and the list reported errors
     * @return void
     */
    public static function restorePhpErrorHandler(): void
    {
        if (self::$status === 2) {
            self::restoreErrorHandler();
        }
        self::$status = 0;
    }

    /**
     * Suspends this error handler. Use {@see resume()} to resume it.
     * @return void
     */
    public static function suspend(): void
    {
        if (self::$status === 2) {
            self::restoreErrorHandler();
            self::$status = 1;
        }
    }

    /**
     * Resumes this error handler if it was suspended.
     * @return void
     */
    public static function resume(): void
    {
        if (self::$status === 1) {
            self::setErrorHandler();
            self::$status = 2;
        }
    }

    /**
     * @param $severity
     * @param $message
     * @param $file
     * @param $line
     * @return bool|string
     * @throws \CodeException
     * @throws \UserFormException
     * @throws \UserReportException
     */
    public static function exception_error_handler($severity, $message, $file, $line) {

        if (!(error_reporting() & $severity)) {
            // This error code is not included in error_reporting
            return false;
        }

        $store = Store::getInstance();
        if ($store->getVar(SYSTEM_THROW_GENERAL_ERROR, STORE_SYSTEM) == 'yes') {

            // Do not show too much to the user. E.g. 'ldap_bind()' might have problems, but the user should not see the
            // file and line number. Often the filename is part of the message >> don't show the message to the user.
            throw new \CodeException(json_encode([
                ERROR_MESSAGE_TO_USER => 'General error - please report.',
                ERROR_MESSAGE_TO_DEVELOPER => "File: $file / Line: $line / $message"
            ]), $severity, null);

        }

        return true;
    }

}