<?php

namespace Qii\Base;

use Qii\Config\Consts;
use Qii\Config\Register;
use Qii\Request\Url;
abstract class Request
{
    public $host = '';
    public $module;
    public $controller;
    public $action;
    public $method;

    public $dispatcher;


    protected $params;

    protected $language;

    protected $_exception;

    protected $_baseUri = '';

    protected $uri = '';

    protected $dispatched = false;

    protected $routed = false;

    protected $forward = false;
    /**
     * @var Qii\Request\Url url
     */
    public $url;

    private static $context = array();

    /**
     * 初始化参数，获取链接中对应的参数并存放到$this->params中
     *
     */
    public function __construct()
    {
        foreach ($_GET AS $key => $val) {
            $this->setParam($key, $val);
        }
        $rewriteRule = \Qii::getInstance()->appConfigure(Consts::APP_SITE_METHOD);
        //如果获取配置文件失败，就是会用默认短链的形式
        if ($rewriteRule == null) $rewriteRule = "Short";
        $this->url = new Url($rewriteRule);
        $this->host = IS_CLI ? '' : $_SERVER['HTTP_HOST'];
        $params = (array)$this->url->getParams();
        if(count($params) > 0) $this->params = array_merge($this->params, $params);
        $routeInfo = (array)$this->url->getPathArgs();
		$controller = $this->defaultController();
        $action = $this->defaultAction();
        //cli 模式处理
        if(IS_CLI) {
            $routeInfo = $this->url->request->getCliPathArgs();
        }
        // 防止异步请求因为中间有内容输出导致header输出失败
        ob_start();
		if(count($routeInfo) > 1)
		{
			$action = array_pop($routeInfo);
			$controller = join("\\", $routeInfo);
		}
		else if(count($routeInfo) == 1 && !empty($routeInfo[0])) {
			$controller = $routeInfo[0];
		}        //处理url中的数据
        if (ucwords($rewriteRule) == 'Short') {
            $this->setControllerName($controller);
            $this->setActionName($action);
        }
        return $this;
    }

    /**
     * request context
     * @param string $key
     * @param string $val
     * @return void
     */
    public function setContext($key, $val) {
        self::$context[$key] = $val;
    }

    /**
     * 获取context
     * @param string $key
     * @return mixed|null
     */
    public function getContext($key) {
        return isset(self::$context[$key]) ? self::$context[$key]: null;
    }

    /**
     * 获取POST数据
     */
    public function post($name = null, $default = null)
    {
        return call_user_func_array(array($this->url, 'post'), func_get_args());
    }


    /**
     * get key是否存在
     * @param string $key
     * @return bool
     */
    public function hasGetKey($key) {
        if($_GET && isset($_GET[$key])) {
            return true;
        }
        return false;
    }

    /**
     * post key是否存在
     * @param string $key
     * @return bool
     */
    public function hasPostKey($key) {
        if($_POST && isset($_POST[$key])) {
            return true;
        }
        return false;
    }
    /**
     * 默认controller
     */
    public function defaultController()
    {
        return Register::get(Consts::APP_DEFAULT_CONTROLLER, 'index');
    }

    /**
     * 默认action
     */
    public function defaultAction()
    {
        return Register::get(Consts::APP_DEFAULT_ACTION, 'index');
    }

    /**
     * 获取当前数据处理
     */
    public function uri()
    {
        return $this->uri;
    }

    public function redirect($url)
    {
        ob_clean();
        header('Location:' . $url);
    }

    /**
     * isGet
     *
     * @param void
     * @return boolean
     */
    public function isGet()
    {
        return (strtoupper($this->method) == 'GET');
    }

    /**
     * isPost
     *
     * @param void
     * @return boolean
     */
    public function isPost()
    {
        return (strtoupper($this->method) == 'POST');
    }

    /**
     * isPut
     *
     * @param void
     * @return boolean
     */
    public function isPut()
    {
        return (strtoupper($this->method) == 'PUT');
    }

    /**
     * isPut
     *
     * @param void
     * @return boolean
     */
    public function isDelete()
    {
        return (strtoupper($this->method) == 'DELETE');
    }
    /**
     * isHead
     *
     * @param void
     * @return boolean
     */
    public function isHead()
    {
        return (strtoupper($this->method) == 'HEAD');
    }

    /**
     * 获取header信息
     * @param $key
     * @return array|false|mixed|string|null
     */
    public function head($key = null) {
        $header = getallheaders();
        $key = ucwords($key);
        if($key != null) {
            return isset($header[$key]) ? $header[$key] : null;
        }
        return $header;
    }
    /**
     * isOptions
     *
     * @param void
     * @return boolean
     */
    public function isOptions()
    {
        return (strtoupper($this->method) == 'OPTIONS');
    }

    /**
     * isCli
     *
     * @param void
     * @return boolean
     */
    public function isCli()
    {
        return (strtoupper($this->method) == 'CLI');
    }

    /**
     * isXmlHttpRequest
     *
     * @param void
     * @return boolean
     */
    public function isXmlHttpRequest()
    {
        return false;
    }

    /**
     * getServer
     *
     * @param string $name
     * @param mixed $default
     * @return mixed
     */
    public function getServer($name = null, $default = null)
    {
        if (is_null($name)) {
            return $_SERVER;
        } elseif (isset($_SERVER[$name])) {
            return $_SERVER[$name];
        }
        return $default;
    }

    /**
     * getEnv
     *
     * @param string $name
     * @param mixed $default
     * @return mixed
     */
    public function getEnv($name = null, $default = null)
    {
        if (is_null($name)) {
            return $_ENV;
        } elseif (isset($_ENV[$name])) {
            return $_ENV[$name];
        }
        return $default;
    }

    /**
     * setParam
     *
     * @param mixed $name
     * @param mixed $value
     * @return $this
     */
    public function setParam($name, $value = null)
    {
        if (is_null($value)) {
            if (is_array($name)) {
                $this->params = array_merge($this->params, $name);
            }
        } elseif (is_string($name)) {
            $this->params[$name] = $value;
        }
        return $this;
    }

    /**
     * getParam
     *
     * @param string $name
     * @param mixed $default
     * @return mixed
     */
    public function getParam($name, $dafault = null)
    {
        if (isset($this->params[$name])) {
            return $this->params[$name];
        }
        return $dafault;
    }

    /**
     * setParams
     *
     * @param array $params
     * @return $this
     */
    public function setParams($params)
    {
        if (is_array($params)) {
            $this->params = $params;
        }
        return $this;
    }

    /**
     * getParams
     *
     * @param void
     * @return array
     */
    public function getParams()
    {
        return $this->params;
    }

    /**
     * setException
     *
     * @param Exception $exception
     * @return $this
     */
    public function setException($exception)
    {
        if (is_object($exception)
            && ($exception instanceof Exception)
        ) {
            $this->_exception = $exception;
        }
        return $this;
    }

    /**
     * getException
     *
     * @param void
     * @return Exception
     */
    public function getException()
    {
        if (is_object($this->_exception)
            && ($this->_exception instanceof Exception)
        ) {
            return $this->_exception;
        }
        return null;
    }


    /**
     * getModuleName
     *
     * @param void
     * @return string
     */
    public function getModuleName()
    {
        return $this->module;
    }

    /**
     * getControllerName
     *
     * @param void
     * @return string
     */
    public function getControllerName()
    {
        return $this->controller;
    }

    /**
     * getActionName
     *
     * @param void
     * @return string
     */
    public function getActionName()
    {
        return $this->action;
    }

    /**
     * setModuleName
     *
     * @param string $name
     * @return $this
     */
    public function setModuleName($name)
    {
        if (!is_string($name)) {
            trigger_error('Expect a string module name', E_USER_WARNING);
            return $this;
        }
        $this->module = $name;
        return $this;
    }

    /**
     * setControllerName
     *
     * @param string $name
     * @return $this
     */
    public function setControllerName($name)
    {
        if (!is_string($name)) {
            trigger_error('Expect a string controller name', E_USER_WARNING);
            return $this;
        }
        $this->controller = $name;
        return $this;
    }

    /**
     * setActionName
     *
     * @param string $name
     * @return $this
     */
    public function setActionName($name)
    {
        if (!is_string($name)) {
            trigger_error('Expect a string action name', E_USER_WARNING);
            return $this;
        }
        $this->action = $name;
        return $this;
    }

    /**
     * getMethod
     *
     * @param void
     * @return string
     */
    public function getMethod()
    {
        return $this->method;
    }

    /**
     * getLanguage
     *
     * @param void
     * @return string
     */
    public function getLanguage()
    {
        return $this->language;
    }

    /**
     * setBaseUri
     *
     * @param string $baseUri
     * @return $this
     */
    public function setBaseUri($baseUri)
    {
        if ($baseUri && is_string($baseUri)) {
            $this->_baseUri = $baseUri;
        }
        return $this;
    }

    /**
     * getBaseUri
     *
     * @param void
     * @return string
     */
    public function getBaseUri()
    {
        return $this->_baseUri;
    }

    /**
     * setRequestUri
     *
     * @param string $uri
     * @return $this
     */
    public function setRequestUri($uri)
    {
        if (is_string($uri)) {
            $this->uri = $uri;
        }
        return $this;
    }

    /**
     * getRequestUri
     *
     * @param void
     * @return string
     */
    public function getRequestUri()
    {
        return $this->uri;
    }

    /**
     * isDispatched
     *
     * @param void
     * @return boolean
     */
    public function isDispatched()
    {
        return (boolean)$this->dispatched;
    }

    /**
     * setDispatched
     *
     * @param boolean $flag
     * @return boolean | Qii_Request_Abstract
     */
    public function setDispatched($flag = true)
    {
        if (is_bool($flag)) {
            $this->dispatched = $flag;
            $content = ob_get_contents();
            ob_end_clean();
            echo ($content);
            return $this;
        }
        $content = ob_get_contents();
        ob_end_clean();
        echo ($content);
        return false;
    }

    /**
     * 设置dispatcher
     *
     * @param \Qii\Controller\Dispatcher $dispatcher
     */
    public function setDispatcher(Dispatcher $dispatcher)
    {
        $this->dispatcher = $dispatcher;
    }

    /**
     * isRouted
     *
     * @param void
     * @return boolean
     */
    public function isRouted()
    {
        return $this->routed;
    }

    /**
     * setRouted
     *
     * @param boolean $flag
     * @return boolean | \Qii\Request\Abstract
     */
    public function setRouted($flag = true)
    {
        if (is_bool($flag)) {
            $this->routed = $flag;
            return $this;
        }
        return false;
    }

    /**
     * 是否需要转发
     */
    public function isForward()
    {
        return $this->forward;
    }

    /**
     * 设置是否需要转发
     * @param bool $flag
     * @return $this
     */
    public function setForward($flag = true)
    {
        if (is_bool($flag)) {
            $this->forward = $flag;
            return $this;
        }
        return $this;
    }

    /**
     * __setbaseUri
     *
     * @param string $baseUri
     * @param string $requestUri
     * @return boolean
     */
    protected function _setBaseUri($baseUri, $requestUri = null)
    {
        if ($baseUri && is_string($baseUri)) {
            $this->_baseUri = $baseUri;

            return true;
        } elseif ($requestUri && is_string($requestUri)) {
            $scriptFileName = $this->getServer('SCRIPT_FILENAME');

            do {
                if ($scriptFileName && is_string($scriptFileName)) {
                    $suffer = (string) \Qii::getInstance()->appConfigure('ext', '.php');
                    $fileName = basename($scriptFileName, $suffer);
                    $fileNameLen = strlen($fileName);

                    $scriptName = $this->getServer('SCRIPT_NAME');
                    if ($scriptName && is_string($scriptName)) {
                        $script = basename($scriptName);

                        if (strncmp($fileName, $script, $fileNameLen) == 0) {
                            $basename = $scriptName;
                            break;
                        }
                    }

                    $phpSelfName = $this->getServer('PHP_SELF');
                    if ($phpSelfName && is_string($phpSelfName)) {
                        $phpSelf = basename($phpSelfName);
                        if (strncmp($fileName, $phpSelf, $fileNameLen) == 0) {
                            $basename = $phpSelfName;
                            break;
                        }
                    }

                    $orig_name = $this->getServer('ORIG_SCRIPT_NAME');
                    if ($orig_name && is_string($orig_name)) {
                        $orig = basename($orig_name);
                        if (strncmp($fileName, $orig, $fileNameLen) == 0) {
                            $basename = $orig_name;
                            break;
                        }
                    }
                }
            } while (0);

            if ($basename && strstr($requestUri, $basename) == $requestUri) {
                $this->_baseUri = rtrim($basename, '/');

                return true;
            } elseif ($basename) {
                $dirname = rtrim(dirname($basename), '/');
                if ($dirname) {
                    if (strstr($requestUri, $dirname) == $requestUri) {
                        $this->_baseUri = $dirname;

                        return true;
                    }
                }
            }

            $this->_baseUri = '';

            return true;
        }

        return false;
    }

    /**
     * 获取uri的extension
     *
     * @return array|string|string[]
     */
    public function getExtension() {
        $extension = pathinfo($this->uri, PATHINFO_EXTENSION);
        return $extension != "" ? $extension : "html";
    }

    /**
     * 对于不存在的方法默认调用url中的方法
     */
    public function __call($method, $args)
    {
        return call_user_func_array(array($this->url, $method), $args);
    }
}