<?php
/**
 * Controller.
 * @package magic.core
 */
/**
 * モジュールを読み込みます.
 * <p>
 * アプリケーション側でコントローラーを作成して、
 * 必要なモジュールを読み込んでください。
 * </p>
 */
require_once CORE . 'Bootstrap.php';
/**
 * コントローラークラスです.
 * <p>
 * 設定情報を読み込んで、Actionクラスを実行します。<br/>
 * Actionクラスの実行結果から、Viewクラスを実行します。
 * </p>
 * @package magic.core
 * @author T.Okumura
 * @version 1.0.0
 */
class Controller {
    /**
     * HttpRequestクラスを保持します.
     * @var HttpRequest
     */
    protected $request = NULL;
    /**
     * HttpSessionクラスを保持します.
     * @var HttpSession
     */
    protected $session = NULL;
    /**
     * NameConfigureクラスを保持します.
     * @var NameConfigure
     */
    protected $name = NULL;
    /**
     * PathConfigureクラスを保持します.
     * @var PathConfigure
     */
    protected $path = NULL;
    /**
     * RouteConfigureクラスを保持します.
     * @var RouteConfigure
     */
    protected $route = NULL;
    /**
     * DataSourceConfigureクラスを保持します.
     * @var DataSourceConfigure
     */
    protected $dataSource = NULL;
    /**
     * セッションを自動的に開始するかどうかのフラグです.
     * @var bool
     */
    protected $sessionAutoStart = FALSE;
    /**
     * コンストラクタ.
     */
    public function __construct() {
    }
    /**
     * index.phpからコールされるエントリポイントです.
     * <p>
     * このファンクションは、オーバーライドできません。
     * </p>
     * @final
     */
    public final function dispatch() {
        try {
            $this->request = new HttpRequest();
            $this->session = new HttpSession('MAGIC');
            $this->configure();
            $this->_makeUp();
            $this->render($this->_invoke());
        } catch (MagicException $e) {
            $this->systemExceptionHandler($e);
            echo $e->message();
        } catch (PDOException $e) {
            $this->sqlExceptionHandler($e);
            echo $e->getMessage();
        }
    }
    /**
     * 設定クラスをセットします.
     * <p>
     * アプリケーション側で設定クラスを作成した場合は、
     * このファンクションをオーバーライドして、
     * 適切な設定クラスをセットしてください。
     * </p>
     */
    protected function configure() {
        $this->name = NULL;
        $this->path = NULL;
        $this->route = NULL;
        $this->dataSource = NULL;
        $this->sessionAutoStart = FALSE;
        LocaleProvider::setDefaultLocale(NULL);
        MessageBehavior::setMessageClass(NULL);
    }
    /**
     * システムエラーが発生した場合にコールされます.
     * <p>
     * デフォルトでは何もしません。<br/>
     * アプリケーション側で処理を実行するには、
     * このファンクションをオーバーライドしてください。
     * </p>
     */
    protected function systemExceptionHandler() {
    }
    /**
     * データベースエラーが発生した場合にコールされます.
     * <p>
     * デフォルトでは何もしません。<br/>
     * アプリケーション側で処理を実行するには、
     * このファンクションをオーバーライドしてください。
     * </p>
     */
    protected function sqlExceptionHandler() {
    }
    /**
     * デフォルトの設定クラスをセットします.
     * <p>
     * このファンクションは、オーバーライドできません。<br/>
     * 設定クラスのうち、アプリケーション側で設定されていないものに、
     * デフォルトの設定クラスをセットします。
     * </p>
     * @throws MagicException 設定クラスが不正な場合
     * @final
     */
    private final function _makeUp() {
        if ($this->sessionAutoStart) {
            $this->session->start();
        }
        if (is_null($this->name)) {
            require_once CORE . 'config' . DIRECTORY_SEPARATOR . 'impl' . DIRECTORY_SEPARATOR . 'NameConfigureImpl.php';
            $this->name = new NameConfigureImpl();
        } elseif (!($this->name instanceof NameConfigure)) {
            throw new MagicException(
                    MessageBehavior::getMessage('SYS003', array('NameConfigure', get_class($this->name))));
        }
        if (is_null($this->path)) {
            require_once CORE . 'config' . DIRECTORY_SEPARATOR . 'impl' . DIRECTORY_SEPARATOR . 'PathConfigureImpl.php';
            $this->path = new PathConfigureImpl();
        } elseif (!($this->path instanceof PathConfigure)) {
            throw new MagicException(
                    MessageBehavior::getMessage('SYS003', array('PathConfigure', get_class($this->path))));
        }
        if (is_null($this->route)) {
            require_once CORE . 'config' . DIRECTORY_SEPARATOR . 'impl' . DIRECTORY_SEPARATOR
                    . 'RouteConfigureImpl.php';
            $this->route = new RouteConfigureImpl($this->request);
        } elseif (!($this->route instanceof RouteConfigure)) {
            throw new MagicException(
                    MessageBehavior::getMessage('SYS003', array('RouteConfigure', get_class($this->route))));
        }
        if (is_null($this->dataSource)) {
            require_once CORE . 'config' . DIRECTORY_SEPARATOR . 'impl' . DIRECTORY_SEPARATOR
                    . 'DataSourceConfigureImpl.php';
            $this->dataSource = new DataSourceConfigureImpl();
        } elseif (!($this->dataSource instanceof DataSourceConfigure)) {
            throw new MagicException(
                    MessageBehavior::getMessage('SYS003', array('DataSourceConfigure', get_class($this->dataSource))));
        }
    }
    /**
     * Actionクラスを実行します.
     * <p>
     * このファンクションは、オーバーライドできません。
     * </p>
     * @return ActionResult Actionクラスの実行結果
     * @final
     */
    private final function _invoke() {
        $invoker = new ActionInvocation($this->request, $this->session, $this->name, $this->path, $this->dataSource);
        return $invoker->invoke($this->route->getActionName(), $this->route->getMethodName());
    }
    /**
     * Actionクラスの結果からViewクラスを実行します.
     * <p>
     * このファンクションは、オーバーライドできません。
     * </p>
     * @param ActionResult $result Actionクラスの実行結果
     * @final
     */
    protected final function render(ActionResult $result) {
        $result->execute($this->name, $this->path, $this->route);
    }
}
// EOF.