<?php
class ServicesDispatcher{
	private static $mrInstance;

	var $mStartKey;
	var $mMultKey;
	var $mAddKey;
	var $mTokenTimeout = 30; // seconds

	private function __construct() {}

	function CreateToken(){
		$token = (string)microtime(true);
		$token = $this->_HashString($token);
		$this->mToken = $token;
	}

	function GetModule($module) {
		$class_name = 'Process' . ucfirst($module);
		$filename = $class_name . '.proc.class.php';
		$path_to_load = GTFW_APP_DIR . 'module/' . $module . '/response/' . $filename;

		if (file_exists($path_to_load)) {
			return array($path_to_load, $class_name);
		} else {
			return array(FALSE, $class_name);
		}
	}

	function ModuleNotFound() {
		echo 'There is no such page or module!';
	}

	function Encrypt($string) {
		$start_key = $this->mStartKey;
		$encrypted = '';
		for ($i = 0, $m = strlen($string); $i < $m; ++$i) {
			$encrypted = $encrypted . chr(ord($string{$i}) ^ ($start_key >> 8));
			$start_key = ((ord($encrypted{$i}) + $start_key) * $this->mMultKey) + $this->mAddKey;
		}
		return urlencode(base64_encode($encrypted));
	}

	function Decrypt($string) {
		$start_key = $this->mStartKey;
		$string = base64_decode(urldecode($string));
		$decrypted = '';
		for ($i = 0, $m = strlen($string); $i < $m; ++$i) {
			$decrypted = $decrypted . chr(ord($string{$i}) ^ ($start_key >> 8));
			$start_key = ((ord($string{$i}) + $start_key) * $this->mMultKey) + $this->mAddKey;
		}
		return $decrypted;
	}

	function Dispatch() {
		$allowedHost = Configuration::Instance()->GetValue('application', 'services_allowed_host');
		if(in_array($_SERVER['REMOTE_ADDR'],$allowedHost)){
			if(!isset($_REQUEST['t'])){
				$this->CreateToken();
				echo $this->mToken;
				die;
			}else $this->_SetKey($_REQUEST['t']);
			// send header first
			header('Cache-Control: no-cache, must-revalidate');
			header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');

			$service = $this->Decrypt($_REQUEST['func']);
			$service = explode('->', $service, 2);
			$module = $service[0];
			$function = 'Service' . $service[1];
			unset($_REQUEST['t']);
			unset($_REQUEST['func']);
			list($file_path, $class_name) = $this->GetModule($module);

			if (FALSE === $file_path) {
				$this->ModuleNotFound();
			} else {
				include $file_path;
				$response = new $class_name(true);
				if(method_exists($response, $function))echo $this->returnJSON($response->$function($_REQUEST));
				else echo 'method doesn\'t exists';
			}
		}
		die;
	}

	function returnJSON($value){
		if (class_exists('Services_JSON')) { // JOSN via PEAR
			$json = new Services_JSON();
			$output = $json->encode($value);
			return $output;
		} elseif (function_exists('json_encode')) { // json.so
			return json_encode($value);
		}
	}
	
	static function Instance() {
		if (!isset(self::$mrInstance))
			self::$mrInstance = new ServicesDispatcher();

		return self::$mrInstance;
	}

	function _SetKey($token){
		$token = $this->_UnhashString($token);
		$to = time() - $this->mTokenTimeout;
		$arr = explode('.', $token);
		if($arr[0] < $to){
			echo 'timeout';
			die;
		}
		$this->mStartKey = (int)$arr[1];
		$this->mMultKey = (int)substr($arr[0], -4);
		$this->mAddKey = (int)substr($arr[0], -8, -4);
	}
	
	function _HashString($str){
		$ret = '';
		if(isset($str)){
			$i = strlen($str);
			do{
				$ret .= ord($str{$i});
			}while(--$i > -1);
		}
		return $ret;
	}
	
	function _UnhashString($str){
		$ret = '';
		if(isset($str)){
			$i = strlen($str);
			do{
				$tmp = substr($str,0,2);
				if($tmp<32){
					$tmp .= $str[2];
					$k = 3;
				}else{
					$k = 2;
				}
				$ret = chr($tmp) . $ret;
				$str = substr($str,$k);
			}while($i-=$k > 0);
		}
		return trim($ret);
	}
}
ServicesDispatcher::Instance()->Dispatch();
?>