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

/**
 * @category  Core
 * @package   Core_Application
 * @copyright Copyright (c) 2011. Burza d.o.o. (http://web.burza.hr/en/)
 * @license   proprietary
 */
class Core_Application_Plugin_EventHandler_WebExceptionHandler extends Core_Application_Plugin_EventHandler_Abstract
{
    /**
     * @var Core_Dispatcher_Location_Interface
     */
    protected $_unauthorizedLocation;

    /**
     * @var Twig_Environment
     */
    protected $_view;

    /**
     * @var Core_Response
     */
    protected $_response;

    /**
     * @var array
     */
    protected $_subscriptions = array(
        array(
            'event'     => Core_Application_UnauthorizedException::EVENT_EXCEPTION,
            'method'    => 'unauthorizedHandler',
            'priority'  => 10,
            'filter'    => 'params.application.context == "web"'
        ),
        array(
            'event'     => Core_Application_ForbiddenException::EVENT_EXCEPTION,
            'method'    => 'exceptionHandler',
            'priority'  => 10,
            'filter'    => 'params.application.context == "web"'
        ),
        array(
            'event'     => Core_Application_NotFoundException::EVENT_EXCEPTION,
            'method'    => 'exceptionHandler',
            'priority'  => 10,
            'filter'    => 'params.application.context == "web"'
        ),
        array(
            'event'     => Core_Application_InvalidInputException::EVENT_EXCEPTION,
            'method'    => 'exceptionHandler',
            'priority'  => 1000,
            'filter'    => 'params.application.context == "web"'
        ),
        array(
            'event'     => Core_Application::EVENT_EXCEPTION,
            'priority'  => 1000,
            'method'    => 'exceptionHandler',
            'filter'    => 'params.application.context == "web"'
        ),
    );

    /**
     * @param Core_Dispatcher_Location_Interface $location
     *
     * @return \Core_Application_Plugin_EventHandler_ErrorHandler
     */
    public function setUnauthorizedLocation(Core_Dispatcher_Location_Interface $location)
    {
        $this->_location = $location;
        return $this;
    }

    /**
     * @return Core_Dispatcher_Location_Interface
     */
    public function getUnauthorizedLocation()
    {
        return $this->_location;
    }

    /**
     * @param Core_Response $response
     *
     * @return \Core_Application_Plugin_EventHandler_ErrorHandler
     */
    public function setResponse(Core_Response $response)
    {
        $this->_response = $response;
        return $this;
    }

    /**
     * @return Core_Response
     */
    public function getResponse()
    {
        if (null === $this->_response) {
            $this->setResponse(Core_Application::get('Response'));
        }
        return $this->_response;
    }

    /**
     * @param Twig_Environment $view
     *
     * @return Core_Application_Plugin_EventHandler_ErrorHandler
     */
    public function setView(Twig_Environment $view)
    {
        $this->_view = $view;
        return $this;
    }

    /**
     * @return Twig_Environment
     */
    public function getView()
    {
        if (null === $this->_view) {
            $this->setView(Core_Application::get('View'));
        }
        return $this->_view;
    }

    /**
     * @param Core_Event_Interface $event
     *
     * @return Core_Response
     */
    public function unauthorizedHandler(Core_Event_Interface $event)
    {
        $unauthorizedLocation = $this->getUnauthorizedLocation();
        if (null === $unauthorizedLocation) {
            return $this->exceptionHandler($event);
        }

        $event
            ->setIsPropagated(false)
            ->setIsProcessed(true);
        $response = $this->getDispatcher()->dispatch($unauthorizedLocation);
        $response->setCode(Core_Response::STATUS_UNAUTHORIZED);
        echo $response;
        exit;
    }

    /**
     * @param Core_Event_Interface $event
     *
     * @return void
     */
    public function exceptionHandler(Core_Event_Interface $event)
    {
        $event
            ->setIsPropagated(false)
            ->setIsProcessed(true);

        $application = $event->getSubject();
        /* @var $exception Exception */
        $exception   = $event->getParam('exception');
        $statusCode  = $this->_getConstant($exception, 'STATUS_CODE', Core_Response::STATUS_INTERNAL_SERVER_ERROR);

        $template    = $application->getView()->loadTemplate('errors/'. $statusCode .'.tpl');
        $response    = $application->getResponse();
        $response
            ->setCode($statusCode)
            ->setBody($template->render(compact('exception')));
        echo $response;
        exit;
    }

    /**
     * @param object $object Object instance to pull constant from
     * @param string $name   Constant name
     * @param mixed  $value  Default
     *
     * @return mixed
     */
    protected function _getConstant($object, $name, $value)
    {
        $constant = get_class($object) .'::'. $name;
        if (defined($constant)) {
            $value = constant($constant);
        }
        return $value;
    }
}
