<?php
/**************************************************
*  Created:  2010-06-08
*
*  框架核心文件
*
*  @Xweibo (C)1996-2099 SINA Inc.
*  @Author xionghui <xionghui1@staff.sina.com.cn>
*
***************************************************/

class APP
{
	//------------------------------------------------------------------
	function APP(){

	}
	//------------------------------------------------------------------
	/**
	 * 初始化 APP
	 * @return 无返回值
	 */
	function init(){
		static $is_init;
		if ($is_init) {return true;}

		APP::_initConfig();
		APP::_initRouteVar();
		APP::_aclCheck();
		APP::_doPreActions();
		$is_init = true;
	}
	//------------------------------------------------------------------
	/// 访问控制检查
	function _aclCheck(){
		$entry = V('-:aclTable/E');
		// 入口控制配置不为空
		if ( is_array($entry) && !empty($entry) ){
			foreach($entry as $e){

			}
		}

		$ips = V('-:aclTable/IP');
		// IP控制配置不为空
		if ( is_array($ips) && !empty($ips) ){
			foreach($ips as $ip){

			}
		}
	}
	//------------------------------------------------------------------
	/// 解释路由模式为 rewrite 时的 GET 变量
	function _initRouteVar(){
		if ( !in_array(R_MODE,array(2,3))) {return true;}

		$ss = trim(V('S:PATH_INFO',''),'/');
		if (empty($ss)) {return true;}
		if (preg_match_all("#/([a-z0-9_]+)-([^/]+)#sim",$ss,$pv)){
			foreach ($pv[1] as $i=>$ni){
				// echo " $ni => ".($pv[2][$i])."\n"; //urldecode
				$_GET[$ni] = urldecode($pv[2][$i]);
				$_REQUEST[$ni] = urldecode($pv[2][$i]);
				V('g:'.$ni, $_GET[$ni], true);
				V('r:'.$ni, $_GET[$ni], true);
			}
		}
	}
	//------------------------------------------------------------------
	/**
	 * 初始化配置
	 * @return 无返回值
	 */
	function _initConfig(){
		if (!is_array($GLOBALS[V_GLOBAL_NAME])){
			$GLOBALS[V_GLOBAL_NAME] = array();
		}
		if (APP::V('g:'.V_AJAX_FLAG_NAME, false)){
			define('IS_IN_AJAX',	true);
		}else{
			define('IS_IN_AJAX',	false);
		}

		// 兼容 WIN 服务器中的 \ 路径问题
		if (PHP_OS=='WINNT'){
			$v1 = str_replace('\\','/',V('S:DOCUMENT_ROOT'));
			$v2 = str_replace('\\','/',V('S:SCRIPT_FILENAME'));
			V('S:DOCUMENT_ROOT',$v1,true);
			V('s:DOCUMENT_ROOT',$v1,true);
			V('S:SCRIPT_FILENAME',$v2,true);
			V('s:SCRIPT_FILENAME',$v2,true);
		}

		// parse base url
		/*
		$p = V("s:SERVER_PORT")=='80' ? '' : ':'.V("s:SERVER_PORT");
		$s =  V("s:SCRIPT_NAME");
		$baseUrl = 'http://' . V("s:HTTP_HOST") . $p . "/" . ltrim(substr($s,0,strrpos($s,"/")),"/");
		define('W_BASE_URL',rtrim($baseUrl,"/ ") . "/" );
		*/
		$p = V("s:SERVER_PORT")=='80' ? '' : ':'.V("s:SERVER_PORT");
		define('W_BASE_HTTP','http://' . V("s:HTTP_HOST") );
		define('W_BASE_URL',preg_replace("#/[^/]+$#",'/',str_replace(V('S:DOCUMENT_ROOT'),'',V('S:SCRIPT_FILENAME'))));
		define('W_BASE_FILENAME', basename(V('S:SCRIPT_FILENAME')));
	}
	//------------------------------------------------------------------
	/**
	 * APP::request();	处理用户请求
	 * @param $halt		执行完请求后是否退出
	 * @return 无返回值
	 */
	function request($halt=false){
		APP::M(APP::getRequestRoute());
		if ($halt) exit;
	}
	//------------------------------------------------------------------
	/**
	 * APP::getRequestRoute();	从当前请求中取得模块路由信息
	 * @param $is_acc			是否以数组的形式返回
	 * @return  requestRoute
	 */
	function getRequestRoute($is_acc=false){
		//--------------------------------------------------------------
		$m = "";
		if ( R_MODE == 0 ){
			$m = APP::V("g:".R_GET_VAR_NAME);
			$m = $m ? $m : R_DEF_MOD;

		}
		//--------------------------------------------------------------
		if ( R_MODE == 1 ){
			$m = ltrim(APP::V("s:PATH_INFO")," /");
			$m = $m ? $m : R_DEF_MOD;
		}
		//--------------------------------------------------------------
		if ( R_MODE == 2 ){
			$ss = trim(V('S:PATH_INFO',''),'/');
			if (empty($ss)) {
				$m = R_DEF_MOD;
			}else{
				preg_match("#^([a-z_][a-z0-9_\./]*/|)([a-z0-9_]+)(?:\.([a-z_][a-z0-9_]*))?(?:/|\$)#sim",$ss,$mm);
				//print_r($mm);
				$m = trim($mm[0], '/');
			}
		}
		//--------------------------------------------------------------
		if ( R_MODE == 3 ){
			$m = APP::V("g:".R_GET_VAR_NAME);
			if ( empty($m) ){
				$ss = trim(V('S:PATH_INFO',''),'/');
				if (empty($ss)) {
					$m = R_DEF_MOD;
				}else{
					preg_match("#^([a-z_][a-z0-9_\./]*/|)([a-z0-9_]+)(?:\.([a-z_][a-z0-9_]*))?(?:/|\$)#sim",$ss,$mm);
					$m = trim($mm[0], '/');
				}
			}
		}
		//--------------------------------------------------------------
		if (!empty($m)) {
			if (!$is_acc) {
				return $m;
			}else{
				$r = APP::_parseRoute($m);
				return array('path'=>$r[1], 'class'=>$r[2], 'function'=>$r[3]);
			}
		}
		//--------------------------------------------------------------
		trigger_error("Unknow route type: [ ".R_TYPE." ]", E_USER_ERROR);
	}
	//------------------------------------------------------------------
	/**
	 * APP::gerRuningRoute();
	 * 获取当前正在执行的 mRoute
	 * @param $is_acc			是否以数组的形式返回
	 */
	function getRuningRoute($is_acc=false){
		$m = APP::getData('RuningRoute');
		return ($is_acc) ? $m :  $m['path'].$m['class'].".".$m['function'] ;
	}
	//------------------------------------------------------------------
	/**
	 * APP::addPreAction($doRoute, $type, $args=false);
	 * 此方法必须在 APP::init();之前执行
	 * @param $doRoute		模块路由，如 demo/index.show
	 * @param $type			模块类型，可选值为： m , f , c ; 分别表示 模块 函数 和 类库
	 * @param $args			模块所需要的参数，统一用数据传递，$type 为 m 时无效
	 * @param $except		例外模块，在这些模块中 将不执行此预处理程序 默认为空 可以是数组或者字符串
	 * @return 无返回值
	 */
	function addPreDoAction($doRoute, $type, $args=array(), $except='') {
		APP::setData($doRoute . ',' . $type, array($doRoute,$type, $args, $except), '_PreDoActions');
	}
	//------------------------------------------------------------------
	/// 处理预加载模块
	function _doPreActions() {
		$as = APP::getData(false,'_PreDoActions');
		if (empty($as) || !is_array($as)) {return true;}

		foreach($as as  $v ){
			$route	= trim($v[0]);
			$type	= strtoupper($v[1]);
			$arg	= $v[2];
			$noRun	= $v[3];
			if (!empty($noRun)){
				if (!is_array($noRun)) { $noRun = array($v[3]); }
				//print_r($noRun);exit;
				if (in_array(APP::getRequestRoute(),$noRun)){ continue;}
			}

			switch ($type) {
				case 'M' :
					APP::M($route);
					break;
				case 'C' :
					$rData	= APP::_parseRoute($route);
					$c		= APP::N($rData[2]);
					$c->$rData[3]($arg);
					break;
				case 'F' :
					APP::F($route,$arg);
					break;
				default :
					trigger_error("Unknow preDoAction type: [ ".$type." ]", E_USER_ERROR);
					break;
			}
		}
	}
	//------------------------------------------------------------------
	/**
	 * APP::setData($k,$v=false,$category='STATIC_STORE');
	 * 保存一个静态全局数据
	 */
	function setData($k,$v=false,$category='STATIC_STORE'){
		if (!is_array($GLOBALS[V_GLOBAL_NAME])){
			$GLOBALS[V_GLOBAL_NAME] = array();
		}
		if (!is_array($GLOBALS[V_GLOBAL_NAME][$category])){
			$GLOBALS[V_GLOBAL_NAME][$category] = array();
		}
		if (is_array($k)){
			$GLOBALS[V_GLOBAL_NAME][$category] = array_merge($GLOBALS[V_GLOBAL_NAME][$category], $k);
		}else{
			$GLOBALS[V_GLOBAL_NAME][$category][$k] = $v;
		}
	}
	//------------------------------------------------------------------
	/**
	 * APP::getData($k=false, $category='STATIC_STORE');
	 * 获取一个静态存储数据
	 */
	function getData($k=false, $category='STATIC_STORE'){
		if (!is_array($GLOBALS[V_GLOBAL_NAME][$category])){
			$GLOBALS[V_GLOBAL_NAME][$category] = array();
		}
		return $k ? $GLOBALS[V_GLOBAL_NAME][$category][$k] : $GLOBALS[V_GLOBAL_NAME][$category];
	}
	//------------------------------------------------------------------
	/**
	 * APP::mkModuleUrl($mRoute, $qData=false, $entry=false);
	 * 根据模块路由，query 数据 ，入口程序，生成URL，
	 * @param $mRoute		模块路由，如 demo/index.show
	 * @param $qData		添加在URL后面的参数，可以是数组或者字符串，
	 * 						如  array('a'=>'a_var') 或者  "a=a_var&b=b_var"
	 * @param $entry		入口程序名，默认获取当前入口程序，如： index.php admin.php
	 * @return 生成的URL
	 */
	function mkModuleUrl($mRoute, $qData=false, $entry=false){
		/*
		$p = V("s:SERVER_PORT")=='80' ? '' : V("s:SERVER_PORT");
		$baseUrl = 'http://' . V("s:HTTP_HOST") . $p  ;
		$baseUrl.= $entry ?  "/" . ltrim($entry,"/ ") : V("s:SCRIPT_NAME");
		*/
		$baseUrl	= $entry ?  W_BASE_URL.$entry  :  str_replace(V('S:DOCUMENT_ROOT'),'',V('S:SCRIPT_FILENAME'));
		//$baseUrl	= $entry ?  "/" . ltrim($entry,"/ ") : str_replace(V('S:DOCUMENT_ROOT'),'',V('S:SCRIPT_FILENAME'));
		$basePath	= preg_replace("#/[^/]+$#",'/',$baseUrl);
		//--------------------------------------------------------------
		if($qData){
			if(is_array($qData)){
				$kv = array();
				foreach($qData as $k=>$v){
					$kv[] = $k . "=" . urlencode($v);
				}
				$qData = implode("&", $kv);
			}else{
				$qData = trim($qData, "&");
			}
		}else{
			$qData = '';
		}
		//--------------------------------------------------------------
		if (R_MODE == 0 ){
			$rStr	= R_GET_VAR_NAME . '=' . $mRoute;
			$qData	= empty($qData) ?  $rStr  : $rStr . "&" . $qData;
			return $baseUrl ."?" . $qData;
		}
		//--------------------------------------------------------------
		if (R_MODE == 1 ){
			return empty($qData) ? $baseUrl."/" . trim($mRoute,'/ ') : $baseUrl."/" . trim($mRoute,'/ ')  ."?" . $qData ;
		}
		//--------------------------------------------------------------
		if (R_MODE == 2 || R_MODE == 3 ){
			return empty($qData)? $basePath. trim($mRoute,'/ ')
								: $basePath. trim($mRoute,'/ ') . preg_replace("#(?:^|&)([a-z0-9_]+)=#sim","/\\1-",$qData) ;
		}
		//--------------------------------------------------------------
		trigger_error("Unknow route type: [ ".R_MODE." ]", E_USER_ERROR);
		return false;
	}
	//------------------------------------------------------------------
	/**
	 * V($vRoute,$def_v=NULL);
	 * APP:V($vRoute,$def_v=NULL);
	 * 获取还原后的  $_GET ，$_POST , $_FILES $_COOKIE $_REQUEST $_SERVER $_ENV
	 * 同名全局函数： V($vRoute,$def_v=NULL);
	 * @param $vRoute	变量路由，规则为：“<第一个字母>[：变量索引/[变量索引]]
	 * 					例:	V('G:TEST/BB'); 表示获取 $_GET['TEST']['BB']
	 * 						V('p'); 		表示获取 $_POST
	 * 						V('c:var_name');表示获取 $_COOKIE['var_name']
	 * @param $def_v
	 * @return unknown_type
	 */
	function V($vRoute,$def_v=NULL,$setVar=false){
		static $v;
		if (empty($v)){$v = array();}
		$vRoute = trim($vRoute);

		//强制初始化值
		if ($setVar) {$v[$vRoute] = $def_v;return true;}

		if (!isset($v[$vRoute])){

			$vKey = array('C'=>$_COOKIE,
						  'G'=>$_GET,
						  'P'=>$_POST,
						  'R'=>$_REQUEST,
						  'F'=>$_FILES,
						  'S'=>$_SERVER,
						  'E'=>$_ENV,
						  '-'=>$GLOBALS[V_CFG_GLOBAL_NAME]
			);
			if (empty($vKey['R'])) {
				$vKey['R'] = array_merge($_GET,$_POST,$_COOKIE);
			}
			if ( !preg_match("#^([cgprfse-])(?::(.+))?\$#sim",$vRoute,$m) || !isset($vKey[strtoupper($m[1])]) ){
				trigger_error("Can't parse var from vRoute: $vRoute ", E_USER_ERROR);
				return NULL;
			}

			//----------------------------------------------------------
			$m[1] = strtoupper($m[1]);
			$tv = $vKey[$m[1]];
			//----------------------------------------------------------
			if ( empty($m[2]) ) {
				$v[$vRoute] =  ($m[1]=='-' || $m[1]=='F' || $m[1]=='S' || $m[1]=='E' ) ? $tv :  APP::_magic_var($tv);
			}elseif ( empty($tv) ) {
				$v[$vRoute] = $def_v;
				return $v[$vRoute];
			}else{
				$vr = explode('/',$m[2]);
				while( count($vr)>0 ){
					$vk = array_shift($vr);
					if (!isset($tv[$vk])){
						$tv = $def_v;break;
					}
					$tv = $tv[$vk];
				}
			}
			$v[$vRoute] = ($m[1]=='-' || $m[1]=='F' || $m[1]=='S' || $m[1]=='E'  )  ? $tv :  APP::_magic_var($tv);
		}
		return $v[$vRoute];
	}
	//------------------------------------------------------------------
	//------------------------------------------------------------------
	/**
	 * 根据用户服务器环境配置，递归还原变量
	 * @param $mixed
	 * @return 还原后的值
	 */
	function _magic_var($mixed) {
		if( (function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc()) || ini_get('magic_quotes_sybase') ) {
			if(is_array($mixed))
				return array_map(array('APP','_magic_var'), $mixed);
			return stripslashes($mixed);
		}else{
			return $mixed;
		}
	}
	//------------------------------------------------------------------
	/**
	 * APP::redirect($mRoute,$type=1);
	 * 重定向 并退出程序
	 * @param $mRoute
	 * @param $type 	1 : 默认 ， 内部模块跳转 ,2 : 给定模块路由，通过浏览器跳转 ,3 : 给定URL
	 * @return 无返回值
	 */
	function redirect($mRoute,$type=1){
		switch ($type){
			case 1:
				APP::M($mRoute);
				break;
			case 2:
				$url = APP::mkModuleUrl($mRoute);
				header("Location: ".$url);
				break;
			case 3:
				header("Location: ".$mRoute);
				break;
			default:
				break;
		}
		exit;
	}
	//------------------------------------------------------------------
	/**
	 * APP::F($fRoute);
	 * 执行 $fRoute 指定的函数 第二个以及以后的参数 将传递给此函数
	 * 例：APP::F('test.func',1,2); 表示执行  func(1,2);
	 * @param $fRoute 函数路由，规则与模块规则一样
	 * @return 函数执行结果
	 */
	function F($fRoute){
		$p = func_get_args();
		array_shift($p);

		$cFile = APP::_getIncFile($fRoute,'func');
		require_once($cFile);

		$pp = preg_match("#^([a-z_][a-z0-9_\./]*/|)([a-z0-9_]+)(?:\.([a-z_][a-z0-9_]*))?\$#sim",$fRoute,$m);
		if (!$pp) { trigger_error("fRoute : [ $fRoute  ] is  invalid ", E_USER_ERROR);  return false;}
		$func = empty($m[3])?$m[2]:$m[3];
		if ( !function_exists($func) ) {
			trigger_error("Can't find function [ $func ] in file [ $cFile ]", E_USER_ERROR);
		}
		return call_user_func_array($func,$p);
	}
	//------------------------------------------------------------------
	/**
	 * APP::O($oRoute);
	 * 根据类路由 和 类初始化参数获取一个单例
	 * 第二个以及以后的参数 将传递给类的构造函数
	 * 如： APP::O('test/classname','a','b'); 实例化时执行的是 new classname('a','b');
	 * @param $oRoute 类路由，规则与模块规则一样
	 * @return 类实例
	 */
	function &O($oRoute){
		static $oArr;
		if (isset($oArr[$oRoute]) && is_object($oArr[$oRoute]) ){
			return $oArr[$oRoute];
		}

		$p = func_get_args();
		array_shift($p);
		array_unshift($p,$oRoute,'cls',false);
		$oArr[$oRoute] = call_user_func_array(array('APP','_cls'),$p);
		return $oArr[$oRoute];
	}
	//------------------------------------------------------------------
	/**
	 * APP::N($oRoute);
	 * 根据类路由 和 类初始化参数获取一个类实例
	 * 第二个以及以后的参数 将传递给类的构造函数
	 * 如： APP::N('test/classname','a','b'); 实例化时执行的是 new classname('a','b');
	 * @param $oRoute 类路由，规则与模块规则一样
	 * @return 类实例
	 */
	function N($oRoute){
		$p = func_get_args();
		array_shift($p);
		array_unshift($p,$oRoute,'cls',false);
		return call_user_func_array(array('APP','_cls'),$p);
	}
	//------------------------------------------------------------------
	/**
	 * APP::M($mRoute);
	 * 执行一个模块
	 * @param $mRoute
	 * @return no nreturn
	 */
	function M($mRoute){
		$r = APP::_parseRoute($mRoute);
		APP::setData('RuningRoute',array('path'=>$r[1], 'class'=>$r[2], 'function'=>$r[3]));

		$p = func_get_args();
		array_shift($p);
		array_unshift($p,$mRoute,'mod',true);
		$m = call_user_func_array(array('APP','_cls'),$p);

		if (!is_object($m)){
			trigger_error("Can't instance mRoute  [ $mRoute ] ", E_USER_ERROR);
		}

		if (substr($r[3],0,1)=='_'){
			trigger_error("Module method: [ ".$r[3]." ]  start with '_' is private !  ", E_USER_ERROR);
		}

		if (!method_exists($m,$r[3])){
			trigger_error("Can't find method  [ ".$r[3]." ]  in  [ ".$r[2]." ] ", E_USER_ERROR);
		}


		/// before hook
		$beforeAct = ACTION_BEFORE_PREFIX . $r[3];
		if (defined('ENABLE_ACTION_HOOK') && ENABLE_ACTION_HOOK  &&  method_exists($m,$beforeAct) ){
			$m->$beforeAct();
		}

		/// call action
		if ($r[3]!=$r[2]) { $m->$r[3]();}

		/// after hook
		$afterAct = ACTION_AFTER_PREFIX . $r[3];
		if (defined('ENABLE_ACTION_HOOK') && ENABLE_ACTION_HOOK  &&  method_exists($m,$afterAct) ){
			$m->$afterAct();
		}
	}
	//------------------------------------------------------------------
	function &_cls($iRoute,$type,$is_single){
		static $clsArr;
		$iRoute = trim($iRoute);
		$type 	= trim($type);


		if ( empty($clsArr) ){
			$clsArr = array();
		}
		if ( $is_single && isset($clsArr[$iRoute]) &&  is_object($clsArr[$iRoute]) ){
			return $clsArr[$iRoute];
		}else{

			$cFile = APP::_getIncFile($iRoute,$type);
			require_once($cFile);
			$r = APP::_parseRoute($iRoute);
			$class	= $r[2];
			$func	= $r[3];

			if(!class_exists ($class)){
				trigger_error("class [ $class ]  is not exists in file [ $cFile ] ", E_USER_ERROR);
			}
			$p = func_get_args();
			array_shift($p);
			array_shift($p);
			array_shift($p);
			if(!empty($p)){
				$prm = array();
				foreach($p as $i=>$v){
					$prm[] = "\$p[".$i."]";
				}
				eval("\$retClass = new ".$class." (".implode(",",$prm).");");
				if ( $is_single ) { $clsArr[$iRoute] = $retClass; }
				return $retClass;
			}else{
				if ( $is_single ) {
					$clsArr[$iRoute] = new $class;
					return $clsArr[$iRoute];
				}else{
					return new $class;
				}
			}
		}
	}
	//------------------------------------------------------------------
	function _parseRoute($route){
		$route = trim($route);
		$p = preg_match("#^([a-z_][a-z0-9_\./]*/|)([a-z0-9_]+)(?:\.([a-z_][a-z0-9_]*))?\$#sim",$route,$m);
		if (!$p) { trigger_error("route : [ $route  ] is  invalid ", E_USER_ERROR);  return false;}
		if (empty($m[3])) $m[3] = R_DEF_MOD_FUNC;
		return $m;
	}
	//------------------------------------------------------------------
	/**
	 * APP::L($k);
	 * 根据语言索引返回信息信息
	 * 如果存在二个以上的参数，将以语言信息为格式 返回格式化后的字符串
	 * 如：APP::L($k,'a','b');
	 * 假设语言信息数据为 $_LANG,上例将返回 sprintf($_LANG[$k],'a','b');
	 * @param $k
	 * @return 格式化后的语言信息
	 */
	function L($k){
		if (!is_array($GLOBALS[V_GLOBAL_NAME]['LANG'])){
			trigger_error("Can't find any lang data ", E_USER_ERROR);
		}
		$s = $GLOBALS[V_GLOBAL_NAME]['LANG'][$k];
		$p = func_get_args();
		array_shift($p);
		if (!empty($p)){
			array_unshift($p,$s);
			$s = call_user_func_array('sprintf',$p);
		}
		return $s;
	}
	//------------------------------------------------------------------
	/**
	 * APP::importLang($lRoute);
	 * 导入一个语言信息文件
	 * @param $lRoute	语言信息路由 规则与模块路由一样
	 * @return 成功 true 失败 false;
	 */
	function importLang($lRoute){
		$lf = APP::_getIncFile($lRoute,'lang');
		include $lf;
		if (!is_array($_LANG)){
			trigger_error("Can't find lang array var \$_LANG in file [ $lf ] ", E_USER_ERROR);
		}


		$g = &$GLOBALS[V_GLOBAL_NAME];
		if(!isset($g['LANG']) ||  !is_array($g['LANG']) ){
			$g['LANG'] = array();
		}
		foreach($_LANG as $k=>$v){
			$g['LANG'][$k]=$v;
		}
		return true;
	}
	//------------------------------------------------------------------
	/**
	 * APP::functionFile($fRoute);
	 * 根据函数路由取得文件路径
	 * @param $fRoute	函数路由
	 * @return 函数文件路径
	 */
	function functionFile($fRoute){
		return APP::_getIncFile($fRoute,'func');
	}
	//------------------------------------------------------------------
	/**
	 * APP::classFile($fRoute);
	 * 根据类路由取得文件路径
	 * @param $fRoute	类路由
	 * @return 类文件路径
	 */
	function classFile($fRoute){
		return APP::_getIncFile($fRoute,'cls');
	}
	//------------------------------------------------------------------
	/**
	 * APP::moduleFile($fRoute);
	 * 根据模块路由取得文件路径
	 * @param $fRoute	模块路由
	 * @return 模块文件路径
	 */
	function moduleFile($fRoute){
		return APP::_getIncFile($fRoute,'mod');
	}
	//------------------------------------------------------------------
	/**
	 * APP::tplFile($fRoute,$baseSkin=true);
	 * 根据模板路由取得文件路径
	 * @param $fRoute	模板路由
	 * @param $baseSkin	模板基准目录选项，默认为 true ，将使用系统配置的皮肤目录
	 * @return 模板文件路径
	 */
	function tplFile($fRoute,$baseSkin=true){
		return APP::_getIncFile($fRoute,'tpl',$baseSkin);
	}
	//------------------------------------------------------------------
	/**
	 * APP::adpFile($name,$type);
	 * 根据适配器的名称和类型取得文件路径
	 * @param $name	适配器名称如： db http cache io 等
	 * @param $name	适配器类型如： db 可能的类型有： mysql access mssql 等
	 * @return 模板文件路径
	 */
	function adpFile($name,$type){
		if ( !preg_match("#^[a-z_][a-z0-9_]*\$#sim",$name) ){
			trigger_error("Adapter name [ ".$name." ] is invalid ", E_USER_ERROR);
		}
		if ( !preg_match("#^[a-z_][a-z0-9_]*\$#sim",$type) ){
			trigger_error("Adapter type [ ".$type." ] is invalid ", E_USER_ERROR);
		}
		return P_ADAPTER."/".$name."/".$type."_".$name.EXT_ADAPTER;
	}
	//------------------------------------------------------------------
	/**
	 * APP::ADP ($name,$is_single=true,$cfg=false);
	 * 根据配置，获取一个适配器实例，使用配置信息初始化
	 * @param $name			适配器名称如： db 类型由配置文件中确定
	 * @param $is_single	是否获取单例
	 * @param $cfg			初始化此适配器的配置数据，默认从配置中取
	 * @return 相应的适配器实例
	 */
	function ADP ($name,$is_single=true,$cfg=false){
		$type		= APP::V('-:adapter/'.$name);
		if (empty($type)){
			trigger_error("Can't find  adapter config data  : \$GLOBALS['".V_CFG_GLOBAL_NAME."']['adapter']['{$name}']  ",
						  E_USER_ERROR);
		}

		$cfgData 	= $cfg ? $cfg : APP::V('-:adapter_cfg/'.$name.'/'.$type);
		return APP::adapter($name,$type,$is_single,$cfgData);
	}
	//------------------------------------------------------------------
	/**
	 * APP::adapter ($name,$type,$is_single=true,$cfgData=false);
	 * 通用的适配器获取方法
	 * @param $name			适配器名称
	 * @param $type			适配器类型
	 * @param $is_single	是否获取单剑
	 * @param $cfgData		适配器初始化参数
	 * @return 相应的适配器实例
	 */
	function &adapter ($name,$type,$is_single=true,$cfgData=false){
		static $adpClass;
		$class = $type."_".$name;

		if (isset($adpClass[$class]) && is_object($adpClass[$class]) && $is_single){
			return $adpClass[$class];
		}

		$cFile = APP::adpFile($name,$type);
		if (!file_exists($cFile)){
			trigger_error("Can't adapter file [ $cFile ] ", E_USER_ERROR);
		}

		require_once($cFile);
		if(!class_exists ($class)){
			trigger_error("class [ $class ]  is not exists in file [ $cFile ] ", E_USER_ERROR);
		}

		$c = new $class;
		$iniFunc = ADP_INIT_FUNC ;

		//var_dump($cfgData);
		if(method_exists($c,$iniFunc)){
			$c->$iniFunc($cfgData);
		}

		if ($is_single){
			$adpClass[$class] = $c;
		}
		return $c;
	}
	//------------------------------------------------------------------
	function _getIncFile($fRoute,$type='cls',$ext=""){
		if ( !APP::_chkPath($fRoute) ){
			trigger_error("file route: [ $fRoute  - $type  ] is  invalid ", E_USER_ERROR);
		}

		$tpldir		= ($type=='tpl'  &&  !$ext)		 	? '' : SITE_SKIN_TYPE."/";
		$langdir	= ($type=='lang' &&  !empty($ext)) 	? $ext : SITE_LANG;

		$m = APP::_parseRoute($fRoute);
		$fp = $m[1].$m[2];
		$type = strtolower($type);
		$f = array('tpl'=>P_TEMPLATE ."/".$tpldir . $fp . EXT_TPL,
				   'cls'=>P_CLASS ."/" . $fp . EXT_CLASS,
				   'mod'=>P_MODULES ."/" . $fp . EXT_MODULES,
				   'func'=>P_FUNCTION . "/" . $fp . EXT_FUNCTION,
				   'lang'=>P_LANG . "/" . $langdir . "/" . $fp . EXT_LANG
		);
		if ( !isset($f[$type]) ){
			trigger_error("file type: [ $type  ] is  invalid ", E_USER_ERROR);
		}
		if ( !file_exists($f[$type]) ){
			trigger_error("file:[ ".$f[$type]." ] not exists  ", E_USER_ERROR);
		}
		return $f[$type];
	}
	//------------------------------------------------------------------
	function _chkPath($v){
		return count(explode("..",$v))== 1 && preg_match("#^[a-z_][a-z0-9_/\.]*\$#sim",$v);
	}
	//------------------------------------------------------------------
	/**
	 * APP::LOG ($msg);
	 * 根据配置信息将 $msg 信息写入日志文件 默认在 /var/log/
	 * @param $msg		日志信息
	 * @return	是否写成功
	 */
	function LOG ($msg) {
		if (!defined('P_VAR_LOG_FILE') || !defined('ENABLE_LOG') || !ENABLE_LOG ) {return false;}
		$msg = sprintf("[%s]:\t%s\r\n",date("Y-m-d H:i:s"),$msg);
		if (!file_exists(P_VAR_LOG_FILE)){
			$msg = "<?php  ".IS_IN_APPLICATION_CODE." ?> \r\n\r\n".$msg;
		}

		IO::write(P_VAR_LOG_FILE, $msg, true);
	}
	//------------------------------------------------------------------
	function halt($error) {
		$e = array();
		$trace			= debug_backtrace();
		$e['message']	= $error;
		$e['file']		= $trace[0]['file'];
		$e['class']		= $trace[0]['class'];
		$e['function']	= $trace[0]['function'];
		$e['line']		= $trace[0]['line'];
		$traceInfo		= '';
		$time = date("Y-m-d H:i:m");
		foreach($trace as $t) {
			$traceInfo .= '['.$time.'] '.$t['file'].' ('.$t['line'].') ';
			$traceInfo .= $t['class'].$t['type'].$t['function'].'(';
			$traceInfo .= implode(', ', $t['args']);
			$traceInfo .=")<br/>";
		}
		$e['trace']  = $traceInfo;
		//print_r($e);
		exit;
	}
	//------------------------------------------------------------------

	/**
	 * APP::ajaxRst($rst,$errno=0,$err='');
	 * 通用的 AJAX 或者  API 输出入口
	 * 生成后的JSON串结构示例为：
	 * 	成功结果： {"rst":[1,0],"errno":0}
	 *  失败结果 ：{"rst":false,"errno":1001,"err":"access deny"}
	 * @param $rst
	 * @param $errno 	错误代码，默认为 0 ，表示正常执行请求， 或者 >0 的 5位数字 ，1 开头的系统保留
	 * @param $err		错误信息，默认为空
	 * @return unknown_type
	 */
	function ajaxRst($rst,$errno=0,$err='', $return = false){
		$r = array('rst'=>$rst,'errno'=>$errno*1,'err'=>$err);
		if ($return) {
			return json_encode($r);
		}
		else {
			echo json_encode($r);
		}
	}
	//------------------------------------------------------------------
	///todo
	function JSONP($rst, $callBack='callback', $script=false){

	}
	//------------------------------------------------------------------
	///todo
	function ACL(){
	}
	//------------------------------------------------------------------
	function deny($info=''){
		header("HTTP/1.1 403 Forbidden");
		exit('Access deny '.$info);
	}
	//------------------------------------------------------------------
	/**
	 * APP::tips($params,$display = true);
	 * 显示一个消息，并定时跳转
	 * @param $params Array
	 * 		['msg'] 显示消息,
	 * 		['location'] 跳转地址,
	 * 		['timeout'] = 3 跳转时长 ,0 则不跳转 此时 location 无效
	 * 		['tpl'] = '' 使用的模板名,
	 * 		如果$params不是数组,则直接当作 $params['msg'] 处理
	 * @param $display boolean 是否即时输出
	 */
	function tips($params,$display = true) {
		static $msg=array();
		if (!is_array($params)) {
			$params = array('msg' => (string)$params);
		}
		if (!isset($params['msg']) || empty($params['msg'])) {
			return false;
		}

		if (is_array($params['msg'])) {
			foreach($params['msg'] as $v) {
				if (!empty($v)) {
					$msg[] = (string)$v;
				}
			}
		} elseif(trim((string)$params) != '') {
			$msg[] = (string)$params['msg'];
		}
		if ($display) {
			$params['msg'] = $msg;
			TPL::assign($params);
			$msg = array();

			$time	= $params['timeout']*1;
			$url	= $params['location']."";
			if($time) {
				header("refresh:{$time};url=".$url);
			}
			if ($params['tpl']) {
				TPL::assign($params);
				if (!isset($params['baseskin'])) {
					$params['baseskin'] = true;
				}
				TPL::display($params['tpl'], $params['lang'], $params['caching'], $params['baseskin']);
				exit;
			} else {
				if($time) {
					echo "<meta http-equiv='Refresh' content='{$time};URL={$url}'>\n";
				}
				echo implode('<br />', $params['msg']);
			}
			exit;
		}
	}
	//------------------------------------------------------------------
}
//----------------------------------------------------------------------
/**
 * 请在模板文件第一行加入： if(!defined("IN_APPLICATION")) { exit("Access Denied"); }
 */
class TPL {
	//------------------------------------------------------------------
	function TPL(){}
	//------------------------------------------------------------------
	/**
	 * TPL::reset();
	 * 重置模板变量列表
	 * @return 无返回值
	 */
	function reset(){
		$GLOBALS[V_GLOBAL_NAME]['TPL'] = array();
	}
	//------------------------------------------------------------------
	/**
	 * TPL::assign($k,$v=null);
	 * 给模板变量赋值，类似SMARTY
	 * 使用实例：
	 * TPL::assign('var_name1','var'); 在模板中可以使用  $var_name1 变量
	 * TPL::assign(array('var_name2'=>'var')); 在模板中可以使用  $var_name2 变量
	 * @param $k	当  $k 为字串时 在模板中 可使用以 $k 命名的变量 其值 为 $v
	 * 				当  $k 为关联数组时 在模板中可以使用 $k 的所有索引为变量名的变量
	 * @param $v	当  $k 为字符串时 其值 即为 模板中 以  $k 为名的变量的值
	 * @return 无返回值
	 */

	function assign($k,$v=null){
		if ( !isset($GLOBALS[V_GLOBAL_NAME]['TPL']) || !is_array($GLOBALS[V_GLOBAL_NAME]['TPL']) ) {
			$GLOBALS[V_GLOBAL_NAME]['TPL'] = array();
		}
		if (!is_array($k)){
			$GLOBALS[V_GLOBAL_NAME]['TPL'][$k] = $v;
		}else{
			TPL::assignExtract($k);
		}
	}
	//------------------------------------------------------------------
	/**
	 * TPL::assignExtract($data);
	 * 给模板变量赋值
	 * @param $data	关联数组
	 * @return 无返回值
	 */
	function assignExtract($data){
		if ( !isset($GLOBALS[V_GLOBAL_NAME]['TPL']) || !is_array($GLOBALS[V_GLOBAL_NAME]['TPL']) ) {
			$GLOBALS[V_GLOBAL_NAME]['TPL'] = array();
		}

		foreach($data as $k=>$v){
			$GLOBALS[V_GLOBAL_NAME]['TPL'][$k] = $v;
		}
	}
	//------------------------------------------------------------------
	/**
	 * TPL::display($tpl, $langs=array(), $ttl=0, $tplDir="");
	 * 显示一个模板
	 * @param $tpl		模板路由
	 * @param $langs	语言包，可以是半角逗号隔开的列表，也可以是数组
	 * @param $ttl		缓存时间 单位秒 （ 未实现 ）
	 * @param $baseSkin	模板基准目录选项，默认为 true ，将使用系统配置的皮肤目录
	 * @return 无返回值
	 */
	function display($tpl, $langs=array(),$ttl=0, $baseSkin=true){
		if (is_array($GLOBALS[V_GLOBAL_NAME]['TPL'])) {
			//print_r($GLOBALS[V_GLOBAL_NAME]['TPL']);
			extract($GLOBALS[V_GLOBAL_NAME]['TPL']);
		}
		if ( !empty($langs) ){
			if ( !is_array($langs) ) $langs = explode(",", $langs);
			foreach ($langs as $t){
				if(!empty($t)) APP::importLang($t);
			}
		}

		include APP::tplFile( $tpl, $baseSkin );
	}
	//------------------------------------------------------------------
	/**
	 * TPL::fetch($tpl,$langs=array(),$ttl=0, $tplDir="");
	 * 获取一个模板解释完后的内容
	 * @param $tpl		模板路由
	 * @param $langs	语言包，可以是半角逗号隔开的列表，也可以是数组
	 * @param $ttl		缓存时间 单位秒 （ 未实现 ）
	 * @param $baseSkin	模板基准目录选项，默认为 true ，将使用系统配置的皮肤目录
	 * @return 模板解释完后的内容，字符串
	 */
	function fetch($tpl, $langs=array(), $ttl=0, $baseSkin=true){
		ob_start();
		TPL::display($tpl,$langs,$ttl, $baseSkin);
		$data = ob_get_contents();
		ob_end_clean();
		return $data;
	}
	//------------------------------------------------------------------
}
//----------------------------------------------------------------------
/**
 * 获取一个变量值  APP::V 的同名函数
 * @param $vRoute	变量路由
 * @param $def		默认值
 * @return 			变量值
 */
function V($vRoute, $def=NULL, $setVar=false){
	return APP::V($vRoute, $def, $setVar);
}
//----------------------------------------------------------------------
/// copydoc APP::L
function L(){
	$p = func_get_args();
	return call_user_func_array(array('APP','L'), $p);
}
//----------------------------------------------------------------------
/**
 * 获取一个url APP::mkModuleUrl 的同名函数
 * @param $mRoute	模块路由
 * @param $qData	URL 参数可以是字符串如 "a=xxx&b=ooo" 或者数组 array('k'=>'k_var')
 * @param $entry	模块入口 默认为当前入口，可指定入口程序 如 admin.php
 * @return 			URL
 */
function URL($mRoute, $qData=false, $entry=false){
	return APP::mkModuleUrl($mRoute, $qData, $entry);
}
//----------------------------------------------------------------------
/// cache
class CACHE {
	//------------------------------------------------------------------
	function CACHE (){}
	//------------------------------------------------------------------
	/**
	 * CACHE::getInstance();
	 * 获取当前缓存适配器的实例
	 * @return unknown_type
	 */
	function getInstance(){
		return APP::ADP('cache',false);
	}
	//------------------------------------------------------------------
	function &instance(){
		static $c;
		if(empty($c)) {
			$c = APP::ADP('cache');
		}
		return $c;
	}
	//------------------------------------------------------------------
	/**
	 * CACHE::get($key);
	 * 获取缓存
	 * @param $key		缓存存储的 KEY
	 * @return 如果缓存存在并未过期则返回缓存值 ，否则返回   false
	 */
	function get($key) {
		$c = & CACHE::instance();
		return $c->get($key);
	}
	//------------------------------------------------------------------
	/**
	 * CACHE::set($key, $value, $ttl = 0) ;
	 * 保存一个缓存
	 * @param $key		缓存  key
	 * @param $value	缓存值
	 * @param $ttl		有效时间 ，单位：秒
	 * @return 失败返回  false
	 */
	function set($key, $value, $ttl = 0) {
		$c = & CACHE::instance();
		return $c->set($key, $value, $ttl);
	}
	//------------------------------------------------------------------
	/**
	 * CACHE::delete($key);
	 * 删除一个缓存
	 * @param $key	缓存  KEY
	 * @return 失败返回 false
	 */
	function delete($key) {
		$c = & CACHE::instance();
		return $c->delete($key);
	}
	//------------------------------------------------------------------
}
//----------------------------------------------------------------------
class IO {
	//------------------------------------------------------------------
	function IO (){}
	//------------------------------------------------------------------
	/**
	 * IO::getInstance();
	 * 获取当前IO适配器实例
	 * @return IO 实例
	 */
	function getInstance(){
		return APP::ADP('io',false);
	}
	//------------------------------------------------------------------
	function &instance(){
		static $c;
		if(empty($c)) {
			$c = APP::ADP('io');
		}
		return $c;
	}
	//------------------------------------------------------------------
	/**
	 * IO::ls($path,$r=false,$info=false);
	 * 获取某个目录的文件列表
	 * @param $path		要处理的目录
	 * @param $r		是否递归子目录
	 * @param $info		是否获取每个文件的文件信息
	 * @return 文件信息列表
	 */
	function ls($path,$r=false,$info=false){
		$c = & IO::instance();
		return $c->ls($path,$r,$info);
	}
	//------------------------------------------------------------------
	/**
	 * IO::write($file,$contents,$append=false);
	 * 写入一个文件
	 * @param $file			目标文件路径，如果目录结构不存在则自动创建
	 * @param $contents		文件内容
	 * @param $append		是否将内容追加到文件末尾，默认为 false 重写文件
	 * @return 写入字节数 失败返回 false
	 */
	function write($file,$contents,$append=false) {
		$c = & IO::instance();
		return $c->write($file,$contents,$append);
	}
	/**
	 * IO::read($file);
	 * @param $file		目标文件路径
	 * @return 如果文件存在，返回内容 反之返回 false
	 */
	function read($file) {
		$c = & IO::instance();
		return $c->read($file);
	}
	/**
	 * IO::mkdir($path);
	 * 生成目录结构，创建目录
	 * @param $path		目录结构
	 * @return 成功返回 true 失败返回 false
	 */
	function mkdir($path) {
		$c = & IO::instance();
		return $c->mkdir($path);
	}
	/**
	 * IO::rm($path);
	 * 删除一个路径，如果是目录则删除它的子目录以及文件
	 * @param $path	要删除的目标路径
	 * @return 删除成功 返回 true 反之 返回 false
	 */
	function rm($path) {
		$c = & IO::instance();
		return $c->rm($path);
	}
	/**
	 * IO::info($path,$key=false);
	 * 获取一个文件、目录的信息
	 * @param $path		目标路径
	 * @param $key		如果 $key 为空 返回所有文件信息  反之返回 文件信息中的  $key 项
	 * @return 文件信息
	 */
	function info($path,$key=false) {
		$c = & IO::instance();
		return $c->info($path);
	}
	//------------------------------------------------------------------
}
//----------------------------------------------------------------------

//----------------------------------------------------------------------
?>
