<?php
/* SVN FILE: $Id: rkt_controller.php 531 2008-06-04 18:58:13Z bb_yujiro $ */
/**
 * Controllerクラス
 *
 * PHP versions 5
 *
 *      hitSuji : Social Network Service <http://rakuto.net/rktSNS/>
 *      Copyright (c) 2007 Yujiro Takahashi
 *
 * Licensed under The MIT License
 * Redistributions of files must retain the above copyright notice.
 *
 * @filesource
 * @package         hitSuji
 * @copyright       Copyright (c) 2007 Yujiro Takahashi
 * @link            http://rakuto.net/
 * @author          Yujiro Takahashi <yujiro@rakuto.net>
 * @version         $Revision: 531 $
 * @modifiedby      $LastChangedBy: bb_yujiro $
 * @lastmodified    $Date: 2008-06-05 03:58:13 +0900 (木, 05 6 2008) $
 * @license         http://opensource.org/licenses/mit-license.php The MIT License
 */

/**
 * Controllerクラス
 *
 * @category        Controller
 * @package         hitSuji
 * @copyright       Copyright (c) 2007 Yujiro Takahashi
 * @link            http://rakuto.net/
 * @author          Yujiro Takahashi <yujiro@rakuto.net>
 * @version         $Revision: 531 $
 * @modifiedby      $LastChangedBy: bb_yujiro $
 * @lastmodified    $Date: 2008-06-05 03:58:13 +0900 (木, 05 6 2008) $
 * @license         http://opensource.org/licenses/mit-license.php The MIT License
 */
class RKT_Controller
{
    /**
     * アカウント情報
     * @var array
     */
    protected $account = null;

    /**
     * DB接続オジェクト
     * @var object
     */
    protected $objdb = null;

    /**
     * Requestオジェクト
     * @var object
     */
    protected $objrqt = null;

    /**
     * Modelクラス名
     * @var array
     */
    protected $models = null;

    /**
     * Viewオブジェクト
     * @var object
     */
    protected $objvew = null;

    /**
     * Nonce
     * @var boolean
     */
    protected $checked_nonce = false;

    /**
     * 入力内容のチェック条件
     * @var array
     */
    protected $conditions = null;

    /**
     * コンストラクタ
     *
     * @access public
     * @param string $content_tpl
     * @return void
     */
    public function __construct($content_tpl='')
    {
        $this->objdb  = RKT_DB::getInstance();
        $this->objrqt = RKT_Request::getInstance();
        $this->objvew = RKT_View::getInstance();
        $this->objmdl = new RKT_Model();

        $this->objvew->setContentFile($content_tpl);

        $this->initGrouping();
        $this->setNonce();
        $this->_setModels();
        $this->setRequest();
        $this->initValue();
        $this->_initModelValue();

        $general = array(
            STATUS_ADMIN=>  'common/menuBar/general.tpl',
            STATUS_GUEST=>  'common/menuBar/guest.tpl',
            STATUS_MEMBER=> 'common/menuBar/general.tpl',
        );
        $this->objvew->setTemplate('generalbar_tpl', $general[$this->account['status']]);
    }

    /**
     * 実行処理
     *
     * @access public
     * @return void
     **/
    public function execute()
    {
        try {
            if (count($this->models['manip'])){
                $this->_manip();
            }
            $this->action();
            if (count($this->models['view'])){
                $this->_list();
            }
            $this->_setHttpReferer();
        } catch (PDOException $exception){
            error_log('-----------  '.date('Y-m-d H:i:s')."  --------------\r\n", 3, ERROR_LOG_FILE);
            error_log($_SERVER['REQUEST_URI']."\r\n", 3, ERROR_LOG_FILE);
            error_log($exception->getMessage()."\r\n", 3, ERROR_LOG_FILE);
            error_log($exception->getTraceAsString()."\r\n", 3, ERROR_LOG_FILE);

            $this->objvew->setContentFile('common'.DS.'error'.DS.'error.tpl');
        } catch (RKT_Exception $exception) {
            $code = $exception->getCode();
            if ($code == RKT_Exception::UNKNOWN_ERROR){
                error_log('-----------  '.date('Y-m-d H:i:s')."  --------------\r\n", 3, ERROR_LOG_FILE);
                error_log($_SERVER['REQUEST_URI']."\r\n", 3, ERROR_LOG_FILE);
                error_log($exception->getMessage()."\r\n", 3, ERROR_LOG_FILE);
                error_log($exception->getTraceAsString()."\r\n", 3, ERROR_LOG_FILE);
            }

            $errortpl = array(
                RKT_Exception::UNKNOWN_ERROR=>     'error.tpl',
                RKT_Exception::ACCESS_DENIED=>     'access.tpl',
                RKT_Exception::PERMISSION_DENIED=> 'permission.tpl',
                RKT_Exception::MALICIOUS_USER=>    'error.tpl',
                RKT_Exception::BAD_REQUEST=>       'error.tpl',
                RKT_Exception::NOT_FOUND=>         'notfound.tpl',
            );

            $this->objvew->setContentFile('common'.DS.'error'.DS.$errortpl[$code]);
        }
    }

    /**
     * 表示処理
     *
     * @access public
     * @return void
     **/
    public function display()
    {
        $this->objvew->display();
    }

    /**
     * リファラーURLの取得
     *
     * @access private
     * @param integer $pos
     * @return string
     */
    public static function getHttpReferer($pos)
    {
        return empty($_SESSION['HTTP_REFERERs'][$pos])? '':$_SESSION['HTTP_REFERERs'][$pos];
    }

    /**
     * アクション処理
     *
     * @abstract
     * @access protected
     **/
    protected function action()
    {
    }

    /**
     * Modelオブジェクトの設定
     *
     * @abstract
     * @access protected
     * @return void
     */
    protected function setCondition()
    {
    }

    /**
     * Nonceの設定
     *
     * @access protected
     * @return void
     */
    protected function setNonce()
    {
        $nonce = RKT_Crypt::getNonce('manipNonce');
        $this->objvew->baseAssign('nonce', $nonce);

        $request_nonce = empty($_GET['_mpnnc'])? 0:$_GET['_mpnnc'];
        $request_nonce = empty($_POST['_mpnnc'])? $request_nonce:$_POST['_mpnnc'];

        $this->checked_nonce = ($nonce === $request_nonce);
    }

    /**
     * 外部入力の取得
     *
     * @access protected
     * @return void
     */
    protected function setRequest()
    {
        $this->setCondition();
        if (empty($this->conditions)){
            return ;
        }

        $this->objrqt->setRequestType('_REQUEST');
        foreach ($this->conditions as $key=>$condition){
            if ($this->objrqt->catchValidate($key, $condition)){
                $this->$key = $this->objrqt->getRequest($key);
            }
        } // foreach ($this->conditions as $key=>$condition)

        $this->objvew->assign('request', $this->objrqt->getRequests());
    }

    /**
     * 変数の初期化
     *
     * @abstract
     * @access protected
     * @return void
     */
    protected function initValue()
    {
    }

    /**
     * グループ毎の初期化
     *
     * @abstract
     * @access protected
     * @return void
     */
    protected function initGrouping()
    {
    }

    /**
     * DB操作の実行
     *
     * @access private
     * @return integer 実行結果
     */
    private function _manip()
    {
        $self   = getUrlSelf();
        $cNonce = true;

        $action = array(            // アクション
            'edit'=>     false,
            'confirm'=>  false,
            'again'=>    false,
            'manip'=>    false,
            'complete'=> false,
            'delete'=>   false,
            'deleted'=>  false,
            'url'=>      '',
            'goback'=>   'again',
        );
        $next = array(              // 次の処理
            'edit'=>    'confirm',
            'confirm'=> 'manip',
            'again'=>   'confirm',
            'manip'=>   'complete',
            'complete'=>'complete',
            'delete'=>  'deleted',
            'deleted'=> 'complete',
        );

        /* 現在の処理を取得 */
        if ($pos = strpos($self, 'manip')){
            $doing  = 'manip';
            $length = 5;
        } elseif ($pos = strpos($self, 'confirm')){
            $is_confirm = true;
            $doing  = 'confirm';
            $length = 7;
        } elseif ($pos = strpos($self, 'complete')){
            $doing  = 'complete';
            $length = 8;
        } elseif ($pos = strpos($self, 'deleted')){
            $doing  = 'deleted';
            $length = 7;
        } elseif ($pos = strpos($self, 'delete')){
            $doing  = 'delete';
            $length = 6;
            $cNonce = false;
        } else {
            $pos           = strlen($self);
            $doing         = 'edit';
            $length        = 4;
            $next['edit'] .= '/';
            $cNonce        = false;
        }
        if (!empty($_POST['again'])){
            $doing = 'again';
            $cNonce = true;
        }
        /* 入力内容のチェック */
        if (!$this->objrqt->getValidate()){
            if (!empty($_POST['confirm'])){
                $doing = 'again';
                $this->objvew->assign('alert', $this->objrqt->getAlerts());
            }
        } // if (!$this->objrqt->getValidate())
        $url  = substr($self, 0, $pos);
        $url .= $next[$doing];
        $url .= substr($self, $pos + $length);
        
        $action[$doing] = true;
        $action['url']   = $url;


        /* 直接URLを開いた場合など */
        if (!$this->checked_nonce && $cNonce){
            throw new RKT_Exception(RKT_Exception::BAD_REQUEST);
        }
        
        /* 前のページへ戻る */
        if (!empty($_POST['back'])){
            header('Location: '. $this->getHttpReferer(1));
            exit();                
        } elseif (!empty($_POST['attach'])){
            foreach ($this->objrqt->requests as $key=>$value){
                $_SESSION[$key] = $value;
            }
            header('Location: '.HTTP_ACTION.'private/attach/attach/module/'.US.SID);
            exit();
        }

        /* 入力内容の保存 */
        if ($action['confirm'] && $this->objrqt->getValidate()){
            foreach ($this->objrqt->requests as $key=>$value){
                $_SESSION[$key] = $value;
            }
            $_SESSION['confirm'] = true;
        } // if ($action['confirm'] && $this->objrqt->validated)

        /* 更新処理の実行 */
        if ($action['manip']){
            if (empty($_SESSION['confirm'])){
                $action['manip']    = false;
                $action['complete'] = true;
            } else {
                $result = true;
                foreach ($this->models['manip'] as $model){
                    if ($this->$model->manip()){
                        foreach ($this->$model->new_values as $key=>$value){
                            unset($_SESSION[$key]);
                        }
                        unset($_SESSION['confirm']);
                    } else {
                        $result = false;
                    }
                    $this->objvew->assign($model, $this->$model->new_values);
                }
                if ($result){
                    $action['manip']    = false;
                    $action['complete'] = true;
                }
            } // if (empty($_SESSION['confirm']))
        } elseif ($action['deleted']){
            foreach ($this->models['manip'] as $model){
                $this->$model->setDelete();
                $this->$model->manip();
            }
            $action['goback'] = 'back';
        } elseif ($action['delete']){
            foreach ($this->models['manip'] as $model){
                $this->objvew->assign($model, $this->$model->old_values);
            }
            $action['goback'] = 'back';
        } else {
            foreach ($this->models['manip'] as $model){
                $this->objvew->assign($model, $this->$model->new_values);
            }
        } // if ($action['manip'] && !empty($_SESSION['confirm']))

        $this->objvew->assign('action', $action);
    }

    /**
     * 一覧表示の実行
     *
     * @access private
     * @return void
     */
    private function _list()
    {
        foreach ($this->models['view'] as $view){
            $objname = 'v_'.$view;

            $list = $this->$objname->getValues();
            $this->objvew->assign('v_'.$view, $list);

            $info = $this->$objname->getInfo();
            $this->objvew->assign('p_'.$view, $info);
        } // foreach ($this->models['view'] as $view)
    }

    /**
     * Modelオブジェクトの設定
     *
     * @access private
     * @return void
     */
    private function _setModels()
    {
        if (empty($this->models)){
            return ;
        }
        $references = array();

        /* Model_Manipオブジェクトの生成 */
        if (count($this->models['manip'])){
            include LIB_DIR.'rktModel'.DS.'Manip.php';
            foreach ($this->models['manip'] as $class){
                include MODEL_DIR.'manips'.DS.$class.'.php';
                $this->$class = new $class();
                $reference = $this->$class->getReference();
                foreach ($reference as $table){
                    $references[$table] = $table;
                }
            } // foreach ($this->models['manip'] as $model)
        }

        /* Model_Viewオブジェクトの生成 */
        if (count($this->models['view'])){
            include LIB_DIR.'rktModel'.DS.'View.php';
            foreach ($this->models['view'] as $table){
                include MODEL_DIR.'views'.DS.$table.'.php';
                $objname = 'v_'.$table;
                $class   = 'View_'.$table;

                $this->$objname = new $class();
                $reference = $this->$objname->getReference();
                foreach ($reference as $table){
                    $references[$table] = $table;
                }
            } // foreach ($this->models['view'] as $model)
        }

        $reference = array();
        foreach ($references as $table){
            $reference[$table] = $this->objmdl->getReferenceList($table);
        }
        $this->objvew->assign('reference', $reference);
    }

    /**
     * Model初期データの設定
     *
     * @access private
     * @return void
     */
    private function _initModelValue()
    {
        if (empty($this->models)){
            return ;
        }
        $request = '_POST';
        if (isSet($_POST['again']) || isSet($_POST['manip'])){
            $request = '_SESSION';
        }

        $self  = getUrlSelf();
        $catch = false;
        if ($pos = strpos($self, 'manip')){
            $catch = true;
        } elseif ($pos = strpos($self, 'confirm')){
            $catch = true;
        } elseif (array_key_exists('again', $_POST)){
            $catch = true;
        } elseif (array_key_exists('attach', $_POST)){
            $catch = true;
        } elseif (array_key_exists('confirm', $_POST)){
            $catch = true;
        } elseif (array_key_exists('manip', $_POST)){
            $catch = true;
        }

        /* Model_Manipオブジェクトの生成 */
        if (count($this->models['manip'])){
            foreach ($this->models['manip'] as $class){
                $this->$class->setInitValue();
            } // foreach ($this->models['manip'] as $model)

            if ($catch){
                foreach ($this->models['manip'] as $class){
                    $this->$class->catchRequest($request);
                } // foreach ($this->models['manip'] as $model)
            }
        }

        /* Model_Viewオブジェクトの生成 */
        if (count($this->models['view'])){
            foreach ($this->models['view'] as $table){
                $objname = 'v_'.$table;
                $this->$objname->catchRequest();

                $this->objvew->assign('r_'.$table, $this->$objname->requests);
            } // foreach ($this->models['view'] as $model)
        }
    }

    /**
     * リファラーURLの保存
     *
     * @access private
     * @return void
     */
    private function _setHttpReferer()
    {
        $pos = strpos($_SERVER['REQUEST_URI'], '/json/');
        if ($pos !== false){
            return ;
        }
        $pos = strpos($_SERVER['REQUEST_URI'], '/module/');
        if ($pos !== false){
            return ;
        }

        $referer_0 = empty($_SESSION['HTTP_REFERERs'][0])? 
                            $_SERVER['REQUEST_URI']:$_SESSION['HTTP_REFERERs'][0];
        $referer_1 = empty($_SESSION['HTTP_REFERERs'][1])? 
                            '':$_SESSION['HTTP_REFERERs'][1];
        $referer_2 = empty($_SESSION['HTTP_REFERERs'][2])? 
                            '':$_SESSION['HTTP_REFERERs'][2];

        if ($referer_0 != $_SERVER['REQUEST_URI']){
            $referer_2 = $referer_1;
            $referer_1 = $referer_0;
            $referer_0 = $_SERVER['REQUEST_URI'];
        }
        $_SESSION['HTTP_REFERERs'] = array(
            $referer_0,
            $referer_1,
            $referer_2
        );
    }
} // class RKT_Controllerの終了
?>
