<?php

// +----------------------------------------------------------------------

// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]

// +----------------------------------------------------------------------

// | Copyright (c) 2006-2012 http://thinkphp.cn All rights reserved.

// +----------------------------------------------------------------------

// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )

// +----------------------------------------------------------------------

// | Author: liu21st <liu21st@gmail.com>

// +----------------------------------------------------------------------



/**

 * ThinkPHP标签库TagLib解析基类

 * @category   Think

 * @package  Think

 * @subpackage  Template

 * @author    liu21st <liu21st@gmail.com>

 */

class TagLib {



    /**

     * 标签库定义XML文件

     * @var string

     * @access protected

     */

    protected $xml      = '';

    protected $tags     = array();// 标签定义

    /**

     * 标签库名称

     * @var string

     * @access protected

     */

    protected $tagLib   ='';



    /**

     * 标签库标签列表

     * @var string

     * @access protected

     */

    protected $tagList  = array();



    /**

     * 标签库分析数组

     * @var string

     * @access protected

     */

    protected $parse    = array();



    /**

     * 标签库是否有效

     * @var string

     * @access protected

     */

    protected $valid    = false;



    /**

     * 当前模板对象

     * @var object

     * @access protected

     */

    protected $tpl;



    protected $comparison = array(' nheq '=>' !== ',' heq '=>' === ',' neq '=>' != ',' eq '=>' == ',' egt '=>' >= ',' gt '=>' > ',' elt '=>' <= ',' lt '=>' < ');



    /**

     * 架构函数

     * @access public

     */

    public function __construct() {

        $this->tagLib  = strtolower(substr(get_class($this),6));

        $this->tpl     = Think::instance('ThinkTemplate');

    }



    /**

     * TagLib标签属性分析 返回标签属性数组

     * @access public

     * @param string $tagStr 标签内容

     * @return array

     */

    public function parseXmlAttr($attr,$tag) {

        //XML解析安全过滤

        $attr   =   str_replace('&','___', $attr);

        $xml    =   '<tpl><tag '.$attr.' /></tpl>';

        $xml    =   simplexml_load_string($xml);

        if(!$xml) {

            throw_exception(L('_XML_TAG_ERROR_').' : '.$attr);

        }

        $xml    =   (array)($xml->tag->attributes());

        $array  =   array_change_key_case($xml['@attributes']);

        if($array) {

            $attrs  = explode(',',$this->tags[strtolower($tag)]['attr']);

            if(isset($this->tags[strtolower($tag)]['must'])){

                $must   =   explode(',',$this->tags[strtolower($tag)]['must']);

            }else{

                $must   =   array();

            }

            foreach($attrs as $name) {

                if( isset($array[$name])) {

                    $array[$name] = str_replace('___','&',$array[$name]);

                }elseif(false !== array_search($name,$must)){

                    throw_exception(L('_PARAM_ERROR_').':'.$name);

                }

            }

            return $array;

        }

    }



    /**

     * 解析条件表达式

     * @access public

     * @param string $condition 表达式标签内容

     * @return array

     */

    public function parseCondition($condition) {

        $condition = str_ireplace(array_keys($this->comparison),array_values($this->comparison),$condition);

        $condition = preg_replace('/\$(\w+):(\w+)\s/is','$\\1->\\2 ',$condition);

        switch(strtolower(C('TMPL_VAR_IDENTIFY'))) {

            case 'array': // 识别为数组

                $condition  =   preg_replace('/\$(\w+)\.(\w+)\s/is','$\\1["\\2"] ',$condition);

                break;

            case 'obj':  // 识别为对象

                $condition  =   preg_replace('/\$(\w+)\.(\w+)\s/is','$\\1->\\2 ',$condition);

                break;

            default:  // 自动判断数组或对象 只支持二维

                $condition  =   preg_replace('/\$(\w+)\.(\w+)\s/is','(is_array($\\1)?$\\1["\\2"]:$\\1->\\2) ',$condition);

        }

        if(false !== strpos($condition, '$Think'))

            $condition      =   preg_replace('/(\$Think.*?)\s/ies',"\$this->parseThinkVar('\\1');" , $condition);        

        return $condition;

    }



    /**

     * 自动识别构建变量

     * @access public

     * @param string $name 变量描述

     * @return string

     */

    public function autoBuildVar($name) {

        if('Think.' == substr($name,0,6)){

            // 特殊变量

            return $this->parseThinkVar($name);

        }elseif(strpos($name,'.')) {

            $vars = explode('.',$name);

            $var  =  array_shift($vars);

            switch(strtolower(C('TMPL_VAR_IDENTIFY'))) {

                case 'array': // 识别为数组

                    $name = '$'.$var;

                    foreach ($vars as $key=>$val){

                        if(0===strpos($val,'$')) {

                            $name .= '["{'.$val.'}"]';

                        }else{

                            $name .= '["'.$val.'"]';

                        }

                    }

                    break;

                case 'obj':  // 识别为对象

                    $name = '$'.$var;

                    foreach ($vars as $key=>$val)

                        $name .= '->'.$val;

                    break;

                default:  // 自动判断数组或对象 只支持二维

                    $name = 'is_array($'.$var.')?$'.$var.'["'.$vars[0].'"]:$'.$var.'->'.$vars[0];

            }

        }elseif(strpos($name,':')){

            // 额外的对象方式支持

            $name   =   '$'.str_replace(':','->',$name);

        }elseif(!defined($name)) {

            $name = '$'.$name;

        }

        return $name;

    }



    /**

     * 用于标签属性里面的特殊模板变量解析

     * 格式 以 Think. 打头的变量属于特殊模板变量

     * @access public

     * @param string $varStr  变量字符串

     * @return string

     */

    public function parseThinkVar($varStr){

        $vars       = explode('.',$varStr);

        $vars[1]    = strtoupper(trim($vars[1]));

        $parseStr   = '';

        if(count($vars)>=3){

            $vars[2] = trim($vars[2]);

            switch($vars[1]){

                case 'SERVER':    $parseStr = '$_SERVER[\''.$vars[2].'\']';break;

                case 'GET':         $parseStr = '$_GET[\''.$vars[2].'\']';break;

                case 'POST':       $parseStr = '$_POST[\''.$vars[2].'\']';break;

                case 'COOKIE':

                    if(isset($vars[3])) {

                        $parseStr = '$_COOKIE[\''.$vars[2].'\'][\''.$vars[3].'\']';

                    }elseif(C('COOKIE_PREFIX')){

                        $parseStr = '$_COOKIE[\''.C('COOKIE_PREFIX').$vars[2].'\']';

                    }else{

                        $parseStr = '$_COOKIE[\''.$vars[2].'\']';

                    }

                    break;

                case 'SESSION':

                    if(isset($vars[3])) {

                        $parseStr = '$_SESSION[\''.$vars[2].'\'][\''.$vars[3].'\']';

                    }elseif(C('SESSION_PREFIX')){

                        $parseStr = '$_SESSION[\''.C('SESSION_PREFIX').'\'][\''.$vars[2].'\']';

                    }else{

                        $parseStr = '$_SESSION[\''.$vars[2].'\']';

                    }

                    break;

                case 'ENV':         $parseStr = '$_ENV[\''.$vars[2].'\']';break;

                case 'REQUEST':  $parseStr = '$_REQUEST[\''.$vars[2].'\']';break;

                case 'CONST':     $parseStr = strtoupper($vars[2]);break;

                case 'LANG':       $parseStr = 'L("'.$vars[2].'")';break;

                case 'CONFIG':    $parseStr = 'C("'.$vars[2].'")';break;

            }

        }else if(count($vars)==2){

            switch($vars[1]){

                case 'NOW':       $parseStr = "date('Y-m-d g:i a',time())";break;

                case 'VERSION':  $parseStr = 'THINK_VERSION';break;

                case 'TEMPLATE':$parseStr = 'C("TEMPLATE_NAME")';break;

                case 'LDELIM':    $parseStr = 'C("TMPL_L_DELIM")';break;

                case 'RDELIM':    $parseStr = 'C("TMPL_R_DELIM")';break;

                default:  if(defined($vars[1])) $parseStr = $vars[1];

            }

        }

        return $parseStr;

    }



    // 获取标签定义

    public function getTags(){

        return $this->tags;

    }

}