<?php

/**
 *--------------------------------------
 * App base
 *--------------------------------------
 * @project		: pfa
 * @author		: cblee
 * @created		: 2012-9-23
 * @copyright	: (c)2012 AsThis
 *--------------------------------------
 */
defined('PFA_PATH') or exit('Access Denied');

class App extends Pfa {
	/* initialization */
	public function __construct() {
		//[RUNTIME]
		App::_build(); // pre-compile
		//[/RUNTIME]
		Url::dispatch(); // URL dispatch and define CTRLR_NAME, ACTN_NAME

		self::_load_comm(); // load common config and function library
		date_default_timezone_set(C('APP.TIMEZONE')); // set timezone

		/* error reporting */
		C('DEBUG.SWITCH') ? error_reporting(E_ALL ^ E_NOTICE ^ E_WARNING) : error_reporting(0);
		set_error_handler(array('App', 'app_error'));
		set_exception_handler(array('App', 'app_exception'));
		self::_load_lang(); // load language
		self::_load_theme(); // load template theme and define template constant
		self::_load_style(); // load skin style and define skin constant

		/* define current request system constant */
		define('NOW_TIME', AServer::get_time());
		define('CLIENT_IP', AServer::get_ip());
		define('REQUEST_METHOD', $_SERVER['REQUEST_METHOD']);
		define('IS_GET', 'GET' == REQUEST_METHOD ? true : false);
		define('IS_POST', 'POST' == REQUEST_METHOD ? true : false);
		define('IS_PUT', 'PUT' == REQUEST_METHOD ? true : false);
		define('IS_DELETE', 'DELETE' == REQUEST_METHOD ? true : false);
		define('IS_AJAX', ((isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') || !empty($_POST[C('VAR.AJAX')]) || !empty($_GET[C('VAR.AJAX')])) ? true : false);

		header('X-Powered-By: PFA '.PFA_VERSION);

		G('initTime'); // record init time
	}

	/* start app */
	public function run() {
		$group = defined('GROUP_NAME') ? GROUP_NAME.C('APP.GROUP_DEPR') : '';
		if(!($ctrlr = A($group.CTRLR_NAME))) {
			$ctrlr = A($group.'Empty');
		}
		if(!preg_match('/^[A-Za-z_0-9]+$/', CTRLR_NAME) or !$ctrlr) {
			if(C('DEBUG.SWITCH')) {
				halt(L('_CTRLR_INEXISTENCE_', null, array('ctrlr' => CTRLR_NAME)), true, true);
			}
			else {
				halt('', true, true);
			}
		}

		/* exclude actn */
		if(in_array(ACTN_NAME, array('assign', 'fetch', 'display', 'build_html', 'error', 'success', 'ajax_return'))) {
			if(C('DEBUG.SWITCH')) {
				halt(L('_METHOD_INEXISTENCE_', null, array('method' => ACTN_NAME)), true, true);
			}
			else {
				halt('', true, true);
			}
		}

		/* execute current action */
		call_user_func(array(&$ctrlr, ACTN_NAME));
	}

	/* custom error handler */
	public static function app_error($errno, $errstr, $errfile, $errline) {
		$errno = $errno & error_reporting();
		if(!defined('E_STRICT')) {
			define('E_STRICT', 2048);
		}
		if(!defined('E_RECOVERABLE_ERROR')) {
			define('E_RECOVERABLE_ERROR', 4096);
		}
		switch($errno) {
			case E_ERROR:
			case E_WARNING:
			case E_PARSE:
			case E_NOTICE:
			case E_CORE_ERROR:
			case E_CORE_WARNING:
			case E_COMPILE_ERROR:
			case E_COMPILE_WARNING:
			case E_USER_ERROR:
				$errorStr = "[{$errno}]{$errstr} ".basename($errfile)."({$errline})";
				Log::record($errorStr);
				halt($errorStr);
				break;
			case E_USER_WARNING:
			case E_USER_NOTICE:
			case E_STRICT:
			case E_RECOVERABLE_ERROR:
			default:
				$errorStr = "[{$errno}]{$errstr} ".basename($errfile)."({$errline})";
				Log::record($errorStr, Log::NOTICE);
				break;
		}
	}

	/* custom exception handler */
	public static function app_exception($e) {
		halt($e->__toString());
	}

	public function __destruct() {
		G('execTime'); // recode exectime

		/* save log */
		if(C('LOG.SWITCH')) {
			Log::save();
		}

		G('endTime');

		/* debug stat and page trace */
		if(!IS_AJAX && C('DEBUG.STAT')) {
			Debug::show_stat();
		}
		if(!IS_AJAX && C('DEBUG.PAGE_TRACE')) {
			Debug::show_trace();
		}
	}

	//[RUNTIME]
	/* load config, compile app */
	private static function _build() {
		/* load app constant */
		require_cache(CFG_PATH.D_S.'define.php');
		/* load app common option */
		C(require_cache(CFG_PATH.D_S.'comm.php'));
		/* load app common file */
		$common = '';
		if(is_file(LIB_COMM_PATH.D_S.'comm.func.php')) {
			include LIB_COMM_PATH.D_S.'comm.func.php';
 			/* load common function library */
			if(!C('DEBUG.SWITCH')) {
				$common .= compile(LIB_COMM_PATH.D_S.'comm.func.php'); // add to compile file
			}
		}
		/* load app extra config */
		$configs = C('APP.CFG_LIST');
		if(is_string($configs)) {
			$configs = explode(',', $configs);
			foreach($configs as $config) {
				if(is_file(CFG_PATH.D_S.$config.'.php')) {
					C(strtoupper($config), (include CFG_PATH.D_S.$config.'.php'));
				}
			}
		}
		C('APP.CFG_LIST', ''); // clear app extra config list

		/* compile app */
		if(!C('DEBUG.SWITCH')) {
			build_runtimeCache($common);
		}
	}
	//[/RUNTIME]

	/* load common config and function library */
	private static function _load_comm() {
		if(defined('GROUP_NAME')) {
			/* load group common config */
			C(require_cache(CFG_PATH.D_S.GROUP_NAME.D_S.'comm.php'));
			/* load group common function library */
			if(is_file(LIB_COMM_PATH.D_S.GROUP_NAME.D_S.'comm.func.php')) {
				include LIB_COMM_PATH.D_S.GROUP_NAME.D_S.'comm.func.php';
			}
		}
		/* load app extra function */
		$funcs = C('APP.FUNC_LIST');
		if(is_string($funcs)) {
			$funcs = explode(',', $funcs);
			foreach($funcs as $func) {
				if(is_file(LIB_COMM_PATH.D_S.$func.'.func.php')) {
					include LIB_COMM_PATH.D_S.$func.'.func.php';
				}
			}
		}
	}

	/* load language */
	private static function _load_lang() {
		$langName = C('LANG.NAME');
		/* detect language */
		if(C('LANG.DETECT')) {
			$lh = C('LANG.HOST');

			$langset = get_langset();
			$_t_l = '';
			if(in_array(__HOST__, $lh)) {
				$userAgent = array_search(__HOST__, $lh);
			}
			elseif('' != ARequest::get(C('VAR.LANG'))) {
				$_t_l = strtolower(ARequest::get(C('VAR.LANG')));
			}
			elseif('' != ACookie::get('lang')) {
				$_t_l = strtolower(ACookie::get('lang'));
			}
			elseif(isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
				preg_match('/^([a-z\-]+)/i', $_SERVER['HTTP_ACCEPT_LANGUAGE'], $matches);
				$_t_l = strtolower($matches[1]);
			}
			if(!empty($langName)) {
				if(array_key_exists($_t_l, $langset) and is_dir(LANG_PATH.D_S.$_t_l)) {
					$langName = $_t_l;
				}
				elseif(strpos($_t_l, '-')) {
					$_t_l = explode('-', $_t_l);
					$_t_l = $_t_l[0];
					if(array_key_exists($_t_l, $langset) and is_dir(LANG_PATH.D_S.$_t_l)) {
						$langName = $_t_l;
					}
				}
			}
			if($langName != ACookie::get('lang')) {
				ACookie::set('lang', $langName);
			}
		}

		define('LANG_NAME', $langName);
		/* load framework language */
		if(is_file(PFA_PATH.'/lang/'.LANG_NAME.'.lang.php')) {
			L(include PFA_PATH.'/lang/'.LANG_NAME.'.lang.php');
		}
		elseif(is_file(PFA_PATH.'/lang/'.C('LANG.NAME').'.lang.php')) {
			L(include PFA_PATH.'/lang/'.C('LANG.NAME').'.lang.php');
		}
		/* load common language */
		if(is_file(LANG_PATH.D_S.LANG_NAME.'/lang.php')) {
			L(include LANG_PATH.D_S.LANG_NAME.'/lang.php');
		}
		elseif(is_file(LANG_PATH.D_S.C('LANG.NAME').'/lang.php')) {
			L(include LANG_PATH.D_S.C('LANG.NAME').'/lang.php');
		}
		/* load group common language */
		if(defined('GROUP_NAME')) {
			if(is_file(LANG_PATH.D_S.LANG_NAME.D_S.GROUP_NAME.'/lang.php')) {
				L(include LANG_PATH.D_S.LANG_NAME.D_S.GROUP_NAME.'/lang.php');
			}
			elseif(is_file(LANG_PATH.D_S.C('LANG.NAME').D_S.GROUP_NAME.'/lang.php')) {
				L(include LANG_PATH.D_S.C('LANG.NAME').D_S.GROUP_NAME.'/lang.php');
			}
		}
		/* load controller language */
		if(is_file(LANG_PATH.D_S.LANG_NAME.D_S.CTRLR_NAME.'.lang.php')) {
			L(include LANG_PATH.D_S.LANG_NAME.D_S.CTRLR_NAME.'.lang.php');
		}
		elseif(is_file(LANG_PATH.D_S.C('LANG.NAME').D_S.CTRLR_NAME.'.lang.php')) {
			L(include LANG_PATH.D_S.C('LANG.NAME').D_S.CTRLR_NAME.'.lang.php');
		}
		/* load group controller language */
		if(defined('GROUP_NAME')) {
			if(is_file(LANG_PATH.D_S.LANG_NAME.D_S.GROUP_NAME.D_S.CTRLR_NAME.'.lang.php')) {
				L(include LANG_PATH.D_S.LANG_NAME.D_S.GROUP_NAME.D_S.CTRLR_NAME.'.lang.php');
			}
			elseif(is_file(LANG_PATH.D_S.C('LANG.NAME').D_S.GROUP_NAME.D_S.CTRLR_NAME.'.lang.php')) {
				L(include LANG_PATH.D_S.C('LANG.NAME').D_S.GROUP_NAME.D_S.CTRLR_NAME.'.lang.php');
			}
		}
		define('_LD_', ('rtl' == L('_LD_') ? 'rtl' : 'ltr'));
	}

	/* load template theme and define template constant */
	private static function _load_theme() {
		/* detect theme */
		if(C('TE.TPL_DETECT')) {
			$tplSet = C('TE.TPL_THEME');
			if('' != ARequest::get(C('VAR.TPL'))) {
				$tplSet = strtolower(ARequest::get(C('VAR.TPL')));
			}
			elseif('' != ACookie::get('theme')) {
				$tplSet = ACookie::get('theme');
			}
			/* use default theme when theme not exist */
			if(empty($tplSet) or !preg_match('/^[A-Za-z_0-9]+$/', $tplSet) or !is_dir(TPL_PATH.D_S.$tplSet)) {
				$tplSet = C('TE.TPL_THEME');
			}
			ACookie::set('theme', $tplSet);
			C('TE.TPL_THEME', $tplSet); // current template theme name
		}
 		/* current skin style name */
		define('THEME_NAME', C('TE.TPL_THEME'));

		/* detect user agent */
		$userAgent = '';
		if(C('TE.TPL_DETECT_USER_AGENT')) {
			$tuab = C('TE.TPL_USER_AGENT_BRANCH');
			$ua = detect_device(false);
			if(array_key_exists($ua, $tuab)) {
				$userAgent = $tuab[$ua];
			}

			/* tpl user agent host */
			$tuah = C('TE.TPL_USER_AGENT_HOST');

			if(in_array(__HOST__, $tuah)) {
				$_t_ua = array_search(__HOST__, $tuah);
			}
			elseif('' != ARequest::get(C('VAR.USER_AGENT'))) {
				$_t_ua = strtolower(ARequest::get(C('VAR.USER_AGENT')));
			}
			elseif(ACookie::get('user_agent')) {
				$_t_ua = ACookie::get('user_agent');
			}

			if(preg_match('/^[A-Za-z_0-9]+$/', $_t_ua)) {
				$userAgent = $_t_ua;
			}

			if($userAgent != ACookie::get('user_agent')) {
				ACookie::set('user_agent', $userAgent);
			}

			/* set user agent branch for tpl */
			if(!empty($userAgent) and in_array($userAgent, $tuab) and is_dir(TPL_PATH.D_S.C('TE.TPL_THEME').D_S.$userAgent)) {
				C('TE.TPL_THEME', C('TE.TPL_THEME').'/'.$userAgent);
			}
		}
		define('USER_AGENT', $userAgent);

		if(defined('GROUP_NAME')) {
			/* current template file */
			C('TE.CURRENT_FILE', parse_name(GROUP_NAME).D_S.parse_name(CTRLR_NAME).D_S.strtolower(ACTN_NAME));
		}
		else {
			C('TE.CURRENT_FILE', parse_name(CTRLR_NAME).D_S.strtolower(ACTN_NAME));
		}
		return;
	}

	/* load skin style and define skin constant */
	private static function _load_style() {
		/* detect style */
		if(C('TE.SKIN_DETECT')) {
			$skinSet = C('TE.SKIN_STYLE');
			if('' != ARequest::get(C('VAR.SKIN'))) {
				$skinSet = strtolower(ARequest::get(C('VAR.SKIN')));
			}
			elseif('' != ACookie::get('style')) {
				$skinSet = ACookie::get('style');
			}
			/* use default style when style not exist */
			if(empty($skinSet) or !preg_match('/^[A-Za-z_0-9]+$/', $skinSet) or !is_dir(SKIN_PATH.D_S.$skinSet)) {
				$skinSet = C('TE.SKIN_STYLE');
			}
			ACookie::set('style', $skinSet);
			C('TE.SKIN_STYLE', $skinSet); // current skin style name
		}

		/* skin root URL */
		define('__SKIN__', __RES__.SKIN_DIR.'/');
 		/* current skin style name */
		define('STYLE_NAME', C('TE.SKIN_STYLE'));
 		/* current skin style path */
		define('STYLE_PATH', SKIN_PATH.(STYLE_NAME ? D_S.STYLE_NAME : ''));
 		/* current skin style URL */
		define('__STYLE__', __SKIN__.(STYLE_NAME ? STYLE_NAME.'/' : ''));

		return;
	}
}

?>