<?php
/**
 * @copyright NetMonsters <team@netmonsters.ru>
 * @link http://netmonsters.ru
 * @package Majestic
 * @subpackage app
 * @since 2010-02-24
 */

class FrontController
{
    /**
     * @var Router
     */
    protected $router;

    /**
     * @var string
     */
    protected $view = 'PHPView';

    protected $base_url = '';

    /**
     * @var FrontController
     */
    protected static $instance;


    private function __construct()
    {
        ErrorHandler::init();
        $this->router = new Router();
    }

    /**
     * Refuse cloning
     * @codeCoverageIgnoreStart
     */
    private function __clone()
    {
    }

    /**
     * @codeCoverageIgnoreEnd
     */

    /**
     * @return FrontController
     */
    static public function getInstance()
    {
        if (!isset(self::$instance)) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    /**
     * @param string $view
     * @return FrontController
     */
    public function setView($view)
    {
        $this->view = $view;
        return $this;
    }

    /**
     *
     * @param null $view
     * @return iView
     */
    public function getView($view = null)
    {
        $view = ($view) ? $view : $this->view;
        return new $view(Config::get($view));
    }

    /**
     * @param string $url
     * @return FrontController
     */
    public function setBaseUrl($url)
    {
        $this->base_url = rtrim($url, '/');
        return $this;
    }

    public function getBaseUrl()
    {
        return $this->base_url;
    }

    /**
     * @return Router
     */
    public function getRouter()
    {
        return $this->router;
    }

    public function execute()
    {
        try {
            $request = Env::getRequestUri(true);
            $route = $this->getRouter()->route($request);
            if (!$route) {
                throw new Error404Exception('Route for "' . $request . '" not found');
            }

            $action_class = $route->getAction();
            if (!class_exists($action_class)) {
                throw new GeneralException('Action class "' . $action_class . '" not found.');
            }

            $action = new $action_class();
            $layout_class = $route->getLayout();
            if (!class_exists($layout_class)) {
                throw new GeneralException('Layout class "' . $layout_class . '" not found.');
            }

            /**
             * @var Layout $layout
             */
            $layout = new $layout_class();
            $html = $layout->fetch($action);
            if (Config::get('PROFILER')) {
                if (is_subclass_of($action, 'AjaxAction')) {
                    Profiler::getInstance()->getJson();
                } else {
                    $html = Profiler::getInstance()->end($html);
                }
            }
            return $html;
        }
        catch (Exception $e) {
            if (Config::get('DEBUG')) {
                if (!headers_sent()) {
                    if ($e instanceof ErrorHTTPException) {
                        header($e->getHTTPHeader());
                    } else {
                        header('HTTP/1.0 500 Internal Server Error');
                    }
                }
                return ErrorHandler::showDebug($e);
            }
            $layout_class = $this->getRouter()->getErrorLayout();

            /**
             * @var ErrorLayout $layout
             */
            $layout = new $layout_class();
            $layout->setException($e);
            $error_action = new ErrorAction($e);
            if (isset($action_class) && is_subclass_of($action_class, 'AjaxAction')) {
                $error_action->setAjaxError();
            }
            return $layout->fetch($error_action);
        }
    }
}