<?PHP
/**
* engine - causes the template and the models, combines models of the controller and the core classes
* combines controller and the SQL sentences
*/
class Engine extends Template{

	var $modelPageList = array();

	function __init(){

		$sql_name = _SQL;
		$this->callClass($sql_name)->connect();
		$this->connection = $this->$sql_name->connection;
		$this->database = $this->$sql_name->database;
		$this->Sql = $this->$sql_name;

		$this->callClass('Request', array('Sql' => $this->Sql));
		$this->callClass('defineLanguage');
		if(_UseStaticPagelist == false){

			$this->Request->convertRequest();
			$this->Request->injectionRestriction();
			$this->defineLanguage->setLanguage();

			$this->callClass('Access', array('Sql' => $this->Sql, 'Register' => $this->callClass('Register')));
			$this->modelPageList = $this->Access->__getAccess();
		}
		else{

			$this->modelPageList = json_decode(_ModelPageList, true);
		}
		if( preg_match('/\:/i', $_GET['request']) && !$_GET['model'] ){

			$exp = explode('?', $_GET['request']);
			$request = $exp[0];
			if($exp[1]){

				foreach(explode('&', str_replace('/?', '', $exp[1])) as $v){

					$v = str_replace('?', '', $v);
					list($key, $value) = explode('=', $v);

					if($key && $value){

						$_GET[$key] = $value;
						$prev_key = $key;
					}
					else{

						if($prev_key)
							$_GET[$prev_key] .= '&'.$key.$value;
					}
				}
			}
			$cmd = substr($request, 1);
			if(substr($request, 0, 1) == '/')
				$cmd = substr($request, 2);
			die($this->callCommand($cmd));
		}
	}

	/**
	* call engine with template
	* 
	* @param string $page_position - public or admin
	* @param string $template='template' - template name
	*/
	function __Engine($page_position, $template='template'){

		$this->page_position = $page_position;
		$this->__init();
		$this->__Template($template);
	}

	function inc($include){

		if(is_array($include)){

			foreach($include as $v){

				if(file_Exists(_RootFolder.'/'.$v.'.php')){

					require_once _RootFolder.'/'.$v.'.php';
				}
				else{

					require_once $v.'.php';
				}
			}
		}
		else{

			if(file_Exists(_RootFolder.'/'.$include.'.php')){

				require_once _RootFolder.'/'.$include.'.php';
			}
			else{

				require_once $include.'.php';
			}
		}
	}
	/**
	* @return $_SESSION['UserData'] As object
	* 
	* @example $this->userData()->user_id
	*/
	function userData(){

		return json_decode(json_encode($_SESSION['UserData']), FALSE);
	}

	/**
	* require core class
	* 
	* @param className $class_name
	* @param class $class_file='' file
	*/
	private function requireClass($class_name, $class_file=''){

		if($class_file){

			if(file_exists(_Classes.'/class.'.$class_file.'.php')){

				require_once _Classes.'/class.'.$class_file.'.php';
				return true;
			}
		}
		else if(file_exists(_Classes.'/class.'.$class_name.'.php')){

			require_once _Classes.'/class.'.$class_name.'.php';
			return true;
		}
	}

	/**
	* call sql class
	* 
	* @param array $class_sql
	* @param class $class object
	* 
	* @example in controller var $call_sql_class = array('table_name')
	*/
	function callSqlClass($class_sql, $class){

		foreach ($class_sql as $call_sql){

			if(strtolower($call_sql) != 'sql'){

				if(file_Exists(_RootFolder.'/app/querys/'.$call_sql.'.php')){

					require_once _RootFolder.'/app/querys/'.$call_sql.'.php';
					$sql_class_name = $call_sql.'_SQL';

					$class->$call_sql = new $sql_class_name();
					$class->$call_sql->class_orig_name = $call_sql;
					$class->$call_sql->class_name = $call_sql;
					$class->$call_sql->connection = $this->connection;
					$class->$call_sql->database = $this->database;
				}
			}
		}
		return $class;
	}

	/**
	* call the core class
	*
	* @param array $class_name
	* @param object $set_additional_object = '' - it will pass thrue object paramteres
	* @param class $class_file='' As string - if class file name is not same name
	*
	* @example in controller var $call_class = array('className')
	* 
	*/
	function callClass($class_name, $set_additional_object = '', $class_file=''){

		if(is_array($class_name)){

			foreach($class_name as $v){

				$this->callClass($v, $set_additional_object);
			}
		}
		else{

			if($this->requireClass($class_name, $class_file)){

				if(!property_exists($this, $class_name) || ($this->$class_name instanceof StdClass)){

					$class = new $class_name();
					$class->Sql = $this->Sql;
					$class->connection = $this->connection;
					if($class->call_sql_class){

						$class = $this->callSqlClass($class->call_sql_class, $class);
					}
					if($class->clone_class){

						$class = $this->cloneClass($class->clone_class, $class);
					}
					if($class->get_object){

						$class = $this->getObject($class->get_object, $class);
					}
					if($set_additional_object){

						foreach($set_additional_object as $name => $value){

							$object_name = $name;
							$class->$name = $value;
						}
					}
				}
			}
			else{

				if(!property_exists($this, $class_name) && class_exists($class_name)){

					$class = new $class_name();
					$class->Sql = $this->Sql;
					$class->connection = $this->connection;
					if($class->call_sql_class){

						$class = $this->callSqlClass($class->call_sql_class, $class);
					}
					if($class->clone_class){

						$class = $this->cloneClass($class->clone_class, $class);
					}
					if($class->get_object){

						$class = $this->getObject($class->get_object, $class);
					}
					if($set_additional_object){

						foreach($set_additional_object as $name => $value){

							$object_name = $name;
							$class->$name = $value;
						}
					}
				}
			}
		}

		if($class->call_class){

			$class = $this->callParentClass($class->call_class, $class);
		}
		if((gettype($class_name) == 'string' && !property_exists($this, $class_name)) || ($this->$class_name instanceof StdClass)){

			$this->$class_name = $class;
		}
		return $this->$class_name;
	}

	/**
	* private function
	*/
	private function callParentClass($class_obj, $class){

		foreach ($class_obj as $call_class){

			if(!property_exists($class, $callobj)){

				$class->$call_class = $this->callClass($call_class);
				if( gettype($class->$call_class) != 'NULL' ){

					$class->$call_class->model = $class->model;
					$class->$call_class->page = $class->page;
				}
			}
		}
		return $class;
	}

	/**
	* clone class As new class name
	* 
	* @param Array $clone_class - array( array('className' => 'classNewName') )
	* @param Object $class_obj
	* 
	* @example $self->cloneClass(array( array('className' => 'classNewName') ), $self)
	* @example in controller var $clone_class = array( array('className' => 'classNewName') )
	*/
	function cloneClass($clone_class, $class_obj){

		foreach($clone_class as $v){

			$a_keys = array_keys($v);
			$key = $a_keys[0];
			$from = $key;
			$to = $v[$key];

			$class_obj->$to = clone $class_obj->$from;
			$class_obj->$to->class_orig_name = $from;
			$class_obj->$to->class_name = $to;
		}
		return $class_obj;
	}

	/**
	* get object from parent class
	* 
	* @param Array $objects Or String
	* @param Object $class
	* 
	* @return $class As Object
	* 
	* @example $self->getObject('objectVariableName', $self)
	* usage $self->objectVariableName
	* @example in controlelr var $get_object = 'objectVariableName'
	* usage $this->objectVariableName
	*/
	private function getObject($objects, $class){

		if(is_array($objects)){

			foreach($objects as $v){

				$this->getObject($v, $class);
			}
		}
		else{

			if(!property_exists($class, $objects)){

				$class->$objects = $this->$objects;
			}
		}
		return $class;
	}

	/**
	* call helper(s)
	* 
	* @param Array $helpers Or String
	*/
	private function callHelper($helpers, $controllers, $model_obj){

		if(is_Array($helpers)){

			foreach($helpers as $v){

				if(is_file(_RootFolder.'/app/helpers/'.$v.'.php')){

					require_once _RootFolder.'/app/helpers/'.$v.'.php';
					foreach($controllers as $controller){

						if(is_object($model_obj->$controller)){

							$model_obj->$controller->$v = new $v;
						}
					}
				}
			}
		}
		else{

			if(is_file(_RootFolder.'/app/helpers/'.$helpers.'.php')){

				require_once _RootFolder.'/app/helpers/'.$helpers.'.php';
				foreach($controllers as $controller){

					if(is_object($model_obj->$controller)){

						$model_obj->$controller->$helpers = new $helpers;
					}
				}
			}
		}
		return $model_obj;
	}

	/**
	* call controller
	* 
	* @param Array $call_controller
	* @param String $model
	* @param String $page As
	* @param String $page_position - admin,public
	* @param String $position - template position
	* @param String $type - plugin,model
	* @param Object $model_obj
	* 
	* @example in controller var $call_controller = array('controllerName')
	* @example in controller var $call_controller = array('modelName/controllerName') As child controller
	*/
	private function callControllers($call_controller, $model, $page, $page_position, $position, $type, $model_obj){

		if($call_controller){

			$dir = $type == 'plugin' ? 'plugins' : 'models';

			foreach($call_controller as $k => $controller){

				$controller_as = $controller;
				$controller = !is_numeric($k) ? $k : $controller;

				if(file_exists(_RootFolder.'/app/'.$dir.'/'.$controller.'/controller.php')){

					require_once _RootFolder.'/app/'.$dir.'/'.$controller.'/controller.php';
					$controller_class = new $controller;
					$controller_class->model = $model;
					$controller_class->page = $page;
					$controller_class->page_position = $page_position;
					$controller_class->position = $position;
					$controller_class->type = $type;
					$controller_class->Sql = $this->Sql;
					$controller_class->connection = $this->connection;
					$controller_class->Request = $this->Request;
					$controller_class->Access = $this->Access;

					if($model != $controller){

						$model_obj->other_controller[$controller_as] = $controller_as;
					}

					if($controller_class->call_class){

						$controller_class = $this->callParentClass($controller_class->call_class, $controller_class);
					}
					if($controller_class->call_sql_class){

						$controller_class = $this->callSqlClass($controller_class->call_sql_class, $controller_class);
					}
					if($controller_class->clone_class){

						$controller_class = $this->cloneClass($controller_class->clone_class, $controller_class);
					}
					if($controller_class->get_object){

						$controller_class = $this->getObject($controller_class->get_object, $controller_class);
					}
					$model_obj->$controller_as = $controller_class;
				}
			}
		}
		return $model_obj;
	}

	/**
	* call child model
	* 
	* @param String $call_model
	* @param String $page_position - public,admin
	* @param String $position - template position
	* @param Object $model_obj
	* 
	* @example in model var $call_model = array('modelName')
	*/
	private function callModels($call_model, $page_position, $position, $model_obj){

		if($call_model){

			foreach($call_model as $model){

				$this->$model_obj->$model = $this->callModelPage($model, 'none', $page_position, $variable, $position, 'model');
			}
		}
		return $this->$model_obj;
	}

	/**
	* call plugin and page
	* 
	* @param Array $plugins
	* @param Object $model_obj
	* 
	* @example in model var $call_plugin = array('pluginName')
	*/
	private function callPlugins($plugins, $model_obj){

		foreach ($plugins as $k => $v){

			$model_obj->$v = $this->callModelPage($v, '', $this->page_position, $variables, $this->position, 'plugin');
		}
		return $model_obj;
	}

	/**
	* call model and page
	* 
	* @param String $model
	* @param String $page
	* @param String $page_position - admin,public
	* @param Array $variable - sets object variables
	* @param String $position='' - template position
	* @param String $type='model' - model,plugin
	* 
	* @example in model var $call_model = array('modelName')
	*/
	private function callModelPage($model, $page, $page_position, $variable, $position='', $type='model'){

		$dir = $type == 'plugin' ? 'plugins' : 'models';
		$ext = $type == 'plugin' ? '_Plugin' : '_Model';

		if(file_exists(_RootFolder.'/app/'.$dir.'/'.$model.'/index.php')){

			$controller = $this->$model;

			require_once _RootFolder.'/app/'.$dir.'/'.$model.'/index.php';
			$model_class_name = $model.$ext;
			if(class_exists($model_class_name)){

				if(!is_object($this->$model)){

					$this->$model = new $model_class_name;
				}
				$this->$model->model = $model;
				$this->$model->page = $page;
				$this->$model->page_position = $page_position;
				$this->$model->position = $position;
				$this->$model->type = $type;

				if($this->$model->{'include'}){

					$this->inc($this->$model->{'include'});
				}
				if($this->$model->call_model){

					$this->$model = $this->callModels($this->$model->call_model, $page_position, $position, $this->$model);
				}
				if($this->$model->call_plugin){

					$this->$model = $this->callPlugins($this->$model->call_plugin, $this->$model);
				}
				if($this->$model->call_controller){

					$this->$model = $this->callControllers($this->$model->call_controller, $model, $page, $page_position, $position, $type, $this->$model);
					if($this->$model->other_controller && is_object($this->$model->$model)){

						foreach($this->$model->other_controller as $v){

							if(!property_exists($this->$model->$model, $v))
								$this->$model->$model->$v = $this->$model->$v;
							else
								die("this property exists, rename controller like array('".$v."' => '".$v."_new')");
						}
					}
				}
				if($this->$model->call_helper){

					$this->$model = $this->callHelper($this->$model->call_helper, $this->$model->call_controller, $this->$model);
				}

				if(method_exists($this->$model, $page)){

					$this->$model->$page($variable);
				}
				else{

					return $this->$model;
				}
			}
		}
	}

	private function callModelPages($position){

		$in_list = array();
		//$position = $_GET['position'] ? $_GET['position'] : $position;

		if(is_array($this->modelPageList[$position])){

			foreach ($this->modelPageList[$position] as $k => $v){

				if( ($v['is_static'] == true || ($v['model'] == $_GET['model'] && $v['page'] == $_GET['page']) || ($v['is_first_page'] == true && !$_GET['model'])) && preg_match('/'.$this->page_position.'/i', $v['page_position']) ){

					$this->callModelPage($v['model'], $v['page'], $this->page_position, '', $position, 'model');
					$in_list[$v['model']][$v['page']] = true;
				}
			}
		}
		if( $_GET['model'] && $_GET['page'] && _UseStaticPagelist == false ){

			if( !$in_list[$_GET['model']][$_GET['page']] && ($position == 'center' || $position == 'content') && file_exists(_RootFolder.'/app/models/'.$_GET['model'].'.php') ){

				if($_GET['view'] == 'graphic') echo _RootFolder.'/app/model/'.$_GET['model'].'.php PAGE - '.$_GET['page'].'<br>';
				$this->callModelPage('session', 'session_expired', $this->page_position, '', $position, 'model');
			}
		}
	}

	/**
	* call private command
	* 
	* @param String $command - app/commands/command.php
	* 
	* @example http://domain/:command
	*/
	private function callCommand($command){

		if(file_exists(_RootFolder.'/app/commands/'.$command.'.php')){

			require_once _RootFolder.'/app/commands/'.$command.'.php';
		}
	}

	/**
	* call model with page
	* 
	* @param String $model
	* @param String $page
	*/
	function callModel($model, $page){

		$this->callModelPage($model, $page, $this->page_position, '', $this->position, 'model');
	}

	/**
	* call plugin with page
	* 
	* @param String $plugin
	* @param String $page
	*/
	function callPlugin($plugin, $page){

		$this->callModelPage($plugin, $page, $this->page_position, '', $this->position, 'plugin');
	}

	/**
	* template position
	* 
	* @param String $position
	* 
	* @example in template.php file $this->position('header')
	*/
	function position($position){

		if($_GET['show_position'])
			echo '<div style=\'border:1px solid blue;clear:both;\'>'.
			'<a class=pointer style=\'position:relative;z-index:2000;\'><b class=template_position><font color=red size=5 class='.$position.'>POSITION: '.$position.'</font></b></a>';
		$this->callModelPages($position);
		if($_GET['show_position'])
			echo '</div>';
	}

	/**
	* its alias of
	* print '<pre>';
	* print_r($array);
	* print '</pre>';
	* 
	* @param Array $array or Object
	*/
	function pre($array){

		print '<pre>';
		print_R ($array);
		print '</pre>';
	}

	function memoryGetUsage(){

		$size = memory_get_usage(false);

		$unit=array('b','kb','mb','gb','tb','pb');
		return @round($size/pow(1024,($i=floor(log($size,1024)))),2).' '.$unit[$i];
	}

	/**
	* calls mysql end
	*/
	function end(){

		if($this->Sql && $this->connection){

			$this->Sql->close();
		}
		session_write_close();
	}
}

?>