<?php

namespace AcyMailing\Libraries\Pear;

/**
 * Standard PEAR error class for PHP 4
 *
 * This class is supserseded by {@link PEAR_Exception} in PHP 5
 *
 * @category   pear
 * @package    PEAR
 * @author     Stig Bakken <ssb@php.net>
 * @author     Tomas V.V. Cox <cox@idecnet.com>
 * @author     Gregory Beaver <cellog@php.net>
 * @copyright  1997-2006 The PHP Group
 * @license    http://opensource.org/licenses/bsd-license.php New BSD License
 * @version    Release: 1.10.16
 * @link       http://pear.php.net/manual/en/core.pear.pear-error.php
 * @see        Pear::raiseError(), Pear::throwError()
 * @since      Class available since PHP 4.0.2
 */
class Error
{
    var $error_message_prefix = '';
    var $mode = PEAR_ERROR_RETURN;
    var $level = E_USER_NOTICE;
    var $code = -1;
    var $message = '';
    var $userinfo = '';
    var $backtrace = null;
    var $callback = null;

    /**
     * Error constructor
     *
     * @param string $message  message
     *
     * @param int    $code     (optional) error code
     *
     * @param int    $mode     (optional) error mode, one of: PEAR_ERROR_RETURN,
     *                         PEAR_ERROR_PRINT, PEAR_ERROR_DIE, PEAR_ERROR_TRIGGER,
     *                         PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION
     *
     * @param mixed  $options  (optional) error level, _OR_ in the case of
     *                         PEAR_ERROR_CALLBACK, the callback function or object/method
     *                         tuple.
     *
     * @param string $userinfo (optional) additional user/debug info
     *
     * @access public
     *
     */
    function __construct(
        $message = 'unknown error',
        $code = null,
        $mode = null,
        $options = null,
        $userinfo = null
    ) {
        if ($mode === null) {
            $mode = PEAR_ERROR_RETURN;
        }
        $this->message = $message;
        $this->code = $code;
        $this->mode = $mode;
        $this->userinfo = $userinfo;

        $skiptrace = Pear::getStaticProperty('AcyMailing\Libraries\Pear\Error', 'skiptrace');

        if (!$skiptrace) {
            $this->backtrace = debug_backtrace();
            if (isset($this->backtrace[0]) && isset($this->backtrace[0]['object'])) {
                unset($this->backtrace[0]['object']);
            }
        }

        if ($mode & PEAR_ERROR_CALLBACK) {
            $this->level = E_USER_NOTICE;
            $this->callback = $options;
        } else {
            if ($options === null) {
                $options = E_USER_NOTICE;
            }

            $this->level = $options;
            $this->callback = null;
        }

        if ($this->mode & PEAR_ERROR_PRINT) {
            if (is_null($options) || is_int($options)) {
                $format = "%s";
            } else {
                $format = $options;
            }

            printf($format, $this->getMessage());
        }

        if ($this->mode & PEAR_ERROR_TRIGGER) {
            trigger_error($this->getMessage(), $this->level);
        }

        if ($this->mode & PEAR_ERROR_DIE) {
            $msg = $this->getMessage();
            if (is_null($options) || is_int($options)) {
                $format = "%s";
                if (substr($msg, -1) != "\n") {
                    $msg .= "\n";
                }
            } else {
                $format = $options;
            }
            printf($format, $msg);
            exit($code);
        }

        if ($this->mode & PEAR_ERROR_CALLBACK && is_callable($this->callback)) {
            call_user_func($this->callback, $this);
        }

        if ($this->mode & PEAR_ERROR_EXCEPTION) {
            trigger_error("PEAR_ERROR_EXCEPTION is obsolete, use class PEAR_Exception for exceptions", E_USER_WARNING);
            throw new \Exception($this->message, $this->code);
        }
    }

    /**
     * Get the error mode from an error object.
     *
     * @return int error mode
     * @access public
     */
    function getMode()
    {
        return $this->mode;
    }

    /**
     * Get the callback function/method from an error object.
     *
     * @return mixed callback function or object/method array
     * @access public
     */
    function getCallback()
    {
        return $this->callback;
    }

    /**
     * Get the error message from an error object.
     *
     * @return  string  full error message
     * @access public
     */
    function getMessage()
    {
        return ($this->error_message_prefix.$this->message);
    }

    /**
     * Get error code from an error object
     *
     * @return int error code
     * @access public
     */
    function getCode()
    {
        return $this->code;
    }

    /**
     * Get the name of this error/exception.
     *
     * @return string error/exception name (type)
     * @access public
     */
    function getType()
    {
        return get_class($this);
    }

    /**
     * Get additional user-supplied information.
     *
     * @return string user-supplied information
     * @access public
     */
    function getUserInfo()
    {
        return $this->userinfo;
    }

    /**
     * Get additional debug information supplied by the application.
     *
     * @return string debug information
     * @access public
     */
    function getDebugInfo()
    {
        return $this->getUserInfo();
    }

    /**
     * Get the call backtrace from where the error was generated.
     * Supported with PHP 4.3.0 or newer.
     *
     * @param int $frame (optional) what frame to fetch
     *
     * @return array Backtrace, or NULL if not available.
     * @access public
     */
    function getBacktrace($frame = null)
    {
        if (defined('PEAR_IGNORE_BACKTRACE')) {
            return null;
        }
        if ($frame === null) {
            return $this->backtrace;
        }

        return $this->backtrace[$frame];
    }

    function addUserInfo($info)
    {
        if (empty($this->userinfo)) {
            $this->userinfo = $info;
        } else {
            $this->userinfo .= " ** $info";
        }
    }

    function __toString()
    {
        return $this->getMessage();
    }

    /**
     * Make a string representation of this object.
     *
     * @return string a string with an object summary
     * @access public
     */
    function toString()
    {
        $modes = [];
        $levels = [
            E_USER_NOTICE => 'notice',
            E_USER_WARNING => 'warning',
            E_USER_ERROR => 'error',
        ];
        if ($this->mode & PEAR_ERROR_CALLBACK) {
            if (is_array($this->callback)) {
                $callback = (is_object($this->callback[0])
                        ?
                        strtolower(get_class($this->callback[0]))
                        :
                        $this->callback[0]).'::'.
                    $this->callback[1];
            } else {
                $callback = $this->callback;
            }

            return sprintf(
                '[%s: message="%s" code=%d mode=callback '.
                'callback=%s prefix="%s" info="%s"]',
                strtolower(get_class($this)),
                $this->message,
                $this->code,
                $callback,
                $this->error_message_prefix,
                $this->userinfo
            );
        }
        if ($this->mode & PEAR_ERROR_PRINT) {
            $modes[] = 'print';
        }
        if ($this->mode & PEAR_ERROR_TRIGGER) {
            $modes[] = 'trigger';
        }
        if ($this->mode & PEAR_ERROR_DIE) {
            $modes[] = 'die';
        }
        if ($this->mode & PEAR_ERROR_RETURN) {
            $modes[] = 'return';
        }

        return sprintf(
            '[%s: message="%s" code=%d mode=%s level=%s '.
            'prefix="%s" info="%s"]',
            strtolower(get_class($this)),
            $this->message,
            $this->code,
            implode("|", $modes),
            $levels[$this->level],
            $this->error_message_prefix,
            $this->userinfo
        );
    }
}
