<?php

/**
 * Power By Tmac PHP MVC framework
 * $Author: zhangwentao $  <zwttmac@qq.com>
 * $Id: Controller.class.php 24 2011-11-23 04:28:47Z zhangwentao $
 * http://www.t-mac.org； 
 */
class Controller
{

    /**
     * URL参数
     *
     * @var array
     */
    private $param;
    private $url;

    /**
     * 构造函数.
     *
     * @return void
     * @access public
     *
     */
    public function __construct()
    {
        $this->parsePath();
        $this->getControllerFile();
        $this->getControllerClass();
    }

    /**
     * 解析URL路径
     *
     * @return void
     * @access private
     *
     */
    private function parsePath()
    {
        global $TmacConfig;
        if ($TmacConfig['Common']['url_case_insensitive']) {
            // URL地址中M不区分大小写
            if (!empty($_GET['M']) && empty($_GET['m']))
                $_GET['m'] = strtolower($_GET['M']);
        }
        $url = empty($_GET['m']) ? 'index' : $_GET['m'];     
        //删除参数中的m(Controller)
        unset($_GET['m']);

        $param = explode('/', $url);
        if (count($param) > 1) {
            //Action
            $tmp_action = array_pop($param);
            //如果Action为空就默认成Index
            $tmp_action = empty($tmp_action) ? 'index' : $tmp_action;
            //Controller
            $tmp_controller = array_pop($param);
            //Controller + Action 组合加到url数组中
            array_push($param, $tmp_controller . '/' . $tmp_action);
        } else {
            $tmp_action = $url;
        }

        //确定Controller以及Action
        if (empty($param[0]) || strtolower($param[0]) == PHP_SELF) {
            //如果没有参数任何参数
            $this->param['TMAC_CONTROLLER'] = 'index';
            $this->param['TMAC_CONTROLLER_FILE'] = 'index';
            $this->param['TMAC_ACTION'] = 'index';
        } else {
            //取得Controller
            $controller_name = explode($TmacConfig['Common']['urlseparator'], $tmp_action);
            //Controller的第一个字符必须为字母
            if ($this->isLetter($controller_name[0])) {
                //临时url等待下一步解析
                $url_tmp = explode($TmacConfig['Common']['urlseparator'], end($param));
                //TMAC_CONTROLLER
                $this->param['TMAC_CONTROLLER'] = $url_tmp['0'];
                //TMAC_ACTION 中如果找不到'/'的话就执行默认index的Action 没有$TmacConfig['Common']['urlseparator']
                empty($url_tmp['1']) ? $this->param['TMAC_ACTION'] = 'index' : $this->param['TMAC_ACTION'] = $url_tmp['1'];
                //Action的第一个字母必须为字母 如果不是字母就执行默认的Action index方法
                $this->isLetter($this->param['TMAC_ACTION']) || $this->param['TMAC_ACTION'] = 'index';
                $this->param['TMAC_CONTROLLER_FILE'] = $this->param['TMAC_CONTROLLER'];
                //url数组里去掉control和action  留下路径TMAC_CONTROLLER_FILE
                array_pop($param);
                if (!empty($param)) {
                    $controller_file = implode('/', $param);
                    $this->param['TMAC_CONTROLLER_FILE'] = $controller_file . '/' . $this->param['TMAC_CONTROLLER_FILE'];
                }
            } else {
                $message = "错误的Controller请求";
                $message .= $GLOBALS['TmacConfig']['Common']['debug'] ? ": [{$param[0]}]" : "";
                throw new TmacException($message);
            }
            //在Url中可以使用"/"来作为Controller的目录分隔符
            $this->param['TMAC_CONTROLLER_FILE'] = str_replace('/', DIRECTORY_SEPARATOR, $this->param['TMAC_CONTROLLER_FILE']);
        }

    }

    /**
     * 根据解析的URL获取Controller文件
     *
     * @return void
     * @access private
     *
     */
    private function getControllerFile()
    {
        $controllerFile = APPLICATION_ROOT . 'Controller' . DIRECTORY_SEPARATOR . $this->param['TMAC_CONTROLLER_FILE'] . '.php';
        //有文件先执行目录下的文件
        if (is_file($controllerFile)) {
            require_once($controllerFile);
        } else {
            //判断url最后一位是不是'/'如果是执行下面的尝试下一级
            if (substr($this->url, -1, 1) !== '/') {
                //没有找到文件.尝试找下一级目录的index(尝试执行文件夹的index)  /test/testAction  =>   /test/test/index
                $this->param['TMAC_CONTROLLER_FILE'] .= DIRECTORY_SEPARATOR . 'index';
                $this->param['TMAC_ACTION'] = 'index';
                $controllerFile = APPLICATION_ROOT . 'Controller' . DIRECTORY_SEPARATOR . $this->param['TMAC_CONTROLLER_FILE'] . '.php';
            }            
            if (is_file($controllerFile)) {
                require_once($controllerFile);
            } else {
                $message = "错误的请求，找不到Controller文件";
                $message .= $GLOBALS['TmacConfig']['Common']['debug'] ? ":[$controllerFile]" : "";
                throw new TmacException($message);
            }
        }
    }

    /**
     * 根据Controller文件名获取Controller类名并且执行
     *
     * @return void
     * @access private
     *
     */
    private function getControllerClass()
    {
        $controllerClass = str_replace(DIRECTORY_SEPARATOR, '', ($tmp = strrchr($this->param['TMAC_CONTROLLER_FILE'], DIRECTORY_SEPARATOR)) === false ? $this->param['TMAC_CONTROLLER_FILE'] : $tmp);
        $controllerClass .= 'Action';
        if (class_exists($controllerClass)) {
            //取的Controller中的所有方法
            $methods = get_class_methods($controllerClass);
            //判断是否存在Action
            if (!in_array($this->param['TMAC_ACTION'], $methods)) {
                $message = "错误的请求，找不到Action";
                $message .= $GLOBALS['TmacConfig']['Common']['debug'] ? ":[{$this->param['TMAC_ACTION']}]" : "";
                throw new TmacException($message);
            }
            new HttpRequest($this->param);
            $action = new $controllerClass();
            //执行初始化Action
            in_array('_init', $methods) && $action->_init();
            $action->{$this->param['TMAC_ACTION']}();
        } else {
            $message = "错误的请求，找不到Controller类";
            $message .= $GLOBALS['TmacConfig']['Common']['debug'] ? ":[$controllerClass]" : "";
            throw new TmacException($message);
        }
    }

    /**
     * 判断第一个字符是否为字母
     *
     * @param string $char
     * @return boolean
     */
    private function isLetter($char)
    {
        $ascii = ord($char{0});
        return ($ascii >= 65 && $ascii <= 90) || ($ascii >= 97 && $ascii <= 122);
    }

}