// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006~2016 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------

namespace think;
// 路由器 我来了
use think\App;
use think\Config;
use think\exception\HttpException;
use think\Hook;
use think\Loader;
use think\Log;
use think\Request;
use think\Response;
// 召唤各种工具
class Route
{
    // 路由规则
    private static $rules = [// 初始化 各种 规则
        'GET'     => [],
        'POST'    => [],
        'PUT'     => [],
        'DELETE'  => [],
        'PATCH'   => [],
        'HEAD'    => [],
        'OPTIONS' => [],
        '*'       => [],
        'alias'   => [],
        'domain'  => [],
        'pattern' => [],
        'name'    => [],
    ];

    // REST路由操作方法定义
    private static $rest = [// 重置 方法 REST 路由操作方法 定义
        'index'  => ['GET', '', 'index'],
        'create' => ['GET', '/create', 'create'],
        'edit'   => ['GET', '/:id/edit', 'edit'],
        'read'   => ['GET', '/:id', 'read'],
        'save'   => ['POST', '', 'save'],
        'update' => ['PUT', '/:id', 'update'],
        'delete' => ['DELETE', '/:id', 'delete'],
    ];

    // 不同请求类型的方法前缀
    private static $methodPrefix = [// 不同请求类型的 方法前缀
        'GET'    => 'get',
        'POST'   => 'post',
        'PUT'    => 'put',
        'DELETE' => 'delete',
    ];

    // 子域名
    private static $subDomain = '';// 子域名
    // 域名绑定
    private static $bind = [];// 绑定域名
    // 当前分组信息
    private static $group = [];// 分组信息
    // 当前子域名绑定
    private static $domainBind;// 子域名绑定
    private static $domainRule;// 规则
    // 当前域名
    private static $domain;// 当前域名

    /**
     * 注册变量规则
     * @access public
     * @param string|array  $name 变量名
     * @param string        $rule 变量规则
     * @return void
     */
    public static function pattern($name = null, $rule = '')
    {// 注册变量规则
        if (is_array($name)) {// 如果是数组 合并注册
            self::$rules['pattern'] = array_merge(self::$rules['pattern'], $name);
        } else {// 单独 注册
            self::$rules['pattern'][$name] = $rule;
        }// 设置 变量规则
    }

    /**
     * 注册子域名部署规则
     * @access public
     * @param string|array  $domain 子域名
     * @param mixed         $rule 路由规则
     * @param array         $option 路由参数
     * @param array         $pattern 变量规则
     * @return void
     */
    public static function domain($domain, $rule = '', $option = [], $pattern = [])
    {// 注册子域名 部署规则  子域名 路由规则 路由参数 变量规则
        if (is_array($domain)) {// 如果是数组  其它没有了
            foreach ($domain as $key => $item) {// 遍历执行自己
                self::domain($key, $item, $option, $pattern);
            }
        } elseif ($rule instanceof \Closure) {// 如果规则 是个闭包
            // 执行闭包
            self::setDomain($domain);// 设置域名
            call_user_func_array($rule, []);// 执行闭包 不加参数
            self::setDomain(null);// 再次设置域名 但是 为空
        } elseif (is_array($rule)) {// 如果是数组
            self::setDomain($domain);// 设置了 域名
            self::group('', function () use ($rule) {// 设置闭包 多执行 函数
                // 动态注册域名的路由规则
                self::registerRules($rule);
            }, $option, $pattern);
            self::setDomain(null);// 设置域名 为空
        } else {// 通用的规则设置
            self::$rules['domain'][$domain]['[bind]'] = [$rule, $option, $pattern];
        }
    }

    private static function setDomain($domain)// 设置 或者 清空 当前域名
    {
        self::$domain = $domain;
    }

    /**
     * 设置路由绑定
     * @access public
     * @param mixed     $bind 绑定信息
     * @param string    $type 绑定类型 默认为module 支持 namespace class
     * @return mixed
     */
    public static function bind($bind, $type = 'module')// 设置路由绑定
    {
        self::$bind = ['type' => $type, $type => $bind];// 设置 当前 绑定 默认的是 模块
    }

    /**
     * 设置或者获取路由标识
     * @access public
     * @param string|array     $name 路由命名标识 数组表示批量设置
     * @param array            $value 路由地址及变量信息
     * @return array
     */
    public static function name($name = '', $value = null)
    {// 设置 或者 获取路由 标识
        if (is_array($name)) {// 如果是 数组 直接设置 完成
            return self::$rules['name'] = $name;
        } elseif ('' === $name) {// 如果是字符串
            return self::$rules['name'];// 返回当前
        } elseif (!is_null($value)) { // 如果不为空
            self::$rules['name'][$name][] = $value;// 当前的 为空
        } else {// 设置 规则
            return isset(self::$rules['name'][$name]) ? self::$rules['name'][$name] : null;
        }
    }

    /**
     * 读取路由绑定
     * @access public
     * @param string    $type 绑定类型
     * @return mixed
     */
    public static function getBind($type)
    {// 读取路由绑定
        return isset(self::$bind[$type]) ? self::$bind[$type] : null;// 如果设置了 返回,否则 为空
    }

    /**
     * 导入配置文件的路由规则
     * @access public
     * @param array     $rule 路由规则
     * @param string    $type 请求类型
     * @return void
     */
    public static function import(array $rule, $type = '*')
    {// 导入配置文件的路由规则
        // 检查域名部署
        if (isset($rule['__domain__'])) {// 如果 设置 域名里面的规则
            self::domain($rule['__domain__']);// 当前 域名 规则
            unset($rule['__domain__']);// 删除 已经导入的规则
        }

        // 检查变量规则
        if (isset($rule['__pattern__'])) {// 检查变量规则
            self::pattern($rule['__pattern__']);//导入规则
            unset($rule['__pattern__']);// 清空
        }

        // 检查路由别名
        if (isset($rule['__alias__'])) {
            self::alias($rule['__alias__']);
            unset($rule['__alias__']);
        }// 同上

        // 检查资源路由
        if (isset($rule['__rest__'])) {
            self::resource($rule['__rest__']);
            unset($rule['__rest__']);
        }// 同上

        self::registerRules($rule, strtoupper($type));// 注册 新 规则
    }

    // 批量注册路由
    protected static function registerRules($rules, $type = '*')
    {// 批量注册路由
        foreach ($rules as $key => $val) {// 批量 意味着 就是 遍历
            if (is_numeric($key)) {// 当 为数字
                $key = array_shift($val);// 抛出
            }
            if (empty($val)) {// 如果 为空,值,跳出当前循环,然后继续
                continue;
            }
            if (is_string($key) && 0 === strpos($key, '[')) {// 如果是 字符串 并 以 '['开头
                $key = substr($key, 1, -1);// 如果 截取 最后的
                self::group($key, $val);// 当前 分组 $key 跟 $val 区别
            } elseif (is_array($val)) {// 如果是 数组
                self::setRule($key, $val[0], $type, $val[1], isset($val[2]) ? $val[2] : []);
            } else {// 设置 Rule
                self::setRule($key, $val, $type);
            }
        }
    }