<?php

namespace xmvc;

/**
 * 控制器的返回值类
 *
 */
class ReturnClass
{
    protected $innerCode = R_OK;
    protected $innerData = null;
    protected $innerMsg = null;
    protected $innerExt = null;
    protected $innerError = null; // 记录当前的 debug_backtrace
    protected $isChecked = false; // 是否进行过合法性检查，不管是否合法
    public $header = null;  // 用于模板的<head></head>中的变量
    public $headerPropertys = ['title', 'description', 'keywords']; // header 支持的属性


    public function __get($var)
    {
        if ($var == 'isOK') {
            return $this->isOK();
        } elseif ($var == 'isNO') {
            return $this->isNO();
        } else {
            if (!$this->isChecked) {
                $this->check();
            }
            return $this->{'inner' . ucfirst($var)};
        }
    }

    public function isOK(): bool
    {
        if (!$this->isChecked) {
            $this->check();
        }
        return $this->innerCode & R_OK;
    }

    public function isNO(): bool
    {
        if (!$this->isChecked) {
            $this->check();
        }
        return $this->innerCode & R_NO;
    }

    public function info(string $msg): self
    {
        $this->innerCode = R_OK | R_INFO;
        $this->innerMsg = $msg;
        return $this;
    }

    public function warning(string $msg): self
    {
        $this->innerCode = $this->innerCode | R_WARNING;
        $this->innerMsg = $msg;
        return $this;
    }

    public function error(string $msg): self
    {
        $this->innerCode = R_NO | R_ERROR;
        $this->innerMsg = $msg;
        return $this;
    }

    public function code(int $code): self
    {
        $this->innerCode = $code;
        return $this;
    }

    /**
     * 返回的数据, 如果需要调用模板,$data数组中不要出现return,header,footer的键,它们被另做它用
     *
     * @param mixed $data
     * @return self
     */
    public function data($data): self
    {
        $this->innerData = $data;
        return $this;
    }

    public function msg(string $msg): self
    {
        $this->innerMsg = $msg;
        return $this;
    }

    public function ext($ext): self
    {
        $this->innerExt = $ext;
        return $this;
    }

    /**
     * 返回值检测
     * code 值为常量 R_OK, R_NO, R_INFO, R_WARNING, R_ERROR 或者是它们的集合 ,
     * code 值必须包括有 R_OK 或者 R_NO 这两个的一个,
     * code 值如果有 R_INFO, R_WARNING, R_ERROR, 则必须显性的调用 msg() 方法,
     * 如果同时包括 R_OK 和 R_NO 将只保留 R_NO,
     * code 值如果同时包括 R_OK 和 R_ERROR, 则 R_OK 移除, 并加上 R_NO
     * 如果有调用 msg(), 并且没有指定 R_INFO, R_WARNING, R_ERROR 中的一个,则 R_OK 默认 R_OK|R_INFO, R_NO 默认 R_NO|R_ERROR
     * 如果 code 有 R_NO 与 R_WARNING, R_ERROR 中的一个,将会创建错误跟踪信息
     * ext 扩展值，用于自定义特殊业务逻辑
     * @param [type] $ext
     * @return self
     */
    public function check(): self
    {
        $this->isChecked = true;
        if (!($this->innerCode & (R_OK | R_NO))) {
            throw new \Exception('code 值必须包括有 R_OK 或者 R_NO 这两个的一个');
        }
        if (($this->innerCode & (R_INFO | R_WARNING | R_ERROR))  && is_null($this->msg)) {
            throw new \Exception('code 值有 R_INFO, R_WARNING, R_ERROR, 则必须显性的调用 msg() 方法');
        }
        if (($this->innerCode & (R_OK | R_NO)) === (R_OK | R_NO)) {
            $this->innerCode &= ~R_OK;
        }
        if (($this->innerCode & (R_OK | R_ERROR)) === (R_OK | R_ERROR)) {
            $this->innerCode &= ~R_OK;
            $this->innerCode |= R_NO;
        }
        if (!($this->innerCode & (R_INFO | R_WARNING | R_ERROR)) && !is_null($this->msg)) {
            $this->innerCode  |= ($this->innerCode  & R_OK) ? R_INFO : R_ERROR;
        }
        if (($this->innerCode & R_NO) && ($this->code & (R_WARNING | R_ERROR))) {
            $backtrace = debug_backtrace(DEBUG_BACKTRACE);
            $this->innerError = [
                'type' => $this->code & R_ERROR ?  E_ERROR : E_WARNING,
                'file' => $backtrace[0]['file'],
                'line' => $backtrace[0]['line'],
                'method' => $backtrace[1]['function'] . '::' . $backtrace[1]['class'] . '()',
                'message' => $this->msg
            ];
        }
        return $this;
    }

    /**
     * 用于模板文件的<head></head>之间的变量处理
     *
     * @return self
     */
    public function header(array $params): self
    {
        if (is_null($this->header)) {
            $this->header = new \stdClass();
        }
        foreach ($this->headerPropertys as $key) {
            if ($params && isset($params[$key])) {
                $this->header->$key = $params[$key];
            } else {
                $this->header->$key = MVC::$cfg['header'][$key];
            }
        }
        return $this;
    }

    public function array(): array
    {
        if (!$this->isChecked) {
            $this->check();
        }
        return [
            'code' => $this->innerCode,
            'data' => $this->innerData,
            'msg'  => $this->innerMsg,
            'ext'  => $this->innerExt,
        ];
    }
}
