<?php
/**
 * URL路由处理类
 * ============================================================================
 * Copyright 2014 大秦科技，并保留所有权利。
 * 网站地址: http://www.qintech.net；
 * ----------------------------------------------------------------------------
 * 未获商业授权之前，不得将Magic CMS用于商业用途（包括但不限于企业网站、经营性网站
 * 以营利为目的或实现盈利的网站）未经官方许可，禁止在Magic CMS的整体或任何部分基础
 * 上以发展任何派生版本、修改版本或第三方版本用于重新分发。如果您未能遵守本协议的
 * 条款，您的授权将被终止，所被许可的权利将被收回，并承担相应法律责任。
 * ============================================================================
 * Author: Shiang.Chin
 * Date:2014/12/31
**/
if (!defined('KERNEL_PATH'))exit('No direct script access allowed');
final class Route{
    /**
     * 根据不同url处理方式，得到Url参数
     */
    static public function parseUrl(){

        //请求内容
        $query = $_GET[C("PATHINFO_VAR")];

        //分析路由 && 清除伪静态后缀
        $url = self::parseRoute($query);
        //拆分后的GET变量
        $gets = '';

        $url = str_replace(array('&', '='), C("PATHINFO_DLI"), $url);
        $args = explode(C("PATHINFO_DLI"), $url);

         //模块
          if (empty($args[0])) {
               $_GET[C("VAR_MODULE")] = C("DEFAULT_MODULE");
          } else {
                if ($args[0] == C("VAR_MODULE")) {
                    $_GET[$args[0]] = $args[1];
                    array_shift($args);
                    array_shift($args);
                } else {
                    $_GET[C("VAR_MODULE")] = $args[0];
                    array_shift($args);
                }
            }

			//控制器
            if (empty($args[0])) {
                $_GET[C('VAR_CONTROLLER')] = C('DEFAULT_CONTROLLER');
            } else {
                if ($args[0] == C('VAR_CONTROLLER')) {
                    $_GET[$args[0]] = $args[1];
                    array_shift($args);
                    array_shift($args);
                } else {
                    $_GET[C('VAR_CONTROLLER')] = $args[0];
                    array_shift($args);
                }
            }

            //动作
            if (empty($args[0])) {
                $_GET[C('VAR_ACTION')] = C('DEFAULT_ACTION');
            } else {
                if ($args[0] == C('VAR_ACTION')) {
                    $_GET[$args[0]] = $args[1];
                    array_shift($args);
                    array_shift($args);
                } else {
                    $_GET[C('VAR_ACTION')] = $args[0];
                    array_shift($args);
                }
            }
            //其他$_GET数据
            if (!empty($args[0]) && count($args) % 2 == 0) {
                $count = count($args);
                for ($i = 0; $i < $count;) {
                    $_GET[$args [$i]] = isset($args [$i + 1]) ? $args [$i + 1] : '';
                    $i += 2;
                }
            }


        //模块名大小写
        $_GET[C('VAR_MODULE')] = ucwords($_GET[C('VAR_MODULE')]);
		//控制器
        $_GET[C('VAR_CONTROLLER')] = str_replace('!', '', ucwords(str_replace('_', '!', $_GET[C('VAR_CONTROLLER')])));
		//兼容模式删除其变量
        if (C('URL_TYPE') == 2) {
            unset($_GET[C('PATHINFO_VAR')]);
        }
        $_REQUEST = array_merge($_REQUEST, $_GET);
        //设置常量
        self::setConst();
    }

    /**
     * 设置常量
     */
    static private function setConst(){
        //域名
        $host = $_SERVER['HTTP_HOST'] ? $_SERVER['HTTP_HOST'] : $_SERVER['SERVER_NAME'];
        defined('__HOST__') or define("__HOST__", C("HTTPS") ? "https://" : "http://" . $host);

        //网站根-含入口文件
        $root = rtrim(dirname(rtrim($_SERVER['SCRIPT_NAME'], '/')), '/');
        defined('__APP__') or define("__APP__",  ($root == '/' || $root == '\\' ? '' : $root));

        //网站根-不含入口文件

        defined('__ROOT__') or define("__ROOT__",rtrim(APP_PATH,ucwords(ltrim(__APP__,'/').'/')).'/');

	    define('__TPL__',__HOST__.'/'.TPL_PATH);//定义模板路径

		//完整URL地址
        defined('__URL__') or define("__URL__", __HOST__ . '/' . trim($_SERVER['REQUEST_URI'], '/'));

		//公共目录
        defined('__PUBLIC__') or define("__PUBLIC__", __HOST__ . __APP__ . '/Data/Public');

		//模块
        defined('MODULE') or define("MODULE", ucfirst($_GET[C('VAR_MODULE')]));

		//控制器
        defined('CONTROLLER') or define("CONTROLLER", ucfirst($_GET[C('VAR_CONTROLLER')]));

		//方法
        defined('ACTION') or define("ACTION", $_GET[C('VAR_ACTION')]);

        defined('__MODULE__') or define("__MODULE__",  MODULE);

		defined('__CONTROLLER__') or define("__CONTROLLER__", CONTROLLER);

		defined('__ACTION__') or define("__ACTION__", ACTION);
    }

    /**
     * 分析路由
     * @param string $query
     * @return mixed
     */
    static private function parseRoute($query){
        $query = str_ireplace(C('HTML_SUFFIX'), '', trim($query, '/'));
        $route = C("ROUTE");
        if (!$route or !is_array($route)) return $query;
        foreach ($route as $k => $v) {
            //正则路由
            if (preg_match("@^/.*/[isUx]*$@i", $k)) {
                //如果匹配URL地址
                if (preg_match($k, $query)) {
                    //元子组替换
                    $v = str_replace('#', '\\', $v);
                    //匹配当前正则路由,url按正则替换
                    return preg_replace($k, $v, $query);
                }
                //下一个路由规则
                continue;
            }
            //非正则路由
            $search = array(
                '@(:year)@i',
                '@(:month)@i',
                '@(:day)@i',
                '@(:num)@i',
                '@(:any)@i',
                '@(:[a-z0-9]+\\\d)@i',
                '@(:[a-z0-9]+\\\w)@i',
                '@(:[a-z0-9]+)@i'
            );
            $replace = array(
                '\d{4}',
                '\d{1,2}',
                '\d{1,2}',
                '\d+',
                '.+',
                '\d+',
                '\w+',
                '([a-z0-9]+)'
            );
            //将:year等替换
            $base_preg = "@^" . preg_replace($search, $replace, $k) . "$@i";
            //不满足路由规则
            if (!preg_match($base_preg, $query)) {
                continue;
            }
            //满足路由，但不存在参数如:uid等
            if (!strstr($k, ":")) {
                return $v;
            }
            /**
             * user/:id=>user/1
             */
            $vars = "";
            preg_match('/[^:\sa-z0-9]/i', $k, $vars);
            //:id=>"index/index"
            if (isset($vars[0])) {
                //拆分路由获得:id
                $roles_ex = explode($vars[0], $k);
                //上例中拆分请求参数获得1
                $url_args = explode($vars[0], $query);
            } else {
                $roles_ex = array($k);
                $url_args = array($query);
            }
            //匹配路由规则
            $query = $v;
            foreach ($roles_ex as $m => $n) {
                if (!strstr($n, ":")) {
                    continue;
                }
                $_GET[str_replace(":", "", $n)] = $url_args[$m];
            }
            return $query;
        }
        return $query;
    }


    /**
     * 将URL按路由规则进行处理
     * U()函数等使用
     * @access public
     * @param  string $url url字符串不含__APP__.'?|/'
     * @return string
     */
    static public function toUrl($url)
    {
        $route = C("route");
        /**
         * 未定义路由规则
         */
        if (!$route) {
            return $url;
        }
        foreach ($route as $routeKey => $routeVal) {
            $routeKey = trim($routeKey);
            //正则路由
            if (substr($routeKey, 0, 1) === '/') {
                $regGroup = array(); //识别正则路由中的原子组
                preg_match_all("@\(.*?\)@i", $routeKey, $regGroup, PREG_PATTERN_ORDER);
                //路由规则Value
                $searchRegExp = $routeVal;
                //将正则路由的Value中的值#1换成(\d+)等形式
                for ($i = 0, $total = count($regGroup[0]); $i < $total; $i++) {
                    $searchRegExp = str_replace('#' . ($i + 1), $regGroup[0][$i], $searchRegExp);
                }
                //URL参数
                $urlArgs = array();
                //当前URL是否满足本次路由规则，如果满意获得url参数（原子组）
                preg_match_all("@^" . $searchRegExp . "$@i", $url, $urlArgs, PREG_SET_ORDER);
                //满足路由规则
                if ($urlArgs) {
                    //清除路由中的/$与/正则边界
                    $routeUrl = trim(preg_replace(array('@/\^@', '@/[isUx]$@', '@\$@'), array('', '', ''), $routeKey), '/');
                    /**
                     * 将路由规则中的(\d+)等形式替换为url中的具体值
                     * /admin(\d).html/   => admin1.html
                     */
                    foreach ($regGroup[0] as $k => $v) {
                        $v = preg_replace('@([\*\$\(\)\+\?\[\]\{\}\\\])@', '\\\$1', $v);
                        $routeUrl = preg_replace('@' . $v . '@', $urlArgs[0][$k + 1], $routeUrl, $count = 1);
                    }
                    return trim($routeUrl, '/');
                }
            } else {
                //获得如 "info/:city_:row" 中的:city与:row
                $routeGetVars = array();
                //普通路由处理
                //获得路由规则中以:开始的变量
                preg_match_all('/:([a-z]*)/i', $routeKey, $routeGetVars, PREG_PATTERN_ORDER);
                $getArgs = array();
                preg_match_all($routeVal, $url, $getArgs, PREG_SET_ORDER);
                if ($getArgs) {
                    //去除路由中的传参数如:uid
                    $newUrl = $routeKey;
                    foreach ($routeGetVars[0] as $rk => $getName) {
                        $newUrl = str_replace($getName, $getArgs[0][$rk + 1], $newUrl);
                    }
                    return $newUrl;
                }
            }
        }
        return $url;
    }

    /**
     * 根据配置文件的URL参数重新生成URL地址
     * @param String $path 访问url
     * @param array $args GET参数
     * @return string
     */
    static public function getUrl($path,$repath, $args = array()){

		if (preg_match('/^https?:\/\//', $path)) {
            return $path;
        }

		//参数$args为字符串时转数组
        if (is_string($args)) {parse_str($args, $args);}
        $args = empty($args) ? '' : '&'.http_build_query($args);

        /**
         * 开启伪静态时去除入口文件
         */
		$root = C('URL_REWRITE') ? preg_replace('/\/?[a-z]+\.php/i', '', __APP__) : __APP__;
		$root .= (C('URL_REWRITE') ? '/' : '?') . C('PATHINFO_VAR') . '=';

		if(C('URL_REWRITE') && !empty($repath)){
			return $repath;
		}

        if (preg_match('@[^\w/]@i', $path)) {
            /**
             * 参数如: m=Index&c=Index&a=index&cid=1&page=2
             * 这样形式时直接进行路由解析
             * 比如在分页类时使用
             */
            return $root . Route::toUrl($path.$args);
        } else {

            return __HOST__.'/'.__APP__ . $root . Route::toUrl($path.$args);
        }
    }
}