<?php

class ToolsHandler extends Handler{

	function __construct(){
		parent::__construct('ToolsHandler');
	}

	function getRedirects(){
		global $ROOT_PATH;
		$redirects = array('from' => array(),'to' => array());
		$path = $ROOT_PATH.'/.htaccess';
		if(is_readable($path)){
			$fh = fopen($path,"r");
			$data = fread($fh, filesize($path));
			//print $data;
			fclose($fh);
			$data_arr = explode("\n",$data);
			//printArray($data_arr);
			$r_start = array_search('#start_redirect',$data_arr);
			$r_end = array_search('#end_redirect',$data_arr);
			if ($r_end-$r_start > 1)
				for ($i=$r_start+1;$i<$r_end;$i++){
				$redirects['from'][] = preg_replace('/RewriteRule\s\^(.*)\$\shttp:\/\/(.*)\s.*/i','\\1',$data_arr[$i]);
				$temp   = preg_replace('/RewriteRule\s(.*)\s(http:\/\/.*?)(\/.*)?\s.*/i','\\2\\3',$data_arr[$i]);
				//print $temp.'<br>';
				$redirects['to'][] = preg_replace('/^http:\/\/'.getenv('HTTP_HOST').'/i','',$temp);
			}
		}
		//printArray($redirects);
		return $redirects;
	}

	function validateSite($request = array()){
		global $REGISTRY, $ROOT_PATH, $TOOLS_PATH, $area_codes, $cities;
		$log = array(); $templ_id = array();
		$redirects = $this->getRedirects();
		$selected = $this->DB->SelectAny('SELECT id FROM template;');
		if(!empty($selected))
			foreach($selected as $value) $templ_id[] = $value['id'];
		//printArray($templ_id);
		switch ($request['subject']){
			case 'Registry':
				$selected = $this->DB->SelectAny('SELECT id,name FROM module WHERE is_describe = 1 and type <> 2 and type <> 3;');
				if(!empty($selected))
					foreach($selected as $value) {
						$temp = array();
						$temp['path'] = $this->path_sticker($value['id']);
						$temp['name'] = $value['name'];
						$temp['edit_path'] = '/Registar/ContentManager/Update/'.$value['id'];
						if (!array_key_exists(strtolower($temp['path']),$REGISTRY['VirtualSlotTarget']['main']))
							$log[] = $temp;
					}
				return $log;
			case 'Redirects':
				$temp = array();
				foreach($redirects['to'] as $to){
					if(!preg_match('/^(http:\/\/)/i',$to) && !array_key_exists(strtolower(preg_replace("/\?.*/",'',$to)),$REGISTRY['VirtualSlotTarget']['main'])){
						$temp['path'] = $to;
						$log[] = $temp;
					}
				}
				return $log;
			case 'Menus':
				$selected = $this->DB->SelectAny('SELECT m.name, m.id, mm.path, m.type FROM menulineitem mm, menu m WHERE m.id = mm.ownerid and is_external = 0 and ownerid != 2 ORDER BY m.name');
				if(!empty($selected))
					foreach($selected as $value) {
						$temp = array();
						$temp['name'] = $value['name'];
						$temp['path'] = trim(preg_replace("/#.*/",'',$value['path']));
						$temp['path'] = trim(preg_replace("/\?.*/",'',$temp['path']));
						if (preg_match('/^(http|mailto|javascript|\.|\?)/i',$temp['path'])) continue;
						if(!preg_match('/^[\?\/]/',$temp['path'])) $temp['path'] = '/'.$temp['path'];
						switch ($value['type']){
							case '1': $temp['edit_path'] = '/Registar/MenuManager/SiteMap';break;
							case '3': $temp['edit_path'] = '/Registar/MenuManager/BottomMenu/Update/'.$value['id'];break;
							case '4': $temp['edit_path'] = '/Registar/MenuManager/LeftMenu/Update/'.$value['id'];break;
							case '6': $temp['edit_path'] = '/Registar/MenuManager/RightMenu/Update/'.$value['id'];break;
							case '7': $temp['edit_path'] = '/Registar/MenuManager/TabsMenu/Update/'.$value['id'];break;
							default: $temp['edit_path'] = '/Registar/MenuManager';break;
						}
						if(!array_key_exists(strtolower(preg_replace('/\/$/','',$temp['path'])),$REGISTRY['VirtualSlotTarget']['main']) and !is_file($ROOT_PATH.$temp['path']) and !in_array($temp['path'],$redirects['from']))
							$log[] = $temp;
					}
				return $log;
			case 'Layouts':
				$temp =array();
				$selected = $this->DB->SelectAny("SELECT id, name, value FROM layout WHERE value IS NOT NULL");
				if(!empty($selected) && sizeof($selected)) {
					foreach($selected as $value) {
						$temp[] = array(
							'name' => $value['name'],
							'edit_path' => '/Registar/LayoutManager/Update/'.$value['id'],
							'content' => $value['value']
						);
					}
				}
				break;
			case 'Templates':
				$temp =array();
				$selected = $this->DB->SelectAny('SELECT t.value, tg.name, tg.id FROM templateitem t, template tg WHERE tg.id = t.ownerid AND t.value IS NOT NULL');
				if(!empty($selected))
					foreach($selected as $value) {
						if($value['value'] == '') continue;
						$temp[] = array(
							'name' => $value['name'],
							'edit_path' => '/Registar/TemplateManager/Update/'.$value['id'],
							'content' => $value['value']
						);
					}
				break;
			case 'Pages':
				$temp =array();
				$selected = $this->DB->SelectAny('SELECT c.value, m.name, m.id FROM content c, module m WHERE m.id = c.ownerid AND c.value IS NOT NULL');
				if(!empty($selected))
					foreach($selected as $value) {
						if($value['value'] == '') continue;
						$temp[] = array(
							'name' => $value['name'],
							'edit_path' => '/Registar/ContentManager/Update/'.$value['id'],
							'content' => $value['value'],
							'type' => 'page',
							'id' => $value['id'],
						);
					}
				$selected = $this->DB->SelectAny('SELECT j.value, m.name, m.id FROM modulejszone j, module m WHERE m.id = j.ownerid AND j.value IS NOT NULL');
				if(!empty($selected))
					foreach($selected as $value) {
						if($value['value'] == '') continue;
						$temp[] = array(
							'name' => $value['name'],
							'edit_path' => '/Registar/MetaManager/Page/'.$value['id'],
							'content' => $value['value']
						);
					}
				break;
		}
		if(!empty($temp))
		foreach($temp as $key => $value){
			$text = preg_replace("~'~","\"",$value['content']);
			$text = preg_replace("~&#39;~","\"",$text);
			$text = preg_replace("~&quot;~","\"",$text);
			$text = preg_replace("/%20/"," ",$text);
			$text = preg_replace("/<!--.*?-->/s"," ",$text);
			$text = preg_replace("/<script.*?\/script>/is",'',$text);
			$text = preg_replace("/<style.*?\/style>/is",'',$text);
			$text_arr = explode('>',$text);
			// Files
			$temp[$key]['type'] = 'file';
			$arr = $this->getLinks($text_arr);
			if(!empty($arr))
				foreach($arr as $val) {
					//print strtolower($val).'<br>';
					//if(!empty($temp[$key]['type']) && $temp[$key]['type']=='page') {
						//if(!empty($temp[$key]['id'])) {
							//print '<li>'.strtolower($val).'<br>';
						//}
					//}
					if(empty($cities)) $cities = $this->DB->SelectAny('SELECT path FROM module where type=9');
					if(isset($cities[0]['path']) && preg_match("/^(\/".$cities[0]['path'].")/i",$val)) {
						$paths = explode('/',strtolower(preg_replace('/^\//i','',$val)));
						array_shift($paths);
						if(empty($area_codes)) $area_codes = $this->DB->SelectList('name_in_url','city',array('name_in_url'));
						if(in_array($paths[0],$area_codes)) continue;
					}
					if(array_key_exists(strtolower(preg_replace('/\/$/','',$val)),$REGISTRY['VirtualSlotTarget']['main']) or in_array($val,$redirects['from'])) continue;
					if(!is_file($ROOT_PATH.$val)){
						$temp[$key]['path'] = $val;
						$log[] = $temp[$key];
						//print '<li>'.$temp[$key]['type'].' '.$temp[$key]['id'];
					}
				}
			// Braces
			$temp[$key]['type'] = 'braces';
			if ($request['subject'] == 'Layouts'){
			foreach ($text_arr as $text_row)
				if (preg_match_all('/{.*?}/is',$text_row, $l_arr))
					foreach ($l_arr as $l_row) foreach ($l_row as $braces){
						if (!((preg_match('/.*:static}/i',$braces) && array_key_exists(preg_replace('/{+(.*):.*/is','\\1',$braces),$REGISTRY['Globals']['static'])) or
							(preg_match('/.*:virtual}/i',$braces) && array_key_exists(preg_replace('/{+(.*):.*/is','\\1',$braces),$REGISTRY['VirtualSlotTarget'])) or (preg_match('/{Template.*?}/is',$braces)))){
							$temp[$key]['path'] = $braces;
							$log[] = $temp[$key];
						}
					}
			}
			// Templates
			foreach ($text_arr as $text_row)
				if (preg_match_all('/{Template\*.*?}/is',$text_row, $l_arr))
					foreach ($l_arr as $l_row) foreach ($l_row as $braces){
						if (!(preg_match('/{Template\*(.*?)\*(\d+)\*(\d+)\*(\d+)}/i',$braces) && in_array(preg_replace('/{Template\*(.*?)\*(\d+)\*(\d+)\*(\d+)}/is','\\2',$braces),$templ_id))){
							$temp[$key]['path'] = $braces;
							$log[] = $temp[$key];
						}
					}
		}
		return $log;
	}

	function getLinks($text_arr=array()){
		global $REGISTRY;
		$links_array = array();
		$rep_pattern = array(
			"/.*src[\s]*=[\s]*\"([^\"]*)\".*/i",
			"/.*window\.open[\s]*\([\s]*\"([^\"]*)\".*/i",
			"/.*window\.location[\s]*=[\s]*\"([^\"]*)\".*/i",
			"/.*document\.location[\s]*=[\s]*\"([^\"]*)\".*/i",
			"/.*location\.href[\s]*=[\s]*\"([^\"]*)\".*/i",
			"/.*location\.pathname[\s]*=[\s]*\"([^\"]*)\".*/i",
			"/.*url[\s]*\([\s]*\"?[\s]*([^\"]*)\"?\).*/i",
			"/.*url[\s]*=[\s]*\"?[\s]*([^\"]*)\"?.*/i",
			"/.*href[\s]*=[\s]*\"([^\"]*)\".*/i"
		);
		$match_pattern = "/[href|window\.|location|url].*/i";
		foreach($text_arr as $text_row)
			if (preg_match_all($match_pattern,$text_row, $l_arr)){
				foreach ($l_arr as $l) foreach ($l as $l_row){
					$link = preg_replace($rep_pattern,"\\1",$l_row);
					if (strcmp($link,$l_row) != 0){
						if(preg_match('/^(http|mailto|javascript|\.|\?)/i',$link)) continue;
						$link = preg_replace('/#.*/','',$link);
						$link = trim(preg_replace("/\?.*/",'',$link));
						if (preg_match('/{.*}.*/',$link))
							foreach ($REGISTRY['Globals']['static'] as $key => $reg)
								if (is_string($reg)) $link = preg_replace('/{'.$key.':static}/i',$reg,$link);
						if($link!='' && !preg_match('/^[\?\/{]/',$link)) $link = '/'.$link;
						if ($link != '' && $link != '#') $links_array[] = $link;
					}
				}
			}
		return array_unique($links_array);
	}

	function path_sticker($id){
		global $DatabaseBroker, $Paths;
		if(empty($Paths)) {
			$query = 'SELECT id, path, parent FROM module';
			$selected = $DatabaseBroker->SelectAny($query);
			foreach($selected as $value)
				$Paths[$value['id']] = array(
					'path' => $value['path'],
					'parent' => $value['parent'],
				);
		}
		$p = '';
		while(1){
			if(empty($Paths[$id])) return null;
			if(empty($Paths[$id]['parent'])) return '/'.$Paths[$id]['path'].$p;
			$p = '/'.$Paths[$id]['path'].$p;
			$id = $Paths[$id]['parent'];
		}
	}

	function colorize($text='',$color='red',$bold='normal') {
		return '<span style="color:'.$color.';font-weight:'.$bold.';">'.$text.'</span>';
	}

	function getSignature($request = array()) {
		GLOBAL $ROOT_PATH;
		if(!fopen($ROOT_PATH."/engine/signature.inc", "r")) $request['_error'] = 'Can\'t read signature file from current server';
		else if(eval(str_replace('$signature', '$request', file_get_contents($ROOT_PATH."/engine/signature.inc"))) === false) $request['_error'] = 'Signature code is not valid';
		return $request;
	}

	function createBackup(){
		$backup = new Backup();
		$backup->action = new ObjectsList();
		$backup->action->type = $this->createBackupAction();
		return $backup;
	}

	function createBackupAction(){
		$backupaction = new BackupAction();
		$backupaction->report = new ObjectsList();
		$backupaction->report->type = new BackupActionReport();
		return $backupaction;
	}

	function saveBackupAction($request = array()){
		$backupaction = $this->createBackupAction();
		$this->parseRequest($request, $backupaction);
		$this->DB->processObject($backupaction);
		$this->DB->commit();
		return $backupaction;
	}

	function selectBackups($request = array()){
		GLOBAL $ROOT_PATH, $COMMON_VARS;
		$selected = $this->DB->SelectAny('SELECT * FROM backup ORDER BY date_created DESC, date_restored DESC');
		foreach($selected as $key => $value){
			$datetime = explode('.', $value['date_created']);
			$selected[$key]['date_created'] = $datetime[0];
			$datetime = explode('.', $value['date_restored']);
			$selected[$key]['date_restored'] = $datetime[0];
			$selected[$key]['_error'] = '';
			if(!file_exists($ROOT_PATH.'/'.$COMMON_VARS['backup_dir'].'/'.$value['filename']) || !is_file($ROOT_PATH.'/'.$COMMON_VARS['backup_dir'].'/'.$value['filename']))
				$selected[$key]['_error'] = 'File of system backup doesn\'t exist';
			else if(!is_readable($ROOT_PATH.'/'.$COMMON_VARS['backup_dir'].'/'.$value['filename']))
				$selected[$key]['_error'] = 'Invalid file permissions';
		}
		return $selected;
	}

	function openBackup($request = array()){
		GLOBAL $ROOT_PATH, $COMMON_VARS;
		$backup = $this->createBackup();
		$backup->id = $request['id'];
		$this->DB->initObject($backup);
		$datetime = explode('.', $backup->date_created);
		$backup->date_created = $datetime[0];
		$filepath = $ROOT_PATH.'/'.$COMMON_VARS['backup_dir'].'/'.$backup->filename;
		if(!file_exists($filepath) || !is_file($filepath)) $backup->_error = 'File doesn\'t exist';
		else{
			$format = 'Y-m-d H:i:s';
			$backup->fileinfo['access'] = date($format, fileatime($filepath));
			$backup->fileinfo['modify'] = date($format, filemtime($filepath));
			$fileperms = fileperms($filepath);
			$fileowner = posix_getpwuid(fileowner($filepath));
			$uperms[] = (($fileperms & 0x0100) ? 'r' : '-');
			$uperms[] = (($fileperms & 0x0080) ? 'w' : '-');
			$uperms[] = (($fileperms & 0x0040) ? (($fileperms & 0x0800) ? 's' : 'x' ) : (($fileperms & 0x0800) ? 'S' : '-'));
			$backup->fileinfo['owner'] = $fileowner['name'].' ('.implode('', $uperms).')';
			$filegroup = posix_getgrgid(filegroup($filepath));
			$gperms[] = (($fileperms & 0x0020) ? 'r' : '-');
			$gperms[] = (($fileperms & 0x0010) ? 'w' : '-');
			$gperms[] = (($fileperms & 0x0008) ? (($fileperms & 0x0400) ? 's' : 'x' ) : (($fileperms & 0x0400) ? 'S' : '-'));
			$backup->fileinfo['group'] = $filegroup['name'].' ('.implode('', $gperms).')';
			$backup->fileinfo['size'] = filesize($filepath);
			$temp_dir_path = $ROOT_PATH.'/'.$COMMON_VARS['backup_dir_temp'].'/'.$backup->uid;
			$Archive = new Archive(dirname($filepath).'/', $ROOT_PATH.'/', $backup->filename, true);
			$objects_state_file_path = $COMMON_VARS['backup_dir_temp'].'/'.$backup->uid.'/'.$COMMON_VARS['objects_state_file'];
			$Archive->setExtractFiles(array($objects_state_file_path));
			$Archive->setTarPath($COMMON_VARS['tar_dir']);
			$Archive->extractArchive();
			if(empty($Archive->errors)){
				$objects_state_file_path = $ROOT_PATH.'/'.$objects_state_file_path;
				include($objects_state_file_path);
				if(isset($objects_state) && is_array($objects_state)) $backup->objects_state = $objects_state;
				else $backup->_error = 'Objects\' backup state temp file has wrong structure.';
			}
			else $backup->_error = 'Can\'t extract objects\' state temp file. <br>'.$Archive->errors[0];
			if(file_exists($temp_dir_path)) mysystem('rm -rf '.$temp_dir_path);
		}
		foreach($backup->action->data as $key => $value){
			$date_actioned = explode('.', $value->date_actioned);
			$backup->action->data[$key]->date_actioned = $date_actioned[0];
			$backup->action->data[$key]->username = $this->getUsername(array('id' => $value->userid, 'table' => ($value->type == 4 ? 'publisher_user' : 'member'),));
			$host = '';
			if($value->type == 3){
				$selected = $this->DB->SelectAny('SELECT name FROM preset WHERE id = '.$value->host.' LIMIT 1');
				if(!empty($selected)) $host = $selected[0]['name'];
			}
			if($value->type == 4){
				$selected = $this->DB->SelectAny('SELECT host FROM publisher WHERE id = '.$value->host.' LIMIT 1');
				if(!empty($selected)) $host = $selected[0]['host'];
			}
			$backup->action->data[$key]->hostpath = $host;
		}
		return $backup;
	}

	function saveBackup($request = array()){
		$backup = $this->createBackup();
		$this->parseRequest($request, $backup);
		$this->DB->processObject($backup);
		if($request['action_type'] == 'Backup') $this->setLogEvent(2, 3, 5, 'Make site Backup "'.$backup->name.'" ['.$backup->id.'] into the file "'.$backup->filename.'"', $backup->id);
		$this->DB->commit();
		return $backup;
	}

	function deleteBackup($request = array()){
		$backup = $this->createBackup();
		$this->parseRequest($request, $backup);
		$this->DB->begin();
		$this->DB->initObject($backup);
		$this->setLogEvent(2, 3, 13, 'Delete site backup "'.$backup->name.'" ['.$backup->id.'] and file "'.$backup->filename.'"', $backup->id);
		$this->DB->processObject($backup, 'delete', array(), array(), TRUE);
		$this->DB->commit();
		return $backup;
	}

	function selectPresets($request = array()){
		GLOBAL $MODEL_PATH;
		include_once($MODEL_PATH.'\Modules\Publish\PublishHandler.class.inc');
		$Handler = new PublishHandler();
		return $Handler->selectPreSetGroup(array());
	}

	function getUsername($request = array()){
		if (empty($request['id']) || !is_numeric($request['id'])) return NULL;
		$selected = $this->DB->SelectAny('SELECT username FROM '.(empty($request['table']) ? 'member' : $request['table']).' WHERE id = '.$request['id'].' LIMIT 1');
		if (empty($selected)) return '[unknown]';
		return $selected[0]['username'];
	}

	function getHostPath($request = array()){
		if (empty($request['host']) || !is_numeric($request['host'])) return NULL;
		$selected = $this->DB->SelectAny('SELECT '.(isset($request['incoming']) && $request['incoming'] ? 'host' : 'name').' AS hostpath FROM '.(isset($request['incoming']) && $request['incoming'] ? 'publisher' : 'preset').' WHERE id = '.$request['host'].' LIMIT 1');
		return empty($selected) ? '[unknown]' : $selected[0]['hostpath'];
	}

	function selectReportTypes($request = array()){
		$selected = $this->DB->SelectAny('SELECT number, name FROM reporttype');
		$types = array();
		foreach($selected as $value)
			$types[$value['number']] = $value['name'];
		return $types;
	}

	function selectReportReceivers($request = array()){
		$selected = $this->DB->SelectAny('SELECT id, email FROM reportreceiver');
		$result = array();
		foreach($selected as $key => $value)
			$result[$value['id']] = $value['email'];
		return $result;
	}

	function selectEngineSnapshot($request = array()){
		GLOBAL $ROOT_PATH, $TOOLS_PATH, $COMMON_VARS;
		include_once($TOOLS_PATH.'\File.functions.inc');
		include ($TOOLS_PATH.'\EngineSnapshot.inc');
		$result = array();
		$count = count($EngineSnapshot);
		for($i = 0; $i < $count; $i++){
			$path = $EngineSnapshot[$i];
			$pathtype = 1;
			$result[$i] = array('path' => $path, 'writable' => NULL, 'perm' => array('u' => array(NULL, NULL, NULL, NULL), 'g' => array(NULL, NULL, NULL, NULL), 'o' => array(NULL, NULL, NULL, NULL),), 'type' => NULL, 'size' => NULL, 'modified' => NULL, 'hash' => NULL, 'pathtype' => 1);
			if(($pos = strpos($EngineSnapshot[$i], '/*')) == (strlen($EngineSnapshot[$i]) - 2)) {
				$EngineSnapshot[$i] = substr($EngineSnapshot[$i], 0, $pos);
				$pathtype = 3;
			}
			if(!file_exists($ROOT_PATH.'/'.$EngineSnapshot[$i])){
				$result[$i]['_error'] = 'Doesn\'t exist.';
				$result[$i]['pathtype'] = $pathtype;
				continue;
			}
			if(is_dir($ROOT_PATH.'/'.$EngineSnapshot[$i])){
				$result[$i] = getFileDirInfo($ROOT_PATH.'/'.$EngineSnapshot[$i], false, true, false, false, true, false);
				if($pathtype != 3) $pathtype = 2;
			}
			else $result[$i] = getFileDirInfo($ROOT_PATH.'/'.$EngineSnapshot[$i], false, true, false, true, true, true);
			$result[$i]['path'] = $path;
			$result[$i]['pathtype'] = $pathtype;
			$result[$i]['special_rights'] = array();
			$result[$i]['_error'] = '';
			if(array_key_exists($EngineSnapshot[$i], $COMMON_VARS['special_rights_engine_path'])){
				$perm_link = &$COMMON_VARS['special_rights_engine_path'][$EngineSnapshot[$i]];
				$result[$i]['special_rights'] = $perm_link;
			}
			else{
				if(!is_writable($EngineSnapshot[$i])) $result[$i]['_error'] = 'Not writable. ';
				$perm_link = &$COMMON_VARS['default_rights_engine'];
			}
			if($perm_link['u'][0] != '*' && $result[$i]['perm']['u'][0] != $perm_link['u'][0]) $result[$i]['_error'] = 'Wrong owner. ';
			if($perm_link['g'][0] != '*' && $result[$i]['perm']['g'][0] != $perm_link['g'][0]) $result[$i]['_error'] .= 'Wrong group. ';
			if($perm_link['u'][1] != '*' && $result[$i]['perm']['u'][1] != $perm_link['u'][1]) $result[$i]['_error'] .= 'Wrong owner read permission. ';
			if($perm_link['u'][2] != '*' && $result[$i]['perm']['u'][2] != $perm_link['u'][2]) $result[$i]['_error'] .= 'Wrong owner write permission. ';
			if($perm_link['u'][3] != '*' && $result[$i]['perm']['u'][3] != $perm_link['u'][3]) $result[$i]['_error'] .= 'Wrong owner execute permission. ';
			if($perm_link['g'][1] != '*' && $result[$i]['perm']['g'][1] != $perm_link['g'][1]) $result[$i]['_error'] .= 'Wrong group read permission. ';
			if($perm_link['g'][2] != '*' && $result[$i]['perm']['g'][2] != $perm_link['g'][2]) $result[$i]['_error'] .= 'Wrong group write permission. ';
			if($perm_link['g'][3] != '*' && $result[$i]['perm']['g'][3] != $perm_link['g'][3]) $result[$i]['_error'] .= 'Wrong group execute permission. ';
			if($perm_link['o'][1] != '*' && $result[$i]['perm']['o'][1] != $perm_link['o'][1]) $result[$i]['_error'] .= 'Wrong other read permission. ';
			if($perm_link['o'][2] != '*' && $result[$i]['perm']['o'][2] != $perm_link['o'][2]) $result[$i]['_error'] .= 'Wrong other write permission. ';
			if($perm_link['o'][3] != '*' && $result[$i]['perm']['o'][3] != $perm_link['o'][3]) $result[$i]['_error'] .= 'Wrong other execute permission. ';
		}
		return $result;
	}

	function includeFileDirToSnapshot($request = array()){
		GLOBAL $TOOLS_PATH;
		include ($TOOLS_PATH.'\EngineSnapshot.inc');
		$request = $this->parsePathes($request);
		foreach($request as $value)
			if(!in_array($value, $EngineSnapshot)) $EngineSnapshot[] = $value;
		sort($EngineSnapshot);
		$this->setLogEvent(2, 16, 11, 'Add files/dirs: "'.implode('", "', $request).'" to the Engine Snapshot');
		$this->DB->commit();
		return $this->saveEngineSnapshot($EngineSnapshot);
	}

	function excludeFileDirFromSnapshot($request = array()){
		GLOBAL $TOOLS_PATH;
		include ($TOOLS_PATH.'\EngineSnapshot.inc');
		$request = $this->parsePathes($request);
		foreach($request as $value)
			if(($key = array_search($value, $EngineSnapshot)) !== false) unset($EngineSnapshot[$key]);
		sort($EngineSnapshot);if(empty($request[0])) unset($request[0]);
		$this->setLogEvent(2, 16, 13, 'Delete files/dirs: "'.implode('", "', $request).'" from the Engine Snapshot');
		$this->DB->commit();
		return $this->saveEngineSnapshot($EngineSnapshot);
	}

	function parsePathes($request = array()){
		$count = count($request);
		for($i = 0; $i < $count; $i++){
			$request[$i] = str_replace('\\', '/', $request[$i]);
			$len = strlen($request[$i]);
			if(substr($request[$i], 0, 1) == '/') $request[$i] = substr($request[$i], 1, $len - 1);
			$len = strlen($request[$i]);
			if(substr($request[$i], $len - 1, 1) == '/') $request[$i] = substr($request[$i], 0, $len - 1);
			$request[$i] = preg_replace("/[\/]{2,}/", '/', $request[$i]);
		}
		return $request;
	}

	function saveEngineSnapshot($request = array()){
		GLOBAL $TOOLS_PATH;
		sort($request);
		$file = fopen($TOOLS_PATH.'/EngineSnapshot.inc', "w");
		$string = '<?php'."\r\n".'$EngineSnapshot = '.var_export($request, true).";\r\n".'?>';
		fwrite($file, $string);
		fclose($file);
		include ($TOOLS_PATH.'\EngineSnapshot.inc');
		return $EngineSnapshot;
	}

	function getEngineDBRules($request = array()){
		GLOBAL $TOOLS_PATH;
		include ($TOOLS_PATH.'\EngineDBRules.inc');
		return $EngineDBRules;
	}

	function selectEngineDBRules($request = array()){
		GLOBAL $TOOLS_PATH;
		$result = array();
		include ($TOOLS_PATH.'\EngineDBRules.inc');
		if(empty($request)) $result = $EngineDBRules;
		else{
			$count = count($EngineDBRules);
			foreach($request as $table){
				for ($i = 0; $i < $count; $i++){
					if($EngineDBRules[$i]['name'] == $table){
						$result[$i] = $EngineDBRules[$i];
						break;
					}
				}
				$result = array_values($result);
			}
		}
		$count = count($result);
		for ($i = 0; $i < $count; $i++){
			$result[$i]['_error'] = '';
			$selected = $this->DB->SelectAny('SELECT relid FROM pg_statio_all_tables WHERE schemaname=\'public\' AND relname = \''.$result[$i]['name'].'\' LIMIT 1');
			if(empty($selected)){
				$result[$i]['_error'] = 'Does not exist';
				continue;
			}
			$constraints = $this->DB->SelectAny('SELECT conname AS name, contype AS type  FROM pg_constraint WHERE (contype = \'p\' OR contype = \'u\') AND conrelid = '.$selected[0]['relid']);
			$constraints_c = count($constraints);
			for($j = 0; $j < $constraints_c; $j++){
				$field_oid = $this->DB->SelectAny('SELECT indexrelid FROM pg_stat_all_indexes WHERE indexrelname = \''.$constraints[$j]['name'].'\'');
				$field = $this->DB->SelectAny('SELECT attname as field FROM pg_attribute WHERE attrelid = '.$field_oid[0]['indexrelid'].' LIMIT 1');
				$constraints[$j]['field'] = $field[0]['field'];
			}
			$query = 'SELECT attnum AS num, attname AS name, typname AS type, atttypmod-4 AS length, attnotnull AS notnull, atthasdef AS default, pg_attrdef.adsrc AS defaultvalue FROM pg_attribute INNER JOIN pg_class ON pg_attribute.attrelid = pg_class.oid INNER JOIN pg_type ON pg_attribute.atttypid = pg_type.oid LEFT OUTER JOIN pg_attrdef ON pg_attrdef.adrelid = pg_class.oid AND pg_attrdef.adnum = pg_attribute.attnum WHERE attnum > 0 AND attisdropped <> \'t\' AND pg_class.oid = '.$selected[0]['relid'];
			$selected = $this->DB->SelectAny($query);
			$selected_c = count($selected);
			for ($j = 0; $j < $selected_c; $j++){
				$selected[$j]['constraint'] = '';
				for($k = 0; $k < $constraints_c; $k++)
					if($selected[$j]['name'] == $constraints[$k]['field']) $selected[$j]['constraint'] = $constraints[$k]['type'];
			}
			$c = count($result[$i]['structure']);
			for($j = 0; $j < $c; $j++){
				$result[$i]['structure'][$j]['_error'] = '';
				$result[$i]['structure'][$j]['fixable'] = true;
				$result[$i]['structure'][$j]['db'] = $result[$i]['structure'][$j];
				$result[$i]['structure'][$j]['length'] = empty($result[$i]['structure'][$j]['length']) ? -5 : $result[$i]['structure'][$j]['length'];
				$flag = false;
				for($k = 0; $k < $selected_c; $k++){
					if($selected[$k]['name'] != $result[$i]['structure'][$j]['name']) continue;
					$flag = true;
					if($selected[$k]['default'] != $result[$i]['structure'][$j]['default'] || $selected[$k]['defaultvalue'] != $result[$i]['structure'][$j]['defaultvalue']) $result[$i]['structure'][$j]['_error'] .= 'Wrong default.<br>Rule: <i>'.$result[$i]['structure'][$j]['defaultvalue'].'</i><br>DB: <i>'.$selected[$k]['defaultvalue'].'</i><br>';
					if($selected[$k]['notnull'] != $result[$i]['structure'][$j]['notnull']) $result[$i]['structure'][$j]['_error'] .= 'Wrong not null.<br>Rule: <i>'.$result[$i]['structure'][$j]['notnull'].'</i><br>DB: <i>'.$selected[$k]['notnull'].'</i><br>';
					if($selected[$k]['constraint'] != $result[$i]['structure'][$j]['constraint']) $result[$i]['structure'][$j]['_error'] .= 'Wrong constraint.<br>Rule: <i>'.$result[$i]['structure'][$j]['constraint'].'</i><br>DB: <i>'.$selected[$k]['constraint'].'</i><br>';
					if($selected[$k]['length'] != $result[$i]['structure'][$j]['length']){
						$result[$i]['structure'][$j]['_error'] .= 'Wrong length.<br>Rule: <i>'.$result[$i]['structure'][$j]['length'].'</i><br>DB: <i>'.$selected[$k]['length'].'</i><br>';
						$result[$i]['structure'][$j]['fixable'] = false;
					}
					if($selected[$k]['type'] != $result[$i]['structure'][$j]['type']){
						$result[$i]['structure'][$j]['_error'] .= 'Wrong type.<br>Rule: <i>'.$result[$i]['structure'][$j]['type'].'</i><br>DB: <i>'.$selected[$k]['type'].'</i><br>';
						$result[$i]['structure'][$j]['fixable'] = false;
					}
				}
				if($result[$i]['structure'][$j]['length'] == -5) $result[$i]['structure'][$j]['length'] = '';
				if(!$flag) $result[$i]['structure'][$j]['_error'] .= 'Does not exist<br>';
			}
			$query = 'SELECT indexname AS name, indexdef AS query FROM pg_indexes WHERE schemaname = \'public\' AND tablename = \''.$result[$i]['name'].'\' AND indexname NOT IN (SELECT conname FROM pg_constraint)';
			$indexes = $this->DB->SelectAny($query);
			$indexes_c = count($indexes);
			$c = count ($result[$i]['index']);
			for($j = 0; $j < $c; $j++){
				$result[$i]['index'][$j]['_error'] = '';
				$flag = true;
				for($k = 0; $k < $indexes_c; $k++){
					if($indexes[$k]['name'] != $result[$i]['index'][$j]['name']) continue;
					$flag = false;
					$occ = strstr($indexes[$k]['query'], 'UNIQUE');
					if((empty($result[$i]['index'][$j]['unique']) && $occ !== false) || (!empty($result[$i]['index'][$j]['unique']) && $occ === false)) $result[$i]['index'][$j]['_error'] .= 'Wrong unique.<br>Rule: <i>'.$result[$i]['index'][$j]['unique'].'</i><br>DB: <i>'.($occ === false ? '' : 'u').'</i><br>';
					preg_match("/\([[:alnum:] ,_\"]+\)/i", $indexes[$k]['query'], $match);
					$fields = explode(',', str_replace(array('(', ')', ' ', '"'), '', $match[0]));
					if(count($fields) != count($result[$i]['index'][$j]['fields']) || array_diff($result[$i]['index'][$j]['fields'], $fields)) $result[$i]['index'][$j]['_error'] .= 'Wrong fields.<br>Rule: <i>'.implode(', ', $result[$i]['index'][$j]['fields']).'</i><br>DB: <i>'.implode(', ', $fields).'</i><br>';
				}
				if($flag) $result[$i]['index'][$j]['_error'] = 'Does not exist.';
			}
			foreach($result[$i]['data'] as $ind => $val){
				$result[$i]['data'][$ind]['_error'] = '';
				$flag = true;
				$query = 'SELECT id FROM "'.$result[$i]['name'].'" WHERE ';
				foreach($val as $k => $v){
					$field_flag = false;
					for ($j = 0; $j < $selected_c; $j++){
						if($k != $selected[$j]['name']) continue;
						$field_flag = true;
						$query .= '"'.$k.'" = ';
						switch($selected[$j]['type']){
							case 'varchar': case 'bpchar': case 'text': case 'date': case 'timestamp': case 'bool': $query .= '\''.$v.'\' AND '; break;
							case 'int2': case 'int4': case 'int8': $query .= $v.' AND '; break;
						};
						break;
					}
					if(!$field_flag) $flag = false;
				}
				if($flag) {
					$query = substr($query, 0, strlen($query) - 4).' LIMIT 1';
					$record = $this->DB->SelectAny($query);
					if(empty($record)) $result[$i]['data'][$ind]['_error'] = 'Does not exist';
				}
				else $result[$i]['data'][$ind]['_error'] = 'Does not exist';
			}
		}
		return $result;
	}

	function selectDBExcess($request = array()){
		$result = array('table' => array(), 'structure' => array(), 'index' => array(),);
		GLOBAL $TOOLS_PATH;
		include ($TOOLS_PATH.'\EngineDBRules.inc');
		$dbtables = array();
		$selected = $this->DB->SelectAny('SELECT relname AS name, relid AS oid FROM pg_statio_all_tables WHERE schemaname = \'public\'');
		$count = count($selected);
		for ($i = 0; $i < $count; $i++) $dbtables[$selected[$i]['oid']] = $selected[$i]['name'];
		$rtables = array();
		$count = count($EngineDBRules);
		for($i = 0; $i < $count; $i++){
			$rtables[] = $EngineDBRules[$i]['name'];
			if(($oid = array_search($EngineDBRules[$i]['name'], $dbtables)) === false) continue;
			$query = 'SELECT attname AS name FROM pg_attribute INNER JOIN pg_class ON pg_attribute.attrelid = pg_class.oid WHERE attnum > 0 AND attisdropped <> \'t\' AND pg_class.oid = '.$oid;
			$selected = $this->DB->SelectAny($query);
			$dbfields = array();
			foreach($selected as $val) $dbfields[] = $val['name'];
			$rfields = array();
			foreach($EngineDBRules[$i]['structure'] as $val) $rfields[] = $val['name'];
			$diff = array_diff($dbfields, $rfields);
			foreach($diff as $val) $result['structure'][] = $EngineDBRules[$i]['name'].'/'.$val;
			$query = 'SELECT indexname AS name FROM pg_indexes WHERE schemaname = \'public\' AND tablename = \''.$EngineDBRules[$i]['name'].'\' AND indexname NOT IN (SELECT conname FROM pg_constraint)';
			$selected = $this->DB->SelectAny($query);
			$dbindexes = array();
			foreach($selected as $val) $dbindexes[] = $val['name'];
			$rindexes = array();
			foreach($EngineDBRules[$i]['index'] as $val) $rindexes[] = $val['name'];
			$diff = array_diff($dbindexes, $rindexes);
			foreach($diff as $val) $result['index'][] = $EngineDBRules[$i]['name'].'/'.$val;
		}
		$result['table'] = array_diff($dbtables, $rtables);
		return $result;
	}

	function selectSequences($request = array()) {
		if(empty($request) || !is_array($request)) $EngineDBRules = $this->selectEngineDBRules();
		else $EngineDBRules = $request;
		$result = array();
		$count  = count($EngineDBRules);
		for($i = 0; $i < $count; $i++){
			if(!empty($EngineDBRules[$i]['_error'])) continue;
			$query = 'SELECT
				pg_statio_all_tables.relname AS table,
				pg_attrdef.adsrc AS default,
				pg_attribute.attname AS field
			FROM pg_attrdef, pg_statio_all_tables, pg_attribute
			WHERE pg_statio_all_tables.relname = \''.$EngineDBRules[$i]['name'].'\'
				AND pg_attrdef.adrelid = pg_statio_all_tables.relid
				AND pg_statio_all_tables.schemaname = \'public\'
				AND pg_attrdef.adsrc LIKE \'nextval(%)\'
				AND pg_attribute.attrelid = pg_statio_all_tables.relid
				AND pg_attribute.attnum = pg_attrdef.adnum';
			$selected = $this->DB->SelectAny($query);
			$selected_c = count($selected);
			for($j = 0; $j < $selected_c; $j++){
				$seq_name = explode("'", $selected[$j]['default']);
				$selected[$j]['name'] = $seq_name[1];
				$seq_value = $this->DB->SelectAny('SELECT last_value FROM '.$selected[$j]['name']);
				$selected[$j]['seq_value'] = $seq_value[0]['last_value'];
				$field_max = $this->DB->SelectAny('SELECT max('.$selected[$j]['field'].') AS max FROM "'.$selected[$j]['table'].'"');
				$selected[$j]['field_max'] = $field_max[0]['max'];
				if($selected[$j]['seq_value'] < $selected[$j]['field_max']) $selected[$j]['_error'] = 'Values mismatch';
				else $selected[$j]['_error'] = '';
			}
			$result = array_merge($result, $selected);
		}
		return $result;
	}

	function selectDBObsoleteData($request = array()) {
		GLOBAL $COMMON_VARS;
		$result = array();
		foreach($COMMON_VARS['dbtable_relations'] as $key => $value){
			$count = count($value);
			for($i = 0; $i < $count; $i++){
				$selected = $this->selectDBNoOwnerRecords($key, $value[$i], $request['detailed']);
				$this->addToDBObsoleteDataResult($result, $value[$i], $key, $selected, ($request['detailed'] ? '' : 'some ').$value[$i].' ownerid has no relation with '.$key.' id');
			}
		}
		if($request['detailed']){
			foreach($COMMON_VARS['dbtable_hidden_relations'] as $key => $value){
				$count = count($value);
				for ($i = 0; $i < $count; $i++){
					$query = 'SELECT id FROM "'.$key.'" WHERE '.(empty($value[$i]['condition']) ? '' : $value[$i]['condition'].' AND ').$value[$i]['field'].' NOT IN (SELECT '.$value[$i]['conform_to_field'].' FROM "'.$value[$i]['conform_to_table'].'")';
					$selected = $this->DB->SelectAny($query);
					$this->addToDBObsoleteDataResult($result, $key, '', $selected, $key.' '.$value[$i]['field'].' do not conform to '.$value[$i]['conform_to_table'].' '.$value[$i]['conform_to_field'], 6);
				}
			}
		}
		return $result;
	}

	function addToDBObsoleteDataResult(&$result, $table, $ownertable, $ids, $message = '', $type = 5){
		if(empty($ids)) return;
		$index = count($result);
		$result[$index] = array(
			'table' => $table,
			'ownertable' => $ownertable,
			'id' => array(),
			'message' => $message,
			'type' => $type,
		);
		$count = count($ids);
		for ($i = 0; $i < $count; $i++) $result[$index]['id'][] = $ids[$i]['id'];
	}

	function selectDBNoOwnerRecords($ownertable, $table, $detailed){
		$selected = $this->DB->SelectAny('SELECT id FROM "'.$table.'" WHERE ownerid NOT IN (SELECT id FROM "'.$ownertable.'")'.($detailed ? '' : 'LIMIT 1'));
		if($detailed) return $selected;
		else return empty($selected) ? false : true;
	}

	function selectRegistryLack($request = array()){
		GLOBAL $REGISTRY;
		$result = array('pagefullpath-layoutid' => array(), 'pagefullpath-describeview' => array(),);
		$selected = $this->DB->SelectAny('SELECT id, path, layout, parent, is_describe, default_page FROM module WHERE type IN (1,3,6,8)');
		$page = array();
		$count = count($selected);
		for ($i = 0; $i < $count; $i++) $page[$selected[$i]['id']] = $selected[$i];
		unset($page[1]);
		$page_ids = array_keys($page);
		$count = count($page_ids);
		for ($i = 0; $i < $count; $i++){
			$full_path = '/'.$page[$page_ids[$i]]['path'];
			$parent = $page[$page_ids[$i]]['parent'];
			while($parent){
				$full_path = '/'.$page[$parent]['path'].$full_path;
				if(!isset($page[$parent]['parent'])) break;
				$parent = $page[$parent]['parent'];
			}
			if(empty($page[$page_ids[$i]]['is_describe'])){
				if(!empty($page[$page_ids[$i]]['default_page'])){
					$DescribeView = 'DescribeView:object?id='.$page[$page_ids[$i]]['default_page'].'?dir='.$page_ids[$i];
					if(!array_key_exists($full_path, $REGISTRY['VirtualSlotTarget']['main'])) $result['pagefullpath-describeview'][] = array('id' => $page_ids[$i], 'page full path' => $full_path, 'describe view' => $DescribeView, 'describe view (reg)' => '', 'message' => 'Not in Registry',);
					else if($REGISTRY['VirtualSlotTarget']['main'][$full_path] != $DescribeView) $result['pagefullpath-describeview'][] = array('id' => $page_ids[$i], 'page full path' => $full_path, 'describe view' => $DescribeView, 'describe view (reg)' => $REGISTRY['VirtualSlotTarget']['main'][$full_path], 'message' => 'Wrong describe view value in Registry',);
				}
			}
			else{
				if(!array_key_exists($full_path, $REGISTRY['VirtualSlotTarget'][''])) $result['pagefullpath-layoutid'][] = array('id' => $page_ids[$i], 'page full path' => $full_path, 'layout id' => $page[$page_ids[$i]]['layout'], 'layout id (reg)' => '', 'message' => 'Not in Registry',);
				else if($REGISTRY['VirtualSlotTarget'][''][$full_path] != $page[$page_ids[$i]]['layout']) $result['pagefullpath-layoutid'][] = array('id' => $page_ids[$i], 'page full path' => $full_path, 'layout id' => $page[$page_ids[$i]]['layout'], 'layout id (reg)' => $REGISTRY['VirtualSlotTarget'][''][$full_path], 'message' => 'Wrong layout id in Registry',);
				$DescribeView = 'DescribeView:object?id='.$page_ids[$i];
				if(!array_key_exists($full_path, $REGISTRY['VirtualSlotTarget']['main'])) $result['pagefullpath-describeview'][] = array('id' => $page_ids[$i], 'page full path' => $full_path, 'describe view' => $DescribeView, 'describe view (reg)' => '', 'message' => 'Not in Registry',);
				else if($REGISTRY['VirtualSlotTarget']['main'][$full_path] != $DescribeView) $result['pagefullpath-describeview'][] = array('id' => $page_ids[$i], 'page full path' => $full_path, 'describe view' => $DescribeView, 'describe view (reg)' => $REGISTRY['VirtualSlotTarget']['main'][$full_path], 'message' => 'Wrong describe view value in Registry',);
			}
		}
		return $result;
	}

	function selectRegistryExcess($request = array()){
		GLOBAL $REGISTRY;
		$result = array('pagefullpath-layoutid' => array(), 'pagefullpath-describeview' => array(),);
		$keys = $REGISTRY['VirtualSlotTarget'][''];
		unset($keys[''], $keys['/'], $keys['?']);
		$keys = array_keys($keys);
		$count = count($keys);
		for ($i = 0; $i < $count; $i++){
			if(strstr($REGISTRY['VirtualSlotTarget'][''][$keys[$i]], ':object') !== false) continue;
			$array = explode('/', $keys[$i]);
			$selected = $this->DB->SelectAny('SELECT id, parent, path FROM module WHERE path = \''.$array[(count($array) - 1)].'\'');
			$paths = array();
			$c = count($selected);
			for ($j = 0; $j < $c; $j++){
				$paths[$j] = '/'.$selected[$j]['path'];
				$parent = $selected[$j]['parent'];
				while($parent){
					$sel = $this->DB->SelectAny('SELECT path, parent FROM module WHERE id = '.$parent.' LIMIT 1');
					if(empty($sel)) break;
					$paths[$j] = '/'.$sel[0]['path'].$paths[$j];
					$parent = $sel[0]['parent'];
				}
			}
			if(!in_array($keys[$i], $paths)) $result['pagefullpath-layoutid'][] = array('key' => $keys[$i], 'page full path (reg)' => $keys[$i], 'message' => 'Page with such full path does\'t exist');
		}
		$keys = $REGISTRY['VirtualSlotTarget']['main'];
		unset($keys[''], $keys['/'], $keys['?']);
		$keys = array_keys($keys);
		$count = count($keys);
		for ($i = 0; $i < $count; $i++){
			$array = explode('=', $REGISTRY['VirtualSlotTarget']['main'][$keys[$i]]);
			if(isset($array[2])){
				$dir = intval($array[2]);
				$selected = $this->DB->SelectAny('SELECT id FROM module WHERE id = '.$dir.' LIMIT 1');
				if(empty($selected)) {
					$result['pagefullpath-describeview'][] = array('key' => $keys[$i], 'describe view dir (reg)' => $dir, 'message' => 'Page with such id does\'t exist');
					continue;
				}
			}
			$id = intval($array[1]);
			$selected = $this->DB->SelectAny('SELECT id FROM module WHERE id = '.$id.' LIMIT 1');
			if(empty($selected)) $result['pagefullpath-describeview'][] = array('key' => $keys[$i], 'describe view (reg)' => $id, 'message' => 'Page with such id does\'t exist');
		}
		return $result;
	}

	function fixDatabase($request = array()){
		GLOBAL $TOOLS_PATH;
		$result = array();
		include ($TOOLS_PATH.'\EngineDBRules.inc');
		error_reporting(0);
		switch($request['action']){
			case 'Excess':
				$table_res = array_merge($this->dropDBTables($EngineDBRules, $request['table']['drop']), $this->addDBTablesToRules($EngineDBRules, $request['table']['add']));
				$index_res = array_merge($this->dropDBIndexes($EngineDBRules, $request['index']['drop']), $this->addDBIndexesToRules($EngineDBRules, $request['index']['add']));
				$structure_res = array_merge($this->dropDBTablesFields($EngineDBRules, $request['structure']['drop']), $this->addDBTablesFieldsToRules($EngineDBRules, $request['structure']['add']));
				$result = array_merge($table_res, $index_res, $structure_res);
				break;
			case 'Lack':
				$structure_res = array_merge($this->updateDBTablesStructure($EngineDBRules, $request['structure']['updatedb']), $this->updateTablesStructureDBRules($EngineDBRules, $request['structure']['updaterule']));
				$table_res = array_merge($this->createDBTables($EngineDBRules, $request['table']['updatedb']), $this->deleteTablesDBRules($EngineDBRules, $request['table']['updaterule']));
				$data_res = array_merge($this->updateDBData($EngineDBRules, $request['data']['updatedb']), $this->deleteDataDBRules($EngineDBRules, $request['data']['updaterule']));
				$index_res = array_merge($this->updateDBIndexes($EngineDBRules, $request['index']['updatedb']), $this->deleteIndexesDBRules($EngineDBRules, $request['index']['updaterule']));
				$seq_res = $this->updateDBSequences($request['sequence']['updatedb']);
				$result = array_merge($structure_res, $table_res, $data_res, $index_res, $seq_res);
				break;
		}
		return $result;
	}

	function cleanDatabase($request = array()){
		$result = array();
		error_reporting(0);
		$index = 0;
		foreach($request as $table => $ownertables){
			$count = count($ownertables);
			for ($i = 0; $i < $count; $i++){
				$query = 'DELETE FROM "'.$table.'" WHERE ownerid NOT IN (SELECT id FROM "'.$ownertables[$i].'")';
				$result[$index] = array('message' => 'Deleting from table "<b>'.$table.'</b>" obsolete records', 'query' => $query, 'type' => 0, '_error' => '');
				$this->setLogEvent(2, 16, 13, 'Delete from table "'.$table.'" obsolete records');
				if($this->DB->query($query) && !$this->DB->Errno){
					$this->DB->Commit();
					$result[$index]['type'] = 3;
				}
				else{
					$result[$index]['_error'] = $this->DB->Error;
					$this->DB->Rollback();
				}
				$index++;
			}
		}
		return $result;
	}

	function detailedCleanDatabase($request = array()){
		$result = array();
		error_reporting(0);
		$index = 0;
		foreach($request as $table => $id){
			$count = count($id);
			for ($i = 0; $i < $count; $i++){
				$query = 'DELETE FROM "'.$table.'" WHERE id = '.$id[$i];
				$result[$index] = array('message' => 'Deleting from table "<b>'.$table.'</b>" record ID = <b>'.$id[$i].'</b>', 'query' => $query, 'type' => 0, '_error' => '');
				$this->setLogEvent(2, 16, 13, 'Delete from table "'.$table.'" obsolete record ID='.$id[$i]);
				if($this->DB->query($query) && !$this->DB->Errno){
					$this->DB->Commit();
					$result[$index]['type'] = 3;
				}
				else{
					$result[$index]['_error'] = $this->DB->Error;
					$this->DB->Rollback();
				}
				$index++;
			}
		}
		return $result;
	}

	function fixRegistryLack($request = array()){
		GLOBAL $REGISTRY;
		$result = array();
		$index = 0;
		if(!isset($request['pagefullpath-layoutid'])) $request['pagefullpath-layoutid'] = array();
		if(!isset($request['pagefullpath-describeview'])) $request['pagefullpath-describeview'] = array();
		$count = count($request['pagefullpath-layoutid']);
		for ($i = 0; $i < $count; $i++){
			$index = count($result);
			$result[$index] = array('message' => 'Add/Update pair "page full path - layout id" for page ID: '.$request['pagefullpath-layoutid'][$i], 'error' => '', 'type' => 0);
			$selected = $this->DB->SelectAny('SELECT is_describe, path, layout, parent FROM module WHERE id = '.$request['pagefullpath-layoutid'][$i].' LIMIT 1');
			if(empty($selected)) $result[$index]['error'] = 'Page doesn\'t exist anymore';
			else if(empty($selected[0]['is_describe'])) $result[$index]['error'] = 'Page is not described anymore';
			else {
				$layout = $selected[0]['layout'];
				if(empty($layout)){
					$result[$index]['error'] = 'Layout does\'t exist anymore';
					continue;
				}
				$full_path = '/'.$selected[0]['path'];
				$parent = $selected[0]['parent'];
				while($parent){
					$sel = $this->DB->SelectAny('SELECT path, parent FROM module WHERE id = '.$parent.' LIMIT 1');
					if(empty($sel)) break;
					$full_path = '/'.$sel[0]['path'].$full_path;
					$parent = $sel[0]['parent'];
				}
				$this->setLogEvent(2, 16, 12, $result[$index]['message']);
				$REGISTRY['VirtualSlotTarget'][''][$full_path] = $layout;
				$this->Server->SaveRegistry();
				if(isset($REGISTRY['VirtualSlotTarget'][''][$full_path]) && $REGISTRY['VirtualSlotTarget'][''][$full_path] == $layout){
					$result[$index]['type'] = 3;
					$this->DB->Commit();
				}
				else $result[$index]['error'] = 'Unknown error. Can not add/update registry pair.';
			}
		}
		$count = count($request['pagefullpath-describeview']);
		for ($i = 0; $i < $count; $i++){
			$index = count($result);
			$result[$index] = array('message' => 'Add/Update pair "page full path - describe view" for page ID: '.$request['pagefullpath-describeview'][$i], 'error' => '', 'type' => 0);
			$selected = $this->DB->SelectAny('SELECT is_describe, path, parent, default_page FROM module WHERE id = '.$request['pagefullpath-describeview'][$i].' LIMIT 1');
			if(empty($selected)) $result[$index]['error'] = 'Page doesn\'t exist anymore';
			else {
				$DescribeView = 'DescribeView:object?';
				if($selected[0]['is_describe']) $DescribeView .= 'id='.$request['pagefullpath-describeview'][$i];
				else {
					$sel = $this->DB->SelectAny('SELECT name FROM module WHERE id = '.$selected[0]['default_page']);
					if(empty($sel)){
						$result[$index]['error'] = 'Default Page doesn\'t exist anymore';
						continue;
					}
					$DescribeView .= 'id='.$selected[0]['default_page'].'?dir='.$request['pagefullpath-describeview'][$i];
				}
				$full_path = '/'.$selected[0]['path'];
				$parent = $selected[0]['parent'];
				while($parent){
					$sel = $this->DB->SelectAny('SELECT path, parent FROM module WHERE id = '.$parent.' LIMIT 1');
					if(empty($sel)) break;
					$full_path = '/'.$sel[0]['path'].$full_path;
					$parent = $sel[0]['parent'];
				}
				$this->setLogEvent(2, 16, 12, $result[$index]['message']);
				$REGISTRY['VirtualSlotTarget']['main'][$full_path] = $DescribeView;
				$this->Server->SaveRegistry();
				if(isset($REGISTRY['VirtualSlotTarget']['main'][$full_path]) && $REGISTRY['VirtualSlotTarget']['main'][$full_path] == $DescribeView){
					$result[$index]['type'] = 3;
					$this->DB->Commit();
				}
				else $result[$index]['error'] = 'Unknown error. Can not add/update registry pair.';
			}
		}
		return $result;
	}

	function fixRegistryExcess($request = array()){
		GLOBAL $REGISTRY;
		$result = array();
		$index = 0;
		if(!isset($request['pagefullpath-layoutid'])) $request['pagefullpath-layoutid'] = array();
		if(!isset($request['pagefullpath-describeview'])) $request['pagefullpath-describeview'] = array();
		$count = count($request['pagefullpath-layoutid']);
		for ($i = 0; $i < $count; $i++){
			$index = count($result);
			$result[$index] = array('message' => 'Delete registry pair "page full path - layout id" for page full path: "'.$request['pagefullpath-layoutid'][$i].'"', 'error' => '', 'type' => 0);
			$array = explode('/', $request['pagefullpath-layoutid'][$i]);
			$selected = $this->DB->SelectAny('SELECT id, parent, path FROM module WHERE path = \''.$array[(count($array) - 1)].'\'');
			$paths = array();
			$c = count($selected);
			for ($j = 0; $j < $c; $j++){
				$paths[$j] = '/'.$selected[$j]['path'];
				$parent = $selected[$j]['parent'];
				while($parent){
					$sel = $this->DB->SelectAny('SELECT path, parent FROM module WHERE id = '.$parent.' LIMIT 1');
					if(empty($sel)) break;
					$paths[$j] = '/'.$sel[0]['path'].$paths[$j];
					$parent = $sel[0]['parent'];
				}
			}
			if(in_array($request['pagefullpath-layoutid'][$i], $paths)) $result[$index]['error'] = 'Page with such full path exists';
			else{
				$this->setLogEvent(2, 16, 13, $result[$index]['message']);
				unset($REGISTRY['VirtualSlotTarget'][''][$request['pagefullpath-layoutid'][$i]]);
				$this->Server->SaveRegistry();
				if(isset($REGISTRY['VirtualSlotTarget'][''][$request['pagefullpath-layoutid'][$i]])) $result[$index]['error'] = 'Unknown error. Can not delete registry pair.';
				else{
					$result[$index]['type'] = 3;
					$this->DB->Commit();
				}
			}
		}
		$count = count($request['pagefullpath-describeview']);
		for ($i = 0; $i < $count; $i++){
			$index = count($result);
			$result[$index] = array('message' => 'Delete registry pair "page full path - describe view" for page full path: "'.$request['pagefullpath-describeview'][$i].'"', 'error' => '', 'type' => 0);
			if(!isset($REGISTRY['VirtualSlotTarget']['main'][$request['pagefullpath-describeview'][$i]])){
				$result[$index]['type'] = 3;
				$this->setLogEvent(2, 16, 13, $result[$index]['message']);
				$this->DB->Commit();
			}
			else{
				$array = explode('=', $REGISTRY['VirtualSlotTarget']['main'][$request['pagefullpath-describeview'][$i]]);
				$selected1 = array();
				if(isset($array[2])){
					$dir = intval($array[2]);
					$selected1 = $this->DB->SelectAny('SELECT id FROM module WHERE id = '.$dir.' LIMIT 1');
					/*if(!empty($selected)) {
						$result[$index]['error'] = 'Page with such id exists';
						continue;
					}*/
				}
				$id = intval($array[1]);
				$selected2 = $this->DB->SelectAny('SELECT id FROM module WHERE id = '.$id.' LIMIT 1');
				if(empty($selected1) || empty($selected2)){
					$this->setLogEvent(2, 16, 13, $result[$index]['message']);
					unset($REGISTRY['VirtualSlotTarget']['main'][$request['pagefullpath-describeview'][$i]]);
					$this->Server->SaveRegistry();
					if(isset($REGISTRY['VirtualSlotTarget']['main'][$request['pagefullpath-describeview'][$i]])) $result[$index]['error'] = 'Unknown error. Can not delete registry pair.';
					else{
						$result[$index]['type'] = 3;
						$this->DB->Commit();
					}
				}
				else $result[$index]['error'] = 'Page with such id exists';
			}
		}
		return $result;
	}

	function updateDBTablesStructure(&$DBRules, $request){
		GLOBAL $COMMON_VARS;
		$result = array();
		$i = 0;
		foreach($DBRules as $key => $value){
			foreach($request as $ind => $val){
				$array = explode('/', $val);
				$table = $array[0];
				$field = $array[1];
				if($value['name'] != $table) continue;
				foreach($value['structure'] as $k => $v){
					if($v['name'] != $field) continue;
					$query = 'SELECT relid FROM pg_statio_all_tables WHERE schemaname=\'public\' AND relname = \''.$value['name'].'\' LIMIT 1';
					$selected = $this->DB->SelectAny($query);
					if(empty($selected)){
						$result[$i] = array('message' => 'Creating table "<b>'.$value['name'].'</b>" field "<b>'.$v['name'].'</b>"', 'query' => $query, 'type' => 6, '_error' => 'Table "<b>'.$value['name'].'</b>" does not exist anymore');
						$i++;
						continue;
					}
					$constraints = $this->DB->SelectAny('SELECT conname AS name, contype AS type  FROM pg_constraint WHERE (contype = \'p\' OR contype = \'u\') AND conrelid = '.$selected[0]['relid']);
					foreach($constraints as $ind => $val){
						$field_oid = $this->DB->SelectAny('SELECT indexrelid FROM pg_stat_all_indexes WHERE indexrelname = \''.$val['name'].'\'');
						$field = $this->DB->SelectAny('SELECT attname as field FROM pg_attribute WHERE attrelid = '.$field_oid[0]['indexrelid'].' LIMIT 1');
						$constraints[$ind]['field'] = $field[0]['field'];
					}
					$query = 'SELECT attrelid as oid, attnum AS num, attname AS name, typname AS type, atttypmod-4 AS length, attnotnull AS notnull, atthasdef AS default, pg_attrdef.adsrc AS defaultvalue FROM pg_attribute INNER JOIN pg_class ON pg_attribute.attrelid = pg_class.oid INNER JOIN pg_type ON pg_attribute.atttypid = pg_type.oid LEFT OUTER JOIN pg_attrdef ON pg_attrdef.adrelid = pg_class.oid AND pg_attrdef.adnum = pg_attribute.attnum WHERE attnum > 0 AND attname = \''.$v['name'].'\' AND attisdropped <> \'t\' AND pg_class.oid = '.$selected[0]['relid'];
					$selected = $this->DB->SelectAny($query);
					$query = '';
					$seq_name = '';
					if(empty($selected)){
						if(preg_match("/^nextval\([[:alnum:]'\.:_]+\)/i", $v['defaultvalue'], $matches)){
							$array = explode("'", $matches[0]);
							$array = explode('.', $array[1]);
							$seq_name = empty($array[1]) ? $array[0] : $array[1];
							$seq = $this->DB->SelectAny('SELECT * FROM '.$seq_name);
							if(empty($seq)) $query .= 'CREATE SEQUENCE "'.$seq_name.'" MAXVALUE 2147483647;';
						}
						$query .= 'ALTER TABLE "'.$value['name'].'" ADD COLUMN "'.$v['name'].'" ';
						$query .= strtoupper($COMMON_VARS['dbfield_types'][$v['type']]);
						if(!empty($v['length']) && in_array($v['type'], $COMMON_VARS['sized_dbfield_types'])) $query .= '('.$v['length'].')';
						$query .= ($v['constraint'] == 'u' ? ' UNIQUE' : '').';';
						if($v['default'] == 't') $query .= 'ALTER TABLE "'.$value['name'].'" ALTER COLUMN "'.$v['name'].'" SET DEFAULT '.$v['defaultvalue'].';';
						if($v['notnull'] == 't') $query .= 'ALTER TABLE "'.$value['name'].'" ALTER COLUMN "'.$v['name'].'" SET NOT NULL;';
						if($v['constraint'] == 'p') $query .= 'ALTER TABLE "'.$value['name'].'" ADD PRIMARY KEY ("'.$v['name'].'");';
						$result[$i] = array('message' => 'Creating table "<b>'.$value['name'].'</b>" field "<b>'.$v['name'].'</b>"', 'query' => $query, 'type' => 0, '_error' => '');
					}
					else{
						if($selected[0]['notnull'] != $v['notnull'])
							$query .= 'ALTER TABLE "'.$value['name'].'" ALTER COLUMN "'.$v['name'].'" '.($v['notnull'] == 't' ? 'SET' : 'DROP').' NOT NULL;';
						if($selected[0]['default'] != $v['default'] || $selected[0]['defaultvalue'] != $v['defaultvalue'])
							$query .= 'ALTER TABLE "'.$value['name'].'" ALTER COLUMN "'.$v['name'].'" '.($v['default'] == 't' ? 'SET' : 'DROP').' DEFAULT'.($v['default'] == 't' ? ' '.$v['defaultvalue'] : '').';';
						if(preg_match("/^nextval\([[:alnum:]'\.:_]+\)/i", $v['defaultvalue'], $matches)){
							$array = explode("'", $matches[0]);
							$array = explode('.', $array[1]);
							$seq_name = empty($array[1]) ? $array[0] : $array[1];
						}
						$selected[0]['constraint'] = '';
						foreach($constraints as $constr)
							if($constr['field'] == $v['name']){
								$selected[0]['constraint'] = $constr['type'];
								break;
							}
						if($selected[0]['constraint'] != $v['constraint']){
							switch($v['constraint']){
								case '': case NULL:
									if($selected[0]['constraint'] == 'p') $query .= 'ALTER TABLE "'.$value['name'].'" DROP CONSTRAINT "'.$value['name'].'_pkey" RESTRICT;';
									else if($selected[0]['constraint'] == 'u') $query .= 'ALTER TABLE "'.$value['name'].'" DROP CONSTRAINT "'.$value['name'].'_'.$v['name'].'_key" RESTRICT;';
									break;
								case 'p': $query .= 'ALTER TABLE "'.$value['name'].'" ADD PRIMARY KEY ("'.$v['name'].'");'; break;
								case 'u': $query .= 'ALTER TABLE "'.$value['name'].'" ADD UNIQUE ("'.$v['name'].'");'; break;
							}
						}
						$result[$i] = array('message' => 'Updating table "<b>'.$value['name'].'</b>" field "<b>'.$v['name'].'</b>"', 'query' => $query, 'type' => 0, '_error' => '');
					}
					if(!empty($query)){
						if(empty($selected)) $this->setLogEvent(2, 16, 11, 'Create DB Table "'.$table.'" field "'.$v['name'].'"');
						else $this->setLogEvent(2, 16, 12, 'Update DB Table "'.$table.'" field "'.$v['name'].'"');
						if($this->DB->query($query) && !$this->DB->Errno){
							$result[$i]['type'] = 3;
							$this->DB->Commit();
							if($v['default'] == 't' && empty($seq_name)){
								$i++;
								$query = 'UPDATE "'.$table.'" SET '.$v['name'].' = '.$v['defaultvalue'].' WHERE '.$v['name'].' IS NULL';
								$result[$i] = array('message' => 'Update DB Table "<b>'.$table.'</b>" field "<b>'.$v['name'].'</b>" set NULL values to DEFAULT value', 'query' => $query, 'type' => 0, '_error' => '');
								$this->setLogEvent(2, 16, 12, 'Update DB Table "'.$table.'" field "'.$v['name'].'" set NULL values to DEFAULT value');
								$this->DB->query($query);
								if($this->DB->query($query) && !$this->DB->Errno){
									$result[$i]['type'] = 3;
									$this->DB->Commit();
								}
								else{
									$result[$i]['_error'] = $this->DB->Error;
									$this->DB->Rollback();
								}
							}
						}
						else{
							$result[$i]['_error'] = $this->DB->Error;
							$this->DB->Rollback();
						}
					}
					$i++;
				}
			}
		}
		return $result;
	}

	function createDBTables(&$DBRules, $request){
		GLOBAL $COMMON_VARS;
		$result = array();
		$i = 0;
		foreach($DBRules as $key => $value){
			foreach($request as $ind => $val){
				if($value['name'] != $val) continue;
				$query = 'CREATE TABLE "'.$value['name'].'" (';
				$structure = array();
				$field_types = array();
				foreach($value['structure'] as $k => $v){
					$field_types[$v['name']] = $v['type'];
					$str = '"'.$v['name'].'" ';
					$str .= $v['name'] == 'id' ? 'SERIAL' : strtoupper($COMMON_VARS['dbfield_types'][$v['type']]);
					if(!empty($v['length']) && in_array($v['type'], $COMMON_VARS['sized_dbfield_types'])) $str .= '('.$v['length'].')';
					if($v['name'] != 'id'){
						if($v['default'] == 't') $str .= ' DEFAULT '.$v['defaultvalue'];
						if($v['notnull'] == 't') $str .= ' NOT NULL';
					}
					$structure[] = $str;
					if($v['constraint'] == 'p') $structure[] = 'CONSTRAINT "'.$value['name'].'_pkey" PRIMARY KEY ("'.$v['name'].'")';
					else if($v['constraint'] == 'u') $structure[] = 'CONSTRAINT "'.$value['name'].'_'.$v['name'].'_key" UNIQUE("'.$v['name'].'")';
				}
				$query .= implode(', ', $structure).') WITH OIDS;';
				foreach($value['index'] as $k => $v){
					$sel = $this->DB->SelectAny('SELECT indexname AS name, indexdef AS query FROM pg_indexes WHERE schemaname = \'public\' AND indexname = \''.$v['name'].'\';');
					if(!empty($selected)) $query .= 'DROP INDEX "'.$v['name'].'";';
					$query .= 'CREATE '.(empty($v['unique']) ? '' : 'UNIQUE ').'INDEX "'.$v['name'].'" ON "'.$value['name'].'" USING btree ("'.implode('", "', $v['fields']).'");';
				}
				$result[$i] = array('message' => 'Creating table "<b>'.$value['name'].'</b>"', 'query' => $query, 'type' => 0, '_error' => '');
				$this->setLogEvent(2, 16, 11, 'Create DB Table "'.$value['name'].'"');
				if($this->DB->query($query) && !$this->DB->Errno){
					$good = true;
					$this->DB->Commit();
					foreach($value['data'] as $k => $v){
						$insert_query = 'INSERT INTO "'.$value['name'].'" ("'.implode('", "', array_keys($v)).'") VALUES (';
						foreach($v as $field => $data){
							switch($field_types[$field]){
								case 'varchar': case 'bpchar': case 'text': case 'date': case 'timestamp': case 'bool': $insert_query .= '\''.$data.'\''; break;
								case 'int2': case 'int4': case 'int8': default: $insert_query .= $data; break;
							};
							$insert_query .= ', ';
						}
						$insert_query = substr($insert_query, 0, strlen($insert_query) - 2).');';
						$result[$i]['query'] .= ' '.$insert_query;
						$this->setLogEvent(2, 16, 11, 'Insert DB Table "'.$value['name'].'" data record');
						if($this->DB->query($insert_query) && !$this->DB->Errno){
							$this->DB->Commit();
							if(array_key_exists('id', $v)) $this->updateDBSequences(array($value['name'].'/'.'id'));
						}
						else{
							$this->DB->Rollback();
							$good = false;
							$result[$i]['_error'] = $this->DB->Error;
						}
					}
					if($good) $result[$i]['type'] = 3;
				}
				else{
					$result[$i]['_error'] = $this->DB->Error;
					$this->DB->Rollback();
				}
				$i++;
			}
		}
		return $result;
	}

	function updateDBData(&$DBRules, $request){
		$result = array();
		$i = 0;
		$seqs = array();
		foreach($DBRules as $key => $value){
			$field_types = array();
			foreach($value['structure'] as $val) $field_types[$val['name']] = $val['type'];
			foreach($request as $ind => $val){
				$array = explode('/', $val);
				$table = $array[0];
				$uid = $array[1];
				if($value['name'] != $table) continue;
				foreach($value['data'] as $k => $v){
					if($k != $uid) continue;
					$result[$i] = array('message' => 'Updating table "<b>'.$value['name'].'</b>" data', 'query' => '', 'type' => 0, '_error' => '');
					$query = 'SELECT id FROM "'.$value['name'].'" WHERE ';
					$insert_query = 'INSERT INTO "'.$value['name'].'" ("'.implode('", "', array_keys($v)).'") VALUES (';
					foreach($v as $field => $data){
						if(!isset($field_types[$field])){
							$result[$i]['_error'] = 'Structure mismatches';
							continue 2;
						}
						$query .= '"'.$field.'" = ';
						switch($field_types[$field]){
							case 'varchar': case 'bpchar': case 'text': case 'date': case 'timestamp': case 'bool': $query .= '\''.$data.'\''; $insert_query .= '\''.$data.'\''; break;
							case 'int2': case 'int4': case 'int8': default: $query .= $data; $insert_query .= $data; break;
						};
						$query .= ' AND';
						$insert_query .= ', ';
					}
					$query = substr($query, 0, strlen($query) - 3).' LIMIT 1;';
					$insert_query = substr($insert_query, 0, strlen($insert_query) - 2).');';
					$result[$i]['query'] = $query;
					$selected = $this->DB->SelectAny($query);
					if($this->DB->Errno){
						$result[$i]['_error'] = $this->DB->Error;
						continue;
					}
					if(!empty($selected)){
						$result[$i]['type'] = 5;
						$result[$i]['_error'] = 'Already exists';
						continue;
					}
					$result[$i]['query'] = $insert_query;
					$this->setLogEvent(2, 16, 11, 'Insert DB Table "'.$value['name'].'" record');
					if($this->DB->query($insert_query) && !$this->DB->Errno){
						$this->DB->Commit();
						$result[$i]['type'] = 3;
						if(array_key_exists('id', $v)) $seqs[] = $value['name'].'/'.'id';
					}
					else{
						$this->DB->Rollback();
						$result[$i]['_error'] = $this->DB->Error;
					}
					$i++;
				}
			}
		}
		$this->updateDBSequences($seqs);
		return $result;
	}

	function updateDBIndexes(&$DBRules, $request){
		$result = array();
		$i = 0;
		foreach($DBRules as $key => $value){
			foreach($request as $ind => $val){
				$array = explode('/', $val);
				$table = $array[0];
				$index = $array[1];
				if($value['name'] != $table) continue;
				foreach($value['index'] as $k => $v){
					if($v['name'] != $index) continue;
					$query = 'SELECT indexname AS name, indexdef AS query FROM pg_indexes WHERE schemaname = \'public\' AND indexname = \''.$v['name'].'\';';
					$result[$i] = array('message' => 'Updating table "<b>'.$value['name'].'</b>" index "<b>'.$v['name'].'</b>"', 'query' => $query, 'type' => 0, '_error' => '');
					$selected = $this->DB->SelectAny($query);
					$query = '';
					if(!empty($selected)) $query .= 'DROP INDEX "'.$v['name'].'";';
					$query .= 'CREATE '.(empty($v['unique']) ? '' : 'UNIQUE ').'INDEX "'.$v['name'].'" ON "'.$value['name'].'" USING btree ("'.implode('", "', $v['fields']).'");';
					$result[$i]['query'] = $query;
					if(empty($selected)) $this->setLogEvent(2, 16, 11, 'Add DB Table "'.$value['name'].'" index "'.$v['name'].'"');
					else $this->setLogEvent(2, 16, 12, 'Update DB Table "'.$value['name'].'" index "'.$v['name'].'"');
					if($this->DB->query($query) && !$this->DB->Errno){
						$result[$i]['type'] = 3;
						$this->DB->Commit();
					}
					else{
						$result[$i]['_error'] = $this->DB->Error;
						$this->DB->Rollback();
					}
					$i++;
				}
			}
		}
		return $result;
	}

	function updateDBSequences($request){
		$result = array();
		foreach($request as $key => $value){
			$array = explode('/', $value);
			$table = $array[0];
			$field = $array[1];
			$result[$key] = array('message' => 'Updating table "<b>'.$table.'</b>" field "<b>'.$field.'</b>" sequence ', 'query' => '', 'type' => 0, '_error' => '');
			$query = 'SELECT
				pg_statio_all_tables.relname AS table,
				pg_attrdef.adsrc AS default,
				pg_attribute.attname AS field
			FROM pg_attrdef, pg_statio_all_tables, pg_attribute
			WHERE pg_statio_all_tables.relname = \''.$table.'\'
				AND pg_attribute.attname = \''.$field.'\'
				AND pg_attrdef.adrelid = pg_statio_all_tables.relid
				AND pg_statio_all_tables.schemaname = \'public\'
				AND pg_attrdef.adsrc LIKE \'nextval(%)\'
				AND pg_attribute.attrelid = pg_statio_all_tables.relid
				AND pg_attribute.attnum = pg_attrdef.adnum
			LIMIT 1';
			$selected = $this->DB->SelectAny($query);
			if(empty($selected)){
				$result[$key]['query'] = $query;
				$result[$key]['_error'] = 'Sequence is not founded.<br>'.$this->DB->Error;
				continue;
			}
			$seq_name = explode("'", $selected[0]['default']);
			$seq_name = $seq_name[1];
			$result[$key]['message'] .= '"<b>'.$seq_name.'</b>"';
			$query = 'SELECT max("'.$field.'") as max FROM "'.$table.'"';
			$max = $this->DB->SelectAny($query);
			if(empty($max)){
				if($this->DB->Errno){
					$result[$key]['query'] = $query;
					$result[$key]['_error'] = 'Can not select max value.<br>'.$this->DB->Error;
					continue;
				}
				$query = 'SELECT setval(\''.$seq_name.'\', 1);';
			}
			else $query = 'SELECT setval(\''.$seq_name.'\', '.$max[0]['max'].');';
			$result[$key]['query'] = $query;
			$this->setLogEvent(2, 16, 12, 'Update DB Table "'.$table.'" field "'.$field.'" sequence "'.$seq_name.'" value');
			if($this->DB->query($query) && !$this->DB->Errno){
				$this->DB->Commit();
				$result[$key]['type'] = 3;
			}
			else{
				$this->DB->Rollback();
				$result[$key]['_error'] = $this->DB->Error;
			}
		}
		return $result;
	}

	function dropDBTables(&$DBRules, $request){
		$result = array();
		foreach($request as $key => $value){
			$result[$key] = array('message' => 'Dropping table "<b>'.$value.'</b>"', 'query' => '', 'type' => 0, '_error' => '');
			foreach($DBRules as $val)
				if($val['name'] == $value){
					$result[$key]['_error'] = 'While you were making schyolk-schyolk by your mouth table was added into the Engine DB Rules.';
					continue 2;
				}
			$query = 'DROP TABLE "'.$value.'";';
			$result[$key]['query'] = $query;
			$this->setLogEvent(2, 16, 13, 'Drop DB Table "'.$value.'"');
			if($this->DB->query($query) && !$this->DB->Errno){
				$this->DB->Commit();
				$result[$key]['type'] = 3;
			}
			else{
				$this->DB->Rollback();
				$result[$key]['_error'] = $this->DB->Error;
			}
		}
		return $result;
	}

	function dropDBIndexes(&$DBRules, $request){
		$result = array();
		foreach($request as $key => $value){
			$array = explode('/', $value);
			$table = $array[0];
			$index = $array[1];
			$result[$key] = array('message' => 'Dropping table "<b>'.$table.'</b>" index "<b>'.$index.'</b>"', 'query' => '', 'type' => 0, '_error' => '');
			foreach($DBRules as $val)
				if($val['name'] == $table)
					foreach($val['index'] as $v)
						if($v['name'] == $index){
							$result[$key]['_error'] = 'While you were making schyolk-schyolk by your mouth index was added into the Engine DB Rules.';
							continue 3;
						}
			$query = 'DROP INDEX "'.$index.'";';
			$result[$key]['query'] = $query;
			$this->setLogEvent(2, 16, 13, 'Drop DB Table "'.$table.'" index "'.$index.'"');
			if($this->DB->query($query) && !$this->DB->Errno){
				$this->DB->Commit();
				$result[$key]['type'] = 3;
			}
			else{
				$this->DB->Rollback();
				$result[$key]['_error'] = $this->DB->Error;
			}
		}
		return $result;
	}

	function dropDBTablesFields(&$DBRules, $request){
		$result = array();
		foreach($request as $key => $value){
			$array = explode('/', $value);
			$table = $array[0];
			$field = $array[1];
			$result[$key] = array('message' => 'Dropping table "<b>'.$table.'</b>" field "<b>'.$field.'</b>"', 'query' => '', 'type' => 0, '_error' => '');
			foreach($DBRules as $val)
				if($val['name'] == $table)
					foreach($val['structure'] as $v)
						if($v['name'] == $field){
							$result[$key]['_error'] = 'While you were making schyolk-schyolk by your mouth field was added into the Engine DB Rules.';
							continue 3;
						}
			$query = 'ALTER TABLE "'.$table.'" DROP COLUMN "'.$field.'";';
			$result[$key]['query'] = $query;
			$this->setLogEvent(2, 16, 13, 'Drop DB Table "'.$table.'" field "'.$field.'"');
			if($this->DB->query($query) && !$this->DB->Errno){
				$this->DB->Commit();
				$result[$key]['type'] = 3;
			}
			else{
				$this->DB->Rollback();
				$result[$key]['_error'] = $this->DB->Error;
			}
		}
		return $result;
	}

	function addDBTablesToRules(&$DBRules, $request){
		$result = array();
		foreach($request as $key => $value){
			$result[$key] = array('message' => 'Adding table "<b>'.$value.'</b>"', 'query' => '', 'type' => 0, '_error' => '');
			foreach($DBRules as $val)
				if($val['name'] == $value){
					$result[$key]['_error'] = 'While you were making schyolk-schyolk by your mouth table was added into the Engine DB Rules.';
					continue 2;
				}
			$selected = $this->DB->SelectAny('SELECT relid FROM pg_statio_all_tables WHERE schemaname=\'public\' AND relname = \''.$value.'\' LIMIT 1');
			if(empty($selected)){
				$result[$key]['_error'] = 'While you were making schyolk-schyolk by your mouth table was dropped.';
				continue;
			}
			$constraints = $this->DB->SelectAny('SELECT conname AS name, contype AS type  FROM pg_constraint WHERE (contype = \'p\' OR contype = \'u\') AND conrelid = '.$selected[0]['relid']);
			foreach($constraints as $ind => $val){
				$field_oid = $this->DB->SelectAny('SELECT indexrelid FROM pg_stat_all_indexes WHERE indexrelname = \''.$val['name'].'\'');
				$field = $this->DB->SelectAny('SELECT attname as field FROM pg_attribute WHERE attrelid = '.$field_oid[0]['indexrelid'].' LIMIT 1');
				$constraints[$ind]['field'] = $field[0]['field'];
			}
			$query = 'SELECT attname AS name, typname AS type, atttypmod-4 AS length, attnotnull AS notnull, atthasdef AS default, pg_attrdef.adsrc AS defaultvalue FROM pg_attribute INNER JOIN pg_class ON pg_attribute.attrelid = pg_class.oid INNER JOIN pg_type ON pg_attribute.atttypid = pg_type.oid LEFT OUTER JOIN pg_attrdef ON pg_attrdef.adrelid = pg_class.oid AND pg_attrdef.adnum = pg_attribute.attnum WHERE attnum > 0 AND attisdropped <> \'t\' AND pg_class.oid = '.$selected[0]['relid'].';';
			$result[$key]['query'] = $query;
			$selected = $this->DB->SelectAny($query);
			if($this->DB->Errno){
				$result[$key]['_error'] = $this->DB->Error;
				continue;
			}
			foreach ($selected as $ind => $val){
				$selected[$ind]['constraint'] = '';
				foreach($constraints as $k => $v)
					if($val['name'] == $v['field']) $selected[$ind]['constraint'] = $v['type'];
			}
			$query2 = 'SELECT indexname AS name, indexdef AS query FROM pg_indexes WHERE schemaname = \'public\' AND tablename = \''.$value.'\' AND indexname NOT IN (SELECT conname FROM pg_constraint);';
			$result[$key]['query'] = $query." ".$query2;
			$indexes = $this->DB->SelectAny($query2);
			if($this->DB->Errno){
				$result[$key]['_error'] = $this->DB->Error;
				continue;
			}
			$rule = array('name' => $value, 'structure' => array(), 'index' => array(), 'data' => array(),);
			foreach($selected as $ind => $val){
				$rule['structure'][$ind] = $val;
				$rule['structure'][$ind]['length'] = intval($rule['structure'][$ind]['length']) == -5 ? '' : $rule['structure'][$ind]['length'];
			}
			foreach($indexes as $val){
				$index = array('name' => $val['name'], 'unique' => '', 'fields' => array(),);
				$occ = strstr($val['query'], 'UNIQUE');
				if($occ !== false) $index['unique'] = 'u';
				preg_match("/\([[:alnum:] ,_\"]+\)/i", $val['query'], $match);
				$index['fields'] = explode(',', str_replace(array('(', ')', ' ', '"'), '', $match[0]));
				$rule['index'][] = $index;
			}
			$DBRules[] = $rule;
			$this->setLogEvent(2, 16, 11, 'Add DB Table "'.$value.'" to the Engine DB Rules');
			$EngineDBRules = $this->saveEngineDBRules($DBRules);
			$added = false;
			foreach($EngineDBRules as $val)
				if($val['name'] == $rule['name']){
					$added = true;
					break;
				}
			if($added){
				$this->DB->Commit();
				$result[$key]['type'] = 3;
				$DBRules = $EngineDBRules;
			}
			else{
				$this->DB->Rollback();
				$result[$key]['_error'] = 'Unknown error. Table was not added.';
			}
		}
		return $result;
	}

	function addDBIndexesToRules(&$DBRules, $request){
		$result = array();
		foreach($request as $key => $value){
			$array = explode('/', $value);
			$table = $array[0];
			$index = $array[1];
			$result[$key] = array('message' => 'Adding table "<b>'.$table.'</b>" index "<b>'.$index.'</b>"', 'query' => '', 'type' => 0, '_error' => '');
			$table_key = false;
			foreach($DBRules as $ind => $val)
				if($val['name'] == $table){
					$table_key = $ind;
					foreach($val['index'] as $v)
						if($v['name'] == $index){
							$result[$key]['_error'] = 'While you were making schyolk-schyolk by your mouth index was added into the Engine DB Rules.';
							continue 3;
						}
					break;
				}
			$query = 'SELECT indexname AS name, indexdef AS query FROM pg_indexes WHERE schemaname = \'public\' AND tablename = \''.$table.'\' AND indexname = \''.$index.'\' LIMIT 1;';
			$result[$key]['query'] = $query;
			$selected = $this->DB->SelectAny($query);
			if(empty($selected)){
				$result[$key]['_error'] = 'While you were making schyolk-schyolk by your mouth index was dropped.';
				continue;
			}
			$rule = array('name' => $index, 'unique' => '', 'fields' => array(),);
			$occ = strstr($selected[0]['query'], 'UNIQUE');
			if($occ !== false) $rule['unique'] = 'u';
			preg_match("/\([[:alnum:] ,_\"]+\)/i", $selected[0]['query'], $match);
			$rule['fields'] = explode(',', str_replace(array('(', ')', ' ', '"'), '', $match[0]));
			if($table_key === false) $DBRules[] = array('name' => $table, 'structure' => array(), 'index' => array(0 => $rule,), 'data' => array(),);
			else $DBRules[$table_key]['index'][] = $rule;
			$this->setLogEvent(2, 16, 11, 'Add DB Table "'.$table.'" index "'.$index.'" to the Engine DB Rules');
			$EngineDBRules = $this->saveEngineDBRules($DBRules);
			$added = false;
			foreach($EngineDBRules as $val)
				if($val['name'] == $table){
					foreach($val['index'] as $v)
						if($v['name'] == $index){
							$added = true;
							break;
						}
					break;
				}
			if($added){
				$this->DB->Commit();
				$result[$key]['type'] = 3;
				$DBRules = $EngineDBRules;
			}
			else{
				$this->DB->Rollback();
				$result[$key]['_error'] = 'Unknown error. Index was not added.';
			}
		}
		return $result;
	}

	function addDBTablesFieldsToRules(&$DBRules, $request){
		$result = array();
		foreach($request as $key => $value){
			$array = explode('/', $value);
			$table = $array[0];
			$field = $array[1];
			$result[$key] = array('message' => 'Adding table "<b>'.$table.'</b>" field "<b>'.$field.'</b>"', 'query' => '', 'type' => 0, '_error' => '');
			$table_key = false;
			foreach($DBRules as $ind => $val)
				if($val['name'] == $table){
					$table_key = $ind;
					foreach($val['structure'] as $v)
						if($v['name'] == $field){
							$result[$key]['_error'] = 'While you were making schyolk-schyolk by your mouth field was added into the Engine DB Rules.';
							continue 3;
						}
					break;
				}
			$query = 'SELECT relid FROM pg_statio_all_tables WHERE schemaname=\'public\' AND relname = \''.$table.'\' LIMIT 1';
			$selected = $this->DB->SelectAny($query);
			if(empty($selected)){
				$result[$key]['_error'] = 'While you were making schyolk-schyolk by your mouth table "'.$table.'" was dropped.';
				continue;
			}
			$constraints = $this->DB->SelectAny('SELECT conname AS name, contype AS type  FROM pg_constraint WHERE (contype = \'p\' OR contype = \'u\') AND conrelid = '.$selected[0]['relid']);
			foreach($constraints as $ind => $val){
				$field_oid = $this->DB->SelectAny('SELECT indexrelid FROM pg_stat_all_indexes WHERE indexrelname = \''.$val['name'].'\'');
				$fieldname = $this->DB->SelectAny('SELECT attname as field FROM pg_attribute WHERE attrelid = '.$field_oid[0]['indexrelid'].' LIMIT 1');
				$constraints[$ind]['field'] = $fieldname[0]['field'];
			}
			$query = 'SELECT attname AS name, typname AS type, atttypmod-4 AS length, attnotnull AS notnull, atthasdef AS default, pg_attrdef.adsrc AS defaultvalue FROM pg_attribute INNER JOIN pg_class ON pg_attribute.attrelid = pg_class.oid INNER JOIN pg_type ON pg_attribute.atttypid = pg_type.oid LEFT OUTER JOIN pg_attrdef ON pg_attrdef.adrelid = pg_class.oid AND pg_attrdef.adnum = pg_attribute.attnum WHERE attnum > 0 AND attname = \''.$field.'\' AND attisdropped <> \'t\' AND pg_class.oid = '.$selected[0]['relid'].';';
			$result[$key]['query'] = $query;
			$selected = $this->DB->SelectAny($query);
			$selected[0]['constraint'] = '';
			foreach($constraints as $val)
				if($val['field'] == $field){
					$selected[0]['constraint'] = $val['type'];
					break;
				}
			if(intval($selected[0]['length']) == -5) $selected[0]['length'] = '';
			if($table_key === false) $DBRules[] = array('name' => $table, 'structure' => array(0 => $selected[0],), 'index' => array(), 'data' => array(),);
			else $DBRules[$table_key]['structure'][] = $selected[0];
			$this->setLogEvent(2, 16, 11, 'Add DB Table "'.$table.'" field "'.$field.'" to the Engine DB Rules');
			$EngineDBRules = $this->saveEngineDBRules($DBRules);
			$added = false;
			foreach($EngineDBRules as $val)
				if($val['name'] == $table){
					foreach($val['structure'] as $v)
						if($v['name'] == $field){
							$added = true;
							break;
						}
					break;
				}
			if($added){
				$this->DB->Commit();
				$result[$key]['type'] = 3;
				$DBRules = $EngineDBRules;
			}
			else{
				$this->DB->Rollback();
				$result[$key]['_error'] = 'Unknown error. Field was not added.';
			}
		}
		return $result;
	}

	function updateTablesStructureDBRules(&$DBRules, $request){
		$result = array();
		foreach($request as $key => $value){
			$array = explode('/', $value);
			$table = $array[0];
			$field = $array[1];
			$result[$key] = array('message' => 'Updating/Deleting DBRule for table "<b>'.$table.'</b>" field "<b>'.$field.'</b>"', 'query' => '', 'type' => 0, '_error' => '');
			$query = 'SELECT relid FROM pg_statio_all_tables WHERE schemaname=\'public\' AND relname = \''.$table.'\' LIMIT 1';
			$selected = $this->DB->SelectAny($query);
			if(empty($selected)){
				$result[$key]['_error'] = 'While you were making schyolk-schyolk by your mouth table "'.$table.'" was dropped.';
				continue;
			}
			$constraints = $this->DB->SelectAny('SELECT conname AS name, contype AS type  FROM pg_constraint WHERE (contype = \'p\' OR contype = \'u\') AND conrelid = '.$selected[0]['relid']);
			$constraints = $this->DB->SelectAny('SELECT conname AS name, contype AS type  FROM pg_constraint WHERE (contype = \'p\' OR contype = \'u\') AND conrelid = '.$selected[0]['relid']);
			foreach($constraints as $ind => $val){
				$field_oid = $this->DB->SelectAny('SELECT indexrelid FROM pg_stat_all_indexes WHERE indexrelname = \''.$val['name'].'\'');
				$fieldname = $this->DB->SelectAny('SELECT attname as field FROM pg_attribute WHERE attrelid = '.$field_oid[0]['indexrelid'].' LIMIT 1');
				$constraints[$ind]['field'] = $fieldname[0]['field'];
			}
			$query = 'SELECT attname AS name, typname AS type, atttypmod-4 AS length, attnotnull AS notnull, atthasdef AS default, pg_attrdef.adsrc AS defaultvalue FROM pg_attribute INNER JOIN pg_class ON pg_attribute.attrelid = pg_class.oid INNER JOIN pg_type ON pg_attribute.atttypid = pg_type.oid LEFT OUTER JOIN pg_attrdef ON pg_attrdef.adrelid = pg_class.oid AND pg_attrdef.adnum = pg_attribute.attnum WHERE attnum > 0 AND attname = \''.$field.'\' AND attisdropped <> \'t\' AND pg_class.oid = '.$selected[0]['relid'].';';
			$result[$key]['query'] = $query;
			$selected = $this->DB->SelectAny($query);
			$table_index = false;
			$field_index = false;
			foreach($DBRules as $ind => $val)
				if($val['name'] == $table){
					$table_index = $ind;
					foreach($val['structure'] as $k => $v)
						if($v['name'] == $field){
							$field_index = $k;
							break 2;
						}
					break;
				}
			if(empty($selected)){
				if($table_index === false || $field_index === false) $result[$key]['type'] = 3;
				else{
					unset($DBRules[$table_index]['structure'][$field_index]);
					$this->setLogEvent(2, 16, 13, 'Delete DB Table "'.$table.'" field "'.$field.'" from the Engine DB Rules');
					$EngineDBRules = $this->saveEngineDBRules($DBRules);
					$deleted = true;
					foreach($EngineDBRules as $val)
						if($val['name'] == $table){
							foreach($val['structure'] as $v)
								if($v['name'] == $field){
									$deleted = false;
									break;
								}
							break;
						}
					if($deleted){
						$this->DB->Commit();
						$result[$key]['type'] = 3;
						$DBRules = $EngineDBRules;
					}
					else{
						$this->DB->Rollback();
						$result[$key]['_error'] = 'Unknown error. Field was not deleted.';
					}
				}
			}
			else{
				if($table_index === false) $result[$key]['_error'] = 'While you were making schyolk-schyolk by your mouth table "'.$table.'" was excluded from DB Rules.';
				else if ($field_index === false) $result[$key]['_error'] = 'While you were making schyolk-schyolk by your mouth table "'.$table.'" field "'.$field.'" was excluded from DB Rules.';
				else{
					$selected[0]['constraint'] = '';
					foreach($constraints as $val)
						if($val['field'] == $field){
							$selected[0]['constraint'] = $val['type'];
							break;
						}
					if(intval($selected[0]['length']) == -5) $selected[0]['length'] = '';
					$DBRules[$table_index]['structure'][$field_index] = $selected[0];
					$this->setLogEvent(2, 16, 12, 'Update DB Table "'.$table.'" field "'.$field.'" rule in the Engine DB Rules');
					$EngineDBRules = $this->saveEngineDBRules($DBRules);
					$updated = false;
					foreach($EngineDBRules as $val)
						if($val['name'] == $table){
							foreach($val['structure'] as $v)
								if($v['name'] == $field){
									if($v == $selected[0]) $updated = true;
									break;
								}
							break;
						}
					if($updated){
						$this->DB->Commit();
						$result[$key]['type'] = 3;
						$DBRules = $EngineDBRules;
					}
					else{
						$this->DB->Rollback();
						$result[$key]['_error'] = 'Unknown error. Field was not updated.';
					}
				}
			}
		}
		return $result;
	}

	function deleteTablesDBRules(&$DBRules, $request){
		$result = array();
		foreach($request as $key => $value){
			$result[$key] = array('message' => 'Deleting DBRule for table "<b>'.$value.'</b>"', 'query' => '', 'type' => 0, '_error' => '');
			$index = false;
			foreach($DBRules as $ind => $val){
				if($val['name'] == $value){
					$index = $ind;
					break;
				}
			}
			if ($index === false) $result[$key]['type'] = 3;
			else{
				unset($DBRules[$index]);
				$this->setLogEvent(2, 16, 13, 'Delete DB Table "'.$value.'" from the Engine DB Rules');
				$EngineDBRules = $this->saveEngineDBRules($DBRules);
				$deleted = true;
				foreach($EngineDBRules as $val)
					if($val['name'] == $value){
						$deleted = false;
						break;
					}
				if($deleted){
					$this->DB->Commit();
					$result[$key]['type'] = 3;
					$DBRules = $EngineDBRules;
				}
				else{
					$this->DB->Rollback();
					$result[$key]['_error'] = 'Unknown error. Table was not deleted.';
				}
			}
		}
		return $result;
	}

	function deleteDataDBRules(&$DBRules, $request){
		$result = array();
		foreach($request as $key => $value){
			$array = explode('/', $value);
			$table = $array[0];
			$data_uid = $array[1];
			$result[$key] = array('message' => 'Deleting DBRule for table "<b>'.$table.'</b>" data uid "<b>'.$data_uid.'</b>"', 'query' => '', 'type' => 0, '_error' => '');
			$table_index = false;
			foreach($DBRules as $ind => $val)
				if($val['name'] == $table){
					$table_index = $ind;
					break;
				}
			if($table_index === false) $result[$key]['_error'] = 'While you were making schyolk-schyolk by your mouth table "'.$table.'" was deleted from DB Rules.';
			else{
				unset($DBRules[$table_index]['data'][$data_uid]);
				$this->setLogEvent(2, 16, 13, 'Delete DB Table "'.$table.'" data record from the Engine DB Rules');
				$EngineDBRules = $this->saveEngineDBRules($DBRules);
				$deleted = true;
				foreach($EngineDBRules as $val)
					if($val['name'] == $value){
						foreach($val['data'] as $k => $v){
							if($k == $data_uid){
								$deleted = false;
								break;
							}
						}
						break;
					}
				if($deleted){
					$this->DB->Commit();
					$result[$key]['type'] = 3;
					$DBRules = $EngineDBRules;
				}
				else{
					$this->DB->Rollback();
					$result[$key]['_error'] = 'Unknown error. Table data was not deleted.';
				}
			}
		}
		return $result;
	}

	function deleteIndexesDBRules(&$DBRules, $request){
		$result = array();
		foreach($request as $key => $value){
			$array = explode('/', $value);
			$table = $array[0];
			$index = $array[1];
			$result[$key] = array('message' => 'Deleting DBRule for table "<b>'.$table.'</b>" index "<b>'.$index.'</b>"', 'query' => '', 'type' => 0, '_error' => '');
			$table_index = false;
			$index_index = false;
			foreach($DBRules as $ind => $val)
				if($val['name'] == $table){
					$table_index = $ind;
					foreach($val['index'] as $k => $v)
						if($v['name'] == $index){
							$index_index = $k;
							break;
						}
					break;
				}
			if($table_index === false) $result[$key]['_error'] = 'While you were making schyolk-schyolk by your mouth table "'.$table.'" was deleted from DB Rules.';
			else if($index_index === false) $result[$key]['_error'] = 'While you were making schyolk-schyolk by your mouth table "'.$table.'" index "'.$index.'" was deleted from DB Rules.';
			else{
				unset($DBRules[$table_index]['index'][$index_index]);
				$this->setLogEvent(2, 16, 13, 'Delete DB Table "'.$table.'" index "'.$index.'" from the Engine DB Rules');
				$EngineDBRules = $this->saveEngineDBRules($DBRules);
				$deleted = true;
				foreach($EngineDBRules as $val)
					if($val['name'] == $value){
						foreach($val['index'] as $k => $v){
							if($v['name'] == $index){
								$deleted = false;
								break;
							}
						}
						break;
					}
				if($deleted){
					$this->DB->Commit();
					$result[$key]['type'] = 3;
					$DBRules = $EngineDBRules;
				}
				else{
					$this->DB->Rollback();
					$result[$key]['_error'] = 'Unknown error. Table index was not deleted.';
				}
			}
		}
		return $result;
	}

	function addEngineDBRules($request = array()){
		GLOBAL $TOOLS_PATH;
		include ($TOOLS_PATH.'\EngineDBRules.inc');
		$count = count($EngineDBRules);
		for ($i = 0; $i < $count; $i++){
			if($EngineDBRules[$i]['name'] == $request['name']){
				$c = count($request['data']);
				for ($j = 0; $j < $c; $j++) $EngineDBRules[$i]['data'][md5(microtime())] = $request['data'][$j];
				$this->setLogEvent(2, 16, 11, 'Add DB Table "'.$request['name'].'" data record to the Engine DB Rules');
				$EngineDBRules = $this->saveEngineDBRules($EngineDBRules);
				$this->DB->commit();
				break;
			}
		}
		return $EngineDBRules;
	}

	function deleteEngineDBRules($request = array()){
		$EngineDBRules = $temp = $this->getEngineDBRules(array());
		foreach($EngineDBRules as $key => $value){
			foreach($request['data'] as $val){
				$array = explode('/', $val);
				if($array[0] == $value['name']){
					unset($temp[$key]['data'][$array[1]]);
					$this->setLogEvent(2, 16, 13, 'Delete DB Table "'.$value['name'].'" data record from the Engine DB Rules');
					$temp = $this->saveEngineDBRules($temp);
					$this->DB->commit();
				}
			}
			foreach($request['table'] as $val){
				if($val == $value['name']){
					unset($temp[$key]);
					$this->setLogEvent(2, 16, 13, 'Delete DB Table "'.$value['name'].'" from the Engine DB Rules');
					$temp = $this->saveEngineDBRules($temp);
					$this->DB->commit();
				}
			}
		}
		return $this->getEngineDBRules(array());
	}

	function saveEngineDBRules($request = array()){
		GLOBAL $TOOLS_PATH;
		sort($request);
		$request = sortArrayBy($request, true, 'name', 'string');
		$count = count($request);
		for ($i = 0; $i< $count; $i++){
			$request[$i]['structure'] = array_values($request[$i]['structure']);
			$request[$i]['index'] = array_values($request[$i]['index']);
		}
		$file = fopen($TOOLS_PATH.'/EngineDBRules.inc', "w");
		$string = '<?php'."\r\n".'$EngineDBRules = '.var_export($request, true).";\r\n".'?>';
		fwrite($file, $string);
		fclose($file);
		return $this->getEngineDBRules(array());
	}

	function getFileDirPerms($request = array()){
		GLOBAL $ROOT_PATH, $TOOLS_PATH, $COMMON_VARS;
		include_once($TOOLS_PATH.'/File.functions.inc');
		$result = array();
		if($request['area'] == 'frontend') $array = $this->getFrontendPathesArray();
		else {
			$array = $this->getBackendPathesArray(true);
			$count = count($array);
			for ($i = 0; $i < $count; $i++) $array[$i] = $ROOT_PATH.$array[$i];
		}
		$count = count($array);
		for ($i = 0; $i < $count; $i++){
			if(!file_exists($array[$i])) continue;
			$fileinfo = getFileDirInfo($array[$i], true, true, true, false, false, false);
			$path = substr($fileinfo['path'], strlen($ROOT_PATH));
			$nofirstslash_path = substr($path, 1);
			if($request['area'] == 'backend') {
				if(array_key_exists($nofirstslash_path, $COMMON_VARS['special_rights_engine_path'])) $perm_link = &$COMMON_VARS['special_rights_engine_path'][$nofirstslash_path];
				else $perm_link = &$COMMON_VARS['default_rights_engine'];
			}
			else {
				if(array_key_exists($nofirstslash_path, $COMMON_VARS['special_rights_path'])) $perm_link = &$COMMON_VARS['special_rights_path'][$nofirstslash_path];
				else $perm_link = &$COMMON_VARS['default_rights'];
			}
			if(($perm_link['u'][0] != '*' && $fileinfo['perm']['u'][0] != $perm_link['u'][0])
			|| ($perm_link['u'][1] != '*' && $fileinfo['perm']['u'][1] != $perm_link['u'][1])
			|| ($perm_link['u'][2] != '*' && $fileinfo['perm']['u'][2] != $perm_link['u'][2])
			|| ($perm_link['u'][3] != '*' && $fileinfo['perm']['u'][3] != $perm_link['u'][3])
			|| ($perm_link['g'][0] != '*' && $fileinfo['perm']['g'][0] != $perm_link['g'][0])
			|| ($perm_link['g'][1] != '*' && $fileinfo['perm']['g'][1] != $perm_link['g'][1])
			|| ($perm_link['g'][2] != '*' && $fileinfo['perm']['g'][2] != $perm_link['g'][2])
			|| ($perm_link['g'][3] != '*' && $fileinfo['perm']['g'][3] != $perm_link['g'][3])
			|| ($perm_link['o'][1] != '*' && $fileinfo['perm']['o'][1] != $perm_link['o'][1])
			|| ($perm_link['o'][2] != '*' && $fileinfo['perm']['o'][2] != $perm_link['o'][2])
			|| ($perm_link['o'][3] != '*' && $fileinfo['perm']['o'][3] != $perm_link['o'][3])){
				$fileinfo['path'] = $path;
				$result[] = $fileinfo;
			}
		}
		return $result;
	}

	function getFrontendPathesArray(){
		GLOBAL $ROOT_PATH, $COMMON_VARS;
		$excluded_pathes = array();
		foreach ($COMMON_VARS['publish_path_denied'] as $value) $excluded_pathes[] = $ROOT_PATH.'/'.$value;
		getPathesArray($result, $ROOT_PATH, $excluded_pathes);
		foreach($COMMON_VARS['writable_frontend_path'] as $key => $value){
			$filepath = $ROOT_PATH.'/'.$key;
			if(!file_exists($filepath)) continue;
			if(is_dir($filepath)){
				$temp = array();
				if(empty($value)) $temp = array($filepath);
				else if($value == '*') getPathesArray($temp, $filepath);
				else $temp = getPatternPathes($filepath, $value);
				$result = array_merge($result, $temp);
			}
		}
		return $result;
	}

	function getBackendPathesArray($include_norecdirs = false){
		GLOBAL $ROOT_PATH, $TOOLS_PATH;
		$result = array();
		include_once($TOOLS_PATH.'/File.functions.inc');
		include ($TOOLS_PATH.'/EngineSnapshot.inc');
		$count = count($EngineSnapshot);
		for ($i = 0; $i < $count; $i++){
			if(substr($EngineSnapshot[$i], (strlen($EngineSnapshot[$i]) - 2)) == '/*') {
				$prepath = '/'.substr($EngineSnapshot[$i], 0, (strlen($EngineSnapshot[$i]) - 2));
				$result[] = $prepath;
				$path = $ROOT_PATH.$prepath;
				$res = array();
				getPathesArray($res, $path);
				$c = count($res);
				for($j = 0; $j < $c; $j++){
					$path = substr($res[$j], strlen($ROOT_PATH));
					$result[] = $path;
				}
			}
			else if(is_dir($ROOT_PATH.'/'.$EngineSnapshot[$i])){
				if($include_norecdirs) $result[] = '/'.$EngineSnapshot[$i];
			}
			else $result[] = '/'.$EngineSnapshot[$i];
		}
		natsort($result);
		$result = array_values($result);
		return $result;
	}

	function generateFileDirPermissions($request = array()){
		GLOBAL $ROOT_PATH, $COMMON_VARS;
		$result = array();
		$xperm = array('x', 'S', 's');
		$count = count($request['filedir']);
		$dirs = array();
		for ($i = 0; $i < $count; $i++){
			$filepath = $ROOT_PATH.$request['filedir'][$i];
			if(!file_exists($filepath)) continue;
			$nofirstslash_path = substr($request['filedir'][$i], 1);
			if(!file_exists($filepath)){
				$this->pushCommandArray($result, $request['filedir'][$i], '', 'Does not exist anymore', 0);
				continue;
			}
			if($request['area'] == 'frontend') {
				if(array_key_exists($nofirstslash_path, $COMMON_VARS['special_rights_path'])) $perm_link = $COMMON_VARS['special_rights_path'][$nofirstslash_path];
				else $perm_link = $COMMON_VARS['default_rights'];
			}
			else {
				if(array_key_exists($nofirstslash_path, $COMMON_VARS['special_rights_engine_path'])) $perm_link = $COMMON_VARS['special_rights_engine_path'][$nofirstslash_path];
				else $perm_link = $COMMON_VARS['default_rights_engine'];
			}
			if($perm_link['u'][0] != '*') $this->pushCommandArray($result, $request['filedir'][$i], 'chown '.$perm_link['u'][0].' '.$nofirstslash_path);
			if($perm_link['g'][0] != '*') $this->pushCommandArray($result, $request['filedir'][$i], 'chgrp '.$perm_link['g'][0].' '.$nofirstslash_path);
			foreach($perm_link as $key => $value){
				$plus = '';
				$minus = '';
				if($value[1] == 'r') $plus .= 'r';
				else if($value[1] == '-') $minus .= 'r';
				if($value[2] == 'w') $plus .= 'w';
				else if($value[2] == '-') $minus .= 'w';
				if(in_array($value[3], $xperm)) $plus .= $value[3];
				else if($value[3] == '-') $minus .= $value[3];
				if(!empty($plus)) $this->pushCommandArray($result, $request['filedir'][$i], 'chmod '.$key.'+'.$plus.' '.$nofirstslash_path);
				if(!empty($minus)) $this->pushCommandArray($result, $request['filedir'][$i], 'chmod '.$key.'-'.$minus.' '.$nofirstslash_path);
			}
		}
		return $result;
	}

	function pushCommandArray(&$array, $path, $command, $message = '', $type = 3){
		$array[] = array(
			'path' => $path,
			'command' => $command,
			'message' => $message,
			'type' => $type,
		);
	}

	function selectEnginePackets($request = array()){
		if(!empty($request['all_addable'])){
			$selected = $this->DB->SelectAny('SELECT enginepacket.id, enginepacket.name FROM enginepacket WHERE (enginepacket.access_flag = 0 OR enginepacket.access_flag = '.$request['user'].') AND enginepacket.actioned = 0 ORDER BY date_changed DESC');
			return $selected;
		}
		if(empty($request['curPageNumber'])) $request['curPageNumber'] = 1;
		if(empty($request['pageRecordsQty'])) $request['pageRecordsQty'] = 50;
		$selected = $this->DB->SelectAny('SELECT id, name, uid, filename, access_flag, date_locked, date_changed, parent, actioned FROM enginepacket ORDER BY date_changed DESC LIMIT '.$request['pageRecordsQty'].' OFFSET '.(($request['curPageNumber'] - 1) * $request['pageRecordsQty']));
		$count = count($selected);
		for ($i = 0; $i < $count; $i++){
			$date_changed = explode('.', $selected[$i]['date_changed']);
			$selected[$i]['date_changed'] = $date_changed[0];
			$date_locked = explode('.', $selected[$i]['date_locked']);
			$selected[$i]['date_locked'] = $date_locked[0];
			if(empty($selected[$i]['parent'])) $selected[$i]['parent_exists'] = false;
			else {
				$parent = $this->DB->SelectAny('SELECT id FROM enginepacket WHERE id = '.$selected[$i]['parent'].' LIMIT 1');
				$selected[$i]['parent_exists'] = empty($parent) ? false : true;
			}
			$selected[$i]['username'] = $this->getUserName(array('id' => $selected[$i]['access_flag'],));
			$selected[$i]['action'] = $this->DB->SelectAny('SELECT id, type, successful, host, date_actioned, userid FROM enginepacketaction WHERE ownerid = '.$selected[$i]['id'].' ORDER BY date_actioned DESC');
			$c = count($selected[$i]['action']);
			for ($j = 0; $j < $c; $j++){
				$date_actioned = explode('.', $selected[$i]['action'][$j]['date_actioned']);
				$selected[$i]['action'][$j]['date_actioned'] = $date_actioned[0];
				$selected[$i]['action'][$j]['hostpath'] = $this->getHostPath(array('host' => $selected[$i]['action'][$j]['host'], 'incoming' => ($selected[$i]['action'][$j]['type'] == 4 ? true : false)));
				$selected[$i]['action'][$j]['username'] = $this->getUserName(array('id' => $selected[$i]['action'][$j]['userid'], 'table' => ($selected[$i]['action'][$j]['type'] == 4 ? 'publisher_user' : 'member')));
			}
		}
		$count = $this->DB->SelectAny('SELECT count(id) AS count FROM enginepacket');
		$request['recordsTotal'] = $count[0]['count'];
		$request['pagesTotal'] = ceil($request['recordsTotal'] / $request['pageRecordsQty']);
		$request['curPage'] = $selected;
		return $request;
	}

	function createEnginePacket(){
		$enginepacket = new EnginePacket();
		$enginepacket->items = new ObjectsList();
		$enginepacket->items->type = new EnginePacketItem();
		$enginepacket->action = new ObjectsList();
		$enginepacket->action->type = $this->createEnginePacketAction();
		return $enginepacket;
	}

	function createEnginePacketAction(){
		$enginepacketaction = new EnginePacketAction();
		$enginepacketaction->report = new ObjectsList();
		$enginepacketaction->report->type = new EnginePacketActionReport();
		return $enginepacketaction;
	}

	function openEnginePacket($request = array()){
		GLOBAL $ROOT_PATH, $TOOLS_PATH, $COMMON_VARS;
		$enginepacket = $this->createEnginePacket();
		include_once($TOOLS_PATH.'/File.functions.inc');
		if(empty($request['compile'])){
			if(empty($request['id'])) return $enginepacket;
			$enginepacket->id = $request['id'];
			$this->DB->initObject($enginepacket);
			switch(@$request['action']){
				case 'Duplicate':{
					$enginepacket->id = '';
					$enginepacket->actioned = 0;
					$enginepacket->parent = 0;
					$count = count($enginepacket->items->data);
					for ($i = 0; $i < $count; $i++)
						if (!empty($enginepacket->items->data[$i]->parent)) unset($enginepacket->items->data[$i]);
					break;
				}
				case 'AddItem': return $enginepacket; break;
			}
		}
		else{
			if(!empty($request['id'])){
				$enginepacket_noitems = new EnginePacket();
				$class_vars = get_class_vars(get_class($enginepacket_noitems));
				$enginepacket_noitems->id = $request['id'];
				$this->DB->initObject($enginepacket_noitems);
				foreach($class_vars as $key => $value)
					if(!isset($request[$key]) && $enginepacket_noitems->{$key} !== NULL) $request[$key] = $enginepacket_noitems->{$key};
				unset($enginepacket_noitems);
			}
			$this->parseRequest($request, $enginepacket);
		}
		$datetime = explode('.', $enginepacket->date_created);
		$enginepacket->date_created = $datetime[0];
		if(empty($enginepacket->actioned)){
			$selected = $this->DB->SelectAny('SELECT max(id) AS max_id FROM enginepacketitem');
			$max = empty($selected) ? 0 : $selected[0]['max_id'];
			for ($i = 0; $i < count($enginepacket->items->data); $i++){
				if(empty($enginepacket->items->data[$i]->id)) $enginepacket->items->data[$i]->id = ++$max;
				$path = $ROOT_PATH.$enginepacket->items->data[$i]->object;
				if(!file_exists($path)) $enginepacket->items->data[$i]->_error = 'Does not exist';
				else{
					if(!is_writable($path)) $enginepacket->items->data[$i]->_error = 'Not writable';
					if(is_dir($path)){
						if(empty($enginepacket->items->data[$i]->parent)){
							$result = array();
							getPathesArray($result, $path);
							$c = count($result);
							$index = count($enginepacket->items->data);
							for ($j = 0; $j < $c; $j++){
								$enginepacket->items->data[$index] = new EnginePacketItem();
								$enginepacket->items->data[$index]->id = ++$max;
								$enginepacket->items->data[$index]->object = substr($result[$j], strlen($ROOT_PATH));
								$enginepacket->items->data[$index]->parent = $enginepacket->items->data[$i]->id;
								$index++;
							}
						}
					}
					else{
						$enginepacket->items->data[$i]->date_changed = date('Y-m-d H:i:s', filemtime($path));
						$enginepacket->items->data[$i]->hash = md5_file($path);
					}
				}
			}
		}
		else{
			$filepath = $ROOT_PATH.'/'.$COMMON_VARS['enginepacket_dir'].'/'.$enginepacket->filename;
			if(!file_exists($filepath) || !is_file($filepath)) $enginepacket->_error = 'Packet file does not exist';
			//if(!is_writable($filepath)) $enginepacket->_error = 'Packet file is not writable';
			$count = count($enginepacket->items->data);
			for ($i = 0; $i < $count; $i++){
				$enginepacket->items->data[$i]->message = '';
				$path = $ROOT_PATH.$enginepacket->items->data[$i]->object;
				if(!file_exists($path)) $enginepacket->items->data[$i]->message = 'Does not exist anymore';
				else{
					if(!is_writable($path)) $enginepacket->items->data[$i]->message = 'Not writable anymore';
					$is_dir = is_dir($path);
					if($is_dir){
						if(!empty($enginepacket->items->data[$i]->hash)) $enginepacket->items->data[$i]->message = 'Not a file anymore';
						else if(empty($enginepacket->items->data[$i]->parent)){
							$result = array();
							getPathesArray($result, $path);
							for ($j = 0; $j < $count; $j++){
								if($enginepacket->items->data[$j]->parent == $enginepacket->items->data[$i]->id) unset($result[array_search($ROOT_PATH.$enginepacket->items->data[$j]->object, $result)]);
							}
							if(!empty($result)) $enginepacket->items->data[$i]->message = 'Dir content has been changed';
						}
					}
					else{
						if(empty($enginepacket->items->data[$i]->hash)) $enginepacket->items->data[$i]->message = 'Not a dir anymore';
						else{
							//if($enginepacket->items->data[$i]->date_changed != date('Y-m-d H:i:s', filemtime($path))) $enginepacket->items->data[$i]->message = 'Has been changed (date changed)';
							if($enginepacket->items->data[$i]->hash != md5_file($path)) $enginepacket->items->data[$i]->message = 'Has been changed (hash)';
						}
					}
				}
			}
		}
		$count = count($enginepacket->action->data);
		for ($i = 0; $i < $count; $i++){
			$date_actioned = explode('.', $enginepacket->action->data[$i]->date_actioned);
			$enginepacket->action->data[$i]->date_actioned = $date_actioned[0];
			$enginepacket->action->data[$i]->username = $this->getUsername(array('id' => $enginepacket->action->data[$i]->userid, 'table' => ($enginepacket->action->data[$i]->type == 4 ? 'publisher_user' : 'member'),));
			$request = $enginepacket->action->data[$i]->type == 4 ? array('host' => $enginepacket->action->data[$i]->host, 'incoming' => true) : array('host' => $enginepacket->action->data[$i]->host);
			$enginepacket->action->data[$i]->hostpath = $this->getHostPath($request);
		}
		return $enginepacket;
	}

	function selectEnginePacketAdds($request = array()){
		$result = array();
		$paths = $this->getBackendPathesArray();
		$count = count($paths);
		for ($i = 0; $i < $count; $i++) $result[$paths[$i]] = $paths[$i];
		return $result;
	}

	function getEnginePacketAccess($request = array()){
		if(empty($request['id'])) return $request;
		$selected = $this->DB->SelectAny('SELECT id, name, access_flag, date_locked, date_changed, actioned FROM enginepacket WHERE id = '.$request['id'].' LIMIT 1');
		if(!empty($selected)){
			$date_locked = explode('.', $selected[0]['date_locked']);
			$selected[0]['date_locked'] = $date_locked[0];
			$date_changed = explode('.', $selected[0]['date_changed']);
			$selected[0]['date_locked'] = $date_changed[0];
			$selected[0]['username'] = $this->getUserName(array('id' => $selected[0]['access_flag'],));
		}
		return empty($selected) ? $request : $selected[0];
	}

	function setEnginePacketAccess($request = array()){
		if(empty($request['id']) || !isset($request['access_flag'])) return $request;
		$this->setLogEvent(2, 17, (empty($request['access_flag']) ? 4 : 3), (empty($request['access_flag']) ? 'Unlock' : 'Lock').' engine packet "'.$request['name'].'" ['.$request['id'].']', $request['id']);
		$this->DB->update('enginepacket', array('access_flag' => $request['access_flag'], 'date_locked' => 'now()'), array('id' => $request['id']),0);
		if(!$this->DB->Errno) $this->DB->Commit();
		return $this->getEnginePacketAccess($request);
	}

	function openEnginePacketIem($request = array()){
		if(empty($request['id'])) return $request;
		$enginepacketitem = new EnginePacketItem();
		$enginepacketitem->id = $request['id'];
		$this->DB->initObject($enginepacketitem);
		$enginepacketitem->packetname = '';
		$enginepacketitem->packetuid = '';
		$enginepacketitem->filename = '';
		if(empty($enginepacketitem->ownerid)) $enginepacketitem->_error = 'No owner';
		else{
			$selected = $this->DB->SelectAny('SELECT name, uid, filename FROM enginepacket WHERE id = '.$enginepacketitem->ownerid.' LIMIT 1');
			if(!empty($selected)){
				$enginepacketitem->packetname = $selected[0]['name'];
				$enginepacketitem->packetuid = $selected[0]['uid'];
				$enginepacketitem->filename = $selected[0]['filename'];
			}
		}
		return $enginepacketitem;
	}

	function saveEnginePacket($request = array()){
		if(empty($request['id'])){
			$request['uid'] = md5(microtime());
			$request['date_created'] = 'now';
		}
		$request['date_changed'] = 'now';
		//$request['access_flag'] = '0';
		$enginepacket = $this->createEnginePacket();
		$this->parseRequest($request, $enginepacket);
		$this->DB->processObject($enginepacket);
		$this->setLogEvent(2, 17, (empty($request['id']) ? 11 : 12), (empty($request['id']) ? 'Add' : 'Edit').' engine packet "'.$enginepacket->name.'" ['.$enginepacket->id.']', $enginepacket->id);
		if($this->DB->Errno){
			$this->DB->Rollback();
			$enginepacket = $this->openEnginePacket(array_merge($request, array('compile' => true)));
		}
		else{
			$this->DB->Commit();
			$this->setEnginePacketAccess(array('id' => $request['id'], 'name' => $request['name'], 'access_flag' => '0'));
		}
		return $enginepacket;
	}

	function saveActionedEnginePacket($request = array()){
		$request['actioned'] = '1';
		$enginepacket = $this->createEnginePacket();
		$request_noitems = $request;
		$request_noitems['items'] = array();
		$this->parseRequest($request_noitems, $enginepacket);
		$this->DB->processObject($enginepacket);
		$count = count($request['items']);
		$items_id_match = array();
		for ($i = 0; $i < $count; $i++){
			$temp_id = $request['items'][$i]['id'];
			$request['items'][$i]['id'] = '';
			$request['items'][$i]['ownerid'] = $enginepacket->id;
			if(!empty($request['items'][$i]['parent'])) $request['items'][$i]['parent'] = $items_id_match[$request['items'][$i]['parent']];
			$enginepacketitem = $this->saveEnginePacketItem($request['items'][$i]);
			$items_id_match[$temp_id] = $enginepacketitem->id;
		}
		if(empty($request['action'])) $this->setLogEvent(2, 17, 11, 'Add packed engine packet "'.$enginepacket->name.'" ['.$enginepacket->id.']', $enginepacket->id);
		else $this->setLogEvent(2, 17, 5, 'Pack engine packet "'.$enginepacket->name.'" ['.$enginepacket->id.'] into the file "'.$enginepacket->filename.'"', $enginepacket->id);
		$this->DB->Commit();
		if(!empty($enginepacket->access_flag)) $this->setEnginePacketAccess(array('id' => $enginepacket->id, 'name' => $request['name'], 'access_flag' => '0'));
		$enginepacket = $this->openEnginePacket(array('id' => $enginepacket->id));
		return $enginepacket;
	}

	function saveEnginePacketItem($request = array()){
		$enginepacketitem = new EnginePacketItem();
		$this->parseRequest($request, $enginepacketitem);
		$this->DB->Begin();
		$this->DB->processObject($enginepacketitem);
		$this->DB->Commit();
		return $enginepacketitem;
	}

	function openEnginePacketAction($request = array()){
		$enginepacketaction = $this->createEnginePacketAction();
		$enginepacketaction->id = $request['id'];
		$this->DB->initObject($enginepacketaction);
		$date_actioned = explode('.', $enginepacketaction->date_actioned);
		$enginepacketaction->date_actioned = $date_actioned[0];
		$enginepacketaction->username = $this->getUsername(array('id' => $enginepacketaction->userid, 'table' => ($enginepacketaction->type == 4 ? 'publisher_user' : 'member'),));
		$request = $enginepacketaction->type == 4 ? array('host' => $enginepacketaction->host, 'incoming' => true) : array('host' => $enginepacketaction->host);
		$enginepacketaction->hostpath = $this->getHostPath($request);
		return $enginepacketaction;
	}

	function saveEnginePacketAction($request = array()){
		$enginepacketaction = $this->createEnginePacketAction();
		$this->parseRequest($request, $enginepacketaction);
		$this->DB->Begin();
		$this->DB->processObject($enginepacketaction);
		$this->DB->Commit();
		return $this->openEnginePacketAction(array('id' => $enginepacketaction->id));
	}

	function deleteEnginePacket($request = array()){
		if(empty($request['id'])) return $request;
		$enginepacket = $this->createEnginePacket();
		$enginepacket->id = $request['id'];
		$this->DB->Begin();
		$this->DB->initObject($enginepacket);
		$this->setLogEvent(2, 17, 13, 'Delete engine packet "'.$enginepacket->name.'" ['.$enginepacket->id.'] ', $enginepacket->id);
		$this->DB->processObject($enginepacket, 'delete', array(), array(), TRUE);
		$this->DB->Commit();
		return $enginepacket;
	}

	function searchEnginePacket($request = array()){
		$result = array();
		$packets = array();
		$query = 'SELECT id, name FROM enginepacket';
		$conditions = array();
		if(!empty($request['not_older'])) $conditions[] = 'date_created > \''.date("Y-m-d", time() - $request['not_older']).'\'';
		if(!empty($request['packed'])) $conditions[] = 'id IN (SELECT ownerid FROM enginepacketaction WHERE type = 1 AND date_actioned > \''.date("Y-m-d", time() - $request['packed']).'\')';
		if(!empty($request['unpacked'])) $conditions[] = 'id IN (SELECT ownerid FROM enginepacketaction WHERE type = 2 AND date_actioned > \''.date("Y-m-d", time() - $request['unpacked']).'\')';
		if(!empty($request['published'])) $conditions[] = 'id IN (SELECT ownerid FROM enginepacketaction WHERE type = 3 AND date_actioned > \''.date("Y-m-d", time() - $request['published']).'\')';
		if(!empty($request['inpublished'])) $conditions[] = 'id IN (SELECT ownerid FROM enginepacketaction WHERE type = 4 AND date_actioned > \''.date("Y-m-d", time() - $request['inpublished']).'\')';
		if(!empty($conditions)) $query .= ' WHERE '.implode(' AND ', $conditions);
		$query .= ' ORDER BY id DESC';
		$packets = $this->DB->SelectAny($query);
		if(empty($request['contained'])) return $packets;
		else{
			$conditions = array();
			$count  = count($request['contained']);
			for ($i = 0; $i < $count; $i++) $conditions[] = 'object LIKE \'%'.$request['contained'][$i].'%\'';
			$count = count($packets);
			for($i = 0; $i < $count; $i++){
				$contain = true;
				$cond_count = count($conditions);
				for ($j = 0; $j < $cond_count; $j++){
					$selected = $this->DB->SelectAny('SELECT id FROM enginepacketitem WHERE ownerid = '.$packets[$i]['id'].' AND '.$conditions[$j]);
					if(empty($selected)){
						$contain = false;
						break;
					}
				}
				if($contain) $result[] = $packets[$i];
			}
		}
		return $result;
	}

	function getPublisherHostID($request = array()){
		$selected = $this->DB->SelectAny('SELECT id FROM publisher WHERE host = \''.$request['host'].'\' LIMIT 1');
		if(empty($selected)){
			$this->DB->insert('publisher', array('host' => $request['host']));
			$selected = $this->DB->SelectAny('SELECT id FROM publisher WHERE oid = '.$this->DB->Last_ID);
		}
		return $selected[0]['id'];
	}

	function getPublisherUserID($request = array()){
		$selected = $this->DB->SelectAny('SELECT id FROM publisher_user WHERE username = \''.$request['user'].'\' LIMIT 1');
		if(empty($selected)){
			$this->DB->insert('publisher_user', array('username' => $request['user']));
			$selected = $this->DB->SelectAny('SELECT id FROM publisher_user WHERE oid = '.$this->DB->Last_ID);
		}
		return $selected[0]['id'];
	}

	function getUserPublisherID($request = array()){
		$selected = $this->DB->SelectAny('SELECT id FROM member WHERE type = (SELECT id FROM membertype WHERE name = \'publisher\' LIMIT 1) LIMIT 1');
		if(empty($selected)) return false;
		return $selected[0]['id'];
	}

	function deleteFromChangedURLAndDeleted($request = array()){
		if(empty($request['preset'])) return array('_error' => 'PreSet ID is not specified');
		if(!isset($request['objects_state']) || !is_array($request['objects_state'])) $request['objects_state'] = array();
		$this->DB->query('DELETE FROM deleted WHERE preset = '.$request['preset']);
		$this->DB->query('DELETE FROM changedurl WHERE preset = '.$request['preset']);
		$types_request = array(
			1 => array('table' => 'layout', 'fields' => ''),
			2 => array('table' => 'menu', 'fields' => ''),
			3 => array('table' => 'module', 'fields' => 'path'),
			6 => array('table' => 'template', 'fields' => ''),
			12 => array('table' => 'subdomain', 'fields' => ''),
			13 => array('table' => 'importedfeed', 'fields' => ''),
			14 => array('table' => 'city', 'fields' => ''),
			15 => array('table' => 'feed', 'fields' => ''),
		);
		$types = array_keys($request['objects_state']);
		$count = count($types);
		for ($i = 0; $i < $count; $i++){
			$ids = array_keys($request['objects_state'][$types[$i]]);
			$c = count($ids);
			for ($j = 0; $j < $c; $j++){
				$selected = $this->DB->SelectAny('SELECT id, uid'.(empty($types_request[$types[$i]]['fields']) ? '' : ', '.$types_request[$types[$i]]['fields']).' FROM '.$types_request[$types[$i]]['table'].' WHERE id = '.$ids[$j].' LIMIT 1');
				if(empty($selected)) $this->DB->insert('deleted', array('uid' => $request['objects_state'][$types[$i]][$ids[$j]]['uid'], 'preset' => $request['preset'], 'type' => $types[$i]));
				else if ($types[$i] == 3 && $selected[0]['path'] != $request['objects_state'][$types[$i]][$ids[$j]]['path']) $this->DB->insert('changedurl', array('ownerid' => $ids[$j], 'preset' => $request['preset']));
			}
		}
		return array();
	}

	function deleteOldBackups($request = array()) {
		GLOBAL $ROOT_PATH, $COMMON_VARS, $REGISTRY;
		$result = array();
		$engine_version = explode('.', $REGISTRY['Core']['EngineVersion']);
		$selected = $this->DB->SelectAny('SELECT id, name, engine_version, filename FROM backup ORDER BY id ');
		$index = 0;
		$count = count($selected);
		for ($i = 0; $i < $count; $i++){
			$backup_engine_version = explode('.', $selected[$i]['engine_version']);
			$file_exists = file_exists($ROOT_PATH.'/'.$COMMON_VARS['backup_dir'].'/'.$selected[$i]['filename']);
			if($backup_engine_version[0] != $engine_version[0] || $backup_engine_version[1] != $engine_version[1] || !$file_exists){
				$result[$index] = $selected[$i];
				if($file_exists) {
					$result[$index]['message'] = 'Backup engine version does not conform to the current CMS version.';
					mysystem('rm -rf '.$ROOT_PATH.'/'.$COMMON_VARS['backup_dir'].'/'.$selected[$i]['filename']);
				}
				else $result[$index]['message'] = 'Physical backup file does not exist on drive.';
				$deleted = $this->deleteBackup(array('id' => $selected[$i]['id']));
				$result[$index]['error'] = empty($deleted->_error) ? '' : $deleted->_error;
				$index++;
			}
		}
		return $result;
	}
}
?>