<?php
/**
 * core.framework
 *
 * @category  Core
 * @package   Core_Event
 * @copyright Copyright (c) 2011. Burza d.o.o. (http://web.burza.hr/en/)
 * @license   proprietary
 */

/**
 * @category  Core
 * @package   Core_Event
 * @copyright Copyright (c) 2011. Burza d.o.o. (http://web.burza.hr/en/)
 * @license   proprietary
 */
class Core_Exception extends RuntimeException implements Core_Exception_Interface
{
    /**
     * @var array Exception params
     */
    protected $_params;
    
    /**
     * @var array Exception type
     */
    protected $_type = 'php';

    /**
     * @var Core_Request
     */
    protected $_request;

    /**
     * @var Core_Application
     */
    protected $_application;

    /**
     * @param string  $subject Exception message
     * @param integer  $code  Exception code
     * @param exception $previous Previous Exception
     */
    public function __construct($message = '', $code = 0, Exception $previous = null)
    {
        try {
            $application = $this->getApplication();
            if (null !== $application) {
                $this->setParam('lang', $application->getLanguage());
                $this->setParam('env', $application->getEnvironment());
                $this->setParam('clientIp', $application->getClientIp());
                $this->setParam('method', $application->getMethod());
                $this->setParam('referrer', $application->getReferrer());
                $this->setParam('path', $application->getPath());
                $this->setParam('uri', $application->getUriBase());
            }
        } catch (Exception $e) {
            // Ignore internal exceptions, propagate exception even if missing some info
        }

        parent::__construct($message, $code, $previous);
    }


    /**
     * @param Core_Application $application
     *
     * @return Core_Application
     */
    public function setApplication(Core_Application $application)
    {
        $this->_application = $application;
        return $this;
    }

    /**
     * If not set, set Core_Application
     *
     * @return Core_Application
     */
    public function getApplication()
    {
        if (null === $this->_application) {
            $this->setApplication(Core_Application::getInstance());
        }
        return $this->_application;
    }

    /**
     * @param Core_Request $request
     *
     * @return Core_Router
     */
    public function setRequest(Core_Request $request)
    {
        $this->_request = $request;
        return $this;
    }

    /**
     * If not set, fetch from Core_Application
     *
     * @return Core_Request
     */
    public function getRequest()
    {
        if (null === $this->_request) {
            $this->setRequest(Core_Application::get('Request'));
        }
        return $this->_request;
    }

    /**
     * @param array $params
     *
     * @return Core_Event
     */
    public function setParams(array $params)
    {
        $this->_params = $params;
        return $this;
    }

    /**
     * @return array
     */
    public function getParams()
    {
        return $this->_params;
    }

    /**
     * @param string $name  Param name
     * @param mixed  $value Param value
     *
     * @return Core_Event
     */
    public function setParam($name, $value)
    {
        $this->_params[$name] = $value;
        return $this;
    }

    /**
     * @param string $name
     *
     * @return bool
     */
    public function hasParam($name)
    {
        return isset($this->_params[$name]);
    }

    /**
     * @param string $name
     *
     * @return mixed
     */
    public function getParam($name)
    {
        if ($this->hasParam($name)) {
            $value = $this->_params[$name];
        } else {
            $value = null;
        }
        return $value;
    }

    /**
     * @param string $type
     *
     * @return type
     */
    public function setType($type)
    {
        $this->_type = $type;
        return $this;
    }

    /**
     * @return type
     */
    public function getType()
    {
        return $this->_type;
    }

    /**
     * @return string
     */
    public function __toString()
    {
        // JS exceptions need different output
        if ($this->_type == 'javascript') {
            $return = get_class($this) . ": [{$this->code}] ({$this->_type}): {$this->message}\n";
            $data = json_encode($this->getParam('data'));
            $return .= "{$data}\n";
        } else {
            $return = get_class($this) . ": [{$this->code}] ({$this->_type}):";
            if (isset($this->message)) {
                $return .= "{$this->message}\n";
            } else {
                $return .= "no message sent\n";
            }
            if (isset($this->trace)) {
                $return .= "Trace:\n{$this->trace}\n";
            } else {
                $return .= "Trace:\n".$this->getTraceAsString()."\n";
            }
        }

        return $return;
    }
}
