<?php
class View {

	// 模板变量
    public $vars = array();
    // 模版文件
    public $tplFile = null;
    // 编译文件
    public $compileFile = null;

	//模板赋值
	public function assign($name, $value = '') {
		if( is_array($name) ){
			foreach($name as $k => $v){
				$this->vars[$k] = $v;
			}
		} else {
			$this->vars[$name] = $value;
		}
	}

	//执行模板解析输出
    public function display($tplFile = null, $cacheTime = null, $cachePath = null,$cacheName= null, $contentType = "text/html", $show = true) {
		//缓存路径
		$cachePath = is_null($cachePath) ? C('TPL_CACHE_PATH').TPL_STYLE : $cachePath;

		//缓存文件名
		$cacheName = is_null($cacheName) ? md5($_SERVER['REQUEST_URI']) : $cacheName;

		//缓存时间
		$cacheTime = is_numeric($cacheTime) ? $cacheTime : intval(C('TPL_CACHE_TIME'));

		//内容
		$content = null;
		if ($cacheTime >= 0) {
			$content = S(
				$cacheName, false, $cacheTime,
				array("dir" => $cachePath, 'zip' => false, "Driver" => "File")
			);
		}

		//缓存失效
		if (!$content) {

			//获得模板文件
			$this->tplFile = $this->getTemplateFile($tplFile);

			if (!$this->tplFile) {
				return;
			}

			//编译目录
			$this->compilePath = C('TPL_COMPILE_PATH') . TPL_STYLE .'/'. MODULE .'/'. ACTION;

			//编译文件
			$this->compileFile = $this->compilePath . '_' . substr(md5($this->tplFile), 0, 10) . C('TPL_CACHE_SUFFIX');

			//记录模板编译文件
			if (DEBUG) {
			   Debug::$tpl[] = array(basename($this->tplFile),$this->compileFile);
			}

			//编译文件失效（不存在或过期）
			if ($this->compileInvalid()) {
				//执行编译
				$this->compile();
			}

			//加载全局变量
            if (!empty($this->vars)) {
                extract($this->vars);
            }

			ob_start();

			//加载已编译文件
			include($this->compileFile);
			$content = ob_get_clean();

			 //写入缓存
            if ($cacheTime >= 0) {
                S(
                    $cacheName, $content, $cacheTime,
                    array("dir" => $cachePath, 'zip' => false, "Driver" => "File")
                );
            }
		}
		if($show){
			$charset = C('TPL_CHARSET') ? C('TPL_CHARSET') : 'UTF-8';
			if (!headers_sent()) {
				header("Content-type:" . $contentType . ';charset=' . $charset);
			}
			echo $content;
		}else{
			return $content;
		}
	}


	/**
     * 编译是否失效
     * @return bool true 失效
     */
    private function compileInvalid(){
        return DEBUG ||
			   !file_exists($this->compileFile) ||
			   (filemtime($this->tplFile) > filemtime($this->compileFile));
    }

	/**
     * 获取模版文件
     * @param $file 模板文件
     * @return bool|string
     */
    static public function getTemplateFile($file){

        //没有传参时使用 动作为为文件名
        if(is_null($file)) $file = MODULE . '/' . ACTION;

         //模板文件检测
		foreach (C('TPL_SUFFIX') as $suffix) {
			$full_file = TPL_PATH .'/'.$file.$suffix;
			if (is_file($full_file)){
				return $full_file;
			}
		}

        _404('模板不存在:'.$full_file);
        return false;
    }


	//编译模板
	private function compile() {
        // 编译是否失效
        if (!$this->compileInvalid()) {
            return;
        }

		//模板内容
		$this->content = "<?php if (!defined('APP_PATH')) exit;?>".
						 preg_replace("/\<!--{[\s\S]*?}--\>/","",file_get_contents($this->tplFile));

		//解析图片，CSS，JS 路径
		$this->parseHtml();
		//解析标签
		$this->parseTag();
		//解析常量
		$this->parseUrlConst();
		//解析变量
		$this->parseVar();

        //创建编译目录与安全文件
        Files::create(dirname($this->compilePath));

        Files::safeFile(dirname($this->compilePath));

        //储存编译文件
		file_put_contents($this->compileFile, $this->content);
	}

	/**
     * 解析图片，CSS，JS 路径
     * @return mixed
     */
    private function parseHtml(){
		$pregarr[0]   = '/<img(.*?)src=("|\')images\/(.*?)\.(jpg|jpeg|gif|png|bmp|JPG|JPEG|GIF|PNG|BMP)("|\')(.*?)>/i';
		$pregarr[1]   = '/<link(.*?)href=("|\')(.*?)\.css(.*?)("|\')(.*?)>/i';
		$pregarr[2]   = '/<script(.*?)src=("|\')(.*?)\.js(.*?)("|\')(.*?)>/i';
		foreach ($pregarr as $key => $preg) {
			$status = preg_match_all($preg, $this->content, $info,PREG_SET_ORDER);
			if($status){
				foreach ($info as $vo) {
					if(!strstr($vo[0],'__')){
						$replace[0]  = '<img'.$vo[1].'src='.$vo[2].__TPL__.'/images/'.$vo[3].'.'.$vo[4].$vo[5].$vo[6].'>';
						$replace[1]  = '<link'.$vo[1].'href='.$vo[2].__TPL__.'/'.$vo[3].'.css'.$vo[4].$vo[5].$vo[6].'>';
						$replace[2]  = '<script'.$vo[1].'src='.$vo[2].__TPL__.'/'.$vo[3].'.js'.$vo[4].$vo[5].$vo[6].'>';
						$this->content = str_replace($vo[0],$replace[$key], $this->content);
					}
				}
			}
		}


	}

	/**
     * 解析变量
     * @return mixed
     */
    private function parseVar(){
        $preg   = '#\{(\$[\w\.\[\]\'"]+)?(?:\:(.*))?(@\$(.*))?\}#isU';
        $status = preg_match_all($preg, $this->content, $info,PREG_SET_ORDER);

        if ($status) {
            foreach ($info as $d) {
				//定义变量
				if (!empty($d[3]) && !empty($d[4])){
					$dvar[0] = $d[0];
					$dvar[1] = $d[4];
				}
                //输出变量
                $var = '';
                if (!empty($d[1])) {
                    $data = explode('.', $d[1]);
                    foreach ($data as $n => $m) {
                        if($n == 0) {
                            $var .= $m;
                        }else{
                            $var .= '[\'' . $m . '\']';
                        }
                    }
                }
                // 输出函数
                if (!empty($d[2])) {
				   $fstatus = preg_match('#(.*)\($(.*)\)#isU',$d[2], $data);
				   if ($fstatus) {

						$ldata = ltrim($data[2],'$');
						//首先判断是否存在多个参数
						if(strstr($ldata,',')){
							$cdatas = explode(',',$ldata);
					    }else{
							$cdatas = array($ldata);
					    }

						foreach ($cdatas  as $k=>$attr) {
							 //再判断是否存在多个变量
							if(strstr($attr,'.$')){
								$vdatas = explode('.$',$attr);
							}else{
								$vdatas = array($attr);
							}

							//分割变量
							foreach($vdatas as $v){
								$edata = explode('.', $v);
								$var_arr[$k]= empty($edata[1]) ? $edata[0] : '$'.$edata[0].'[\'' . $edata[1] . '\']';
							}

						}
						$var .= $data[1].'('.implode('.',$var_arr).')';

				   }else{
						$var .=  $d[2] ;
				   }
                }

				//定义变量
				if(!empty($dvar)){
                    $replace       = '<?php $' . $dvar[1] . ';?>';
                    $this->content = str_replace($dvar[0], $replace, $this->content);
                }

				//输出变量、函数
                if(!empty($var)){
                    $replace       = '<?php echo ' . $var . ';?>';
                    $this->content = str_replace($d[0], $replace, $this->content);
                }
            }
        }
    }


	/**
     * 解析标签
     * @return mixed
     */
	private function parseTag(){

        //定义标签库类
        $tagClass = array();

		//载入系统标签库
        if (require_once('ViewTag.class.php')) {
            $tagClass[] = 'ViewTag';
        }

        //自定义标签库
		$tags = C('TPL_TAGS');

        if (!empty($tags) && is_array($tags)){
            foreach ($tags as $file) {
				//导入自定义标签库
				if (require_cache(DATA_PATH.'Tag/'.$file.EXT)){
					//类名
					$tagName = basename($file);
					 //判断标签库是否合法
					if (class_exists($tagName, false) && property_exists($tagName, 'Tag') &&  get_parent_class($tagName) == 'Tag'){
						$tagClass[] = $tagName;
					}

				}
            }
        }
         //解析标签类
        foreach ($tagClass as $class) {
            //标签类对象
            $obj = new $class();
            //标签库中的标签方法
            foreach ($obj->Tag as $tag => $option) {
                //标签是否合法
                if (!isset($option['block'])|| ! isset($option['level'])) {
                    continue;
                }
                //解析标签
                for ($i = 0; $i <= $option['level']; $i++) {
                    if ( ! $obj->parseTag($tag,basename($this->tplFile), $this->content, $this->view,$option['method'])) {
                        break;
                    }
                }
            }
        }
	}

	/**
     * 替换URL地址常量
     * 如__PUBLIC__
     */
    private function parseUrlConst(){
        $const = get_defined_constants(true);
        foreach ($const['user'] as $k => $v) {
            if (strstr($k, '__')) {
                $this->content = str_replace($k, $v, $this->content);
            }
        }
    }
}
