<?php

class CorePublishingManagerView extends Slot {

	var $SectionID = 8;
	var $ModuleID = 4;

	function __construct($pquery) {
		parent::__construct($pquery);
	}

	function init() {
		global $TOOLS_PATH;
		switch(@$this->LocalTarget[0]) {
			default: {
				$this->Action->processEvent($this->SectionID, 'select', array(), $this);
				$this->Scheme = 'default';
				break;
			}
			case 'Log': {
				$this->Action->processEvent($this->SectionID, 'get_guides', array(), $this);
				$this->Scheme = 'log';
				break;
			}
		}
		$this->setSchemeTemplate($this->Scheme);
	}

	function validateForm() {
		if(!is_AdvCleanText($this->getRequestFormField('comment'),5,4096)) 
			$this->errors['comment'] = 'Comment is empty or is not valid';
		if(count($this->errors) > 0) 
			return FALSE;
		return TRUE;
	}

	function fillElements() {
		switch($this->Scheme) {
			default: 
				$this->fillDefault();
			case 'log': 
				$this->fillLog(); 
				break;
		}
	}

	function fillDefault() {
		global $CORE_PATH;
		$this->TempFillEls['addBut'] = $this->server_type!='dev'? 'hidden' : 'visible';
		foreach($this->PreparedTemplates as $value) {
			if($value['id'] == 1){
				foreach($value['presets'] as $v)
					$this->TempFillEls['servers'][] = array(
						'id' => $this->server_type!='dev'? '' : inputHidden('form[servers]['.$v['id'].']',0).inputCheckbox('form[servers]['.$v['id'].']',0,'',1),
						'type' => '[SINGLE]',
						'name' => $v['name'],
						'list' => '&nbsp;',
					);
			}
			else{
				if (empty($value['presets']))
					continue;
				$servers = array();
				foreach($value['presets'] as $v)
					$servers[$v['id']] = $v['name'];
				$this->TempFillEls['servers'][] = array(
					'id' => $this->server_type!='dev'? '' : inputHidden('form[groups]['.$value['id'].']',0).inputCheckbox('form[groups]['.$value['id'].']', 0, '', 1),
					'type' => '[GROUP]',
					'name' => $value['name'],
					'list' => '('.implode(', ', $servers).')',
				);
			}
		}
	}

	function fillLog() {
		global $TOOLS_PATH, $ROOT_PATH, $CORE_PATH;
		if(!empty($this->Request)){
			$servers = array();
			foreach($this->Request['form']['servers'] as $key => $value)
				if($value == '1')
					$presets[] = $key;
			foreach($this->Request['form']['groups'] as $key => $value)
				if($value == '1')
					foreach($this->PreparedTemplates['groupslist'][$key]['presets'] as $k => $v)
						$presets[] = $k; 
			include($TOOLS_PATH.'/transfer.php');
			foreach($presets as $key => $value) {
				$this->Action->processEvent($this->SectionID, 'open', array('id' => $value), $this);
				$servers[] = '"'.$this->PreparedTemplates['name'].'"';
				$Trans_field = array(
					'report_id' => $value,
					'server_name' => $this->PreparedTemplates['name'],
					'db_host' => $this->PreparedTemplates['db_host'],
					'db_name' => $this->PreparedTemplates['db_name'],
					'db_user' => $this->PreparedTemplates['db_user'],
					'db_password' => $this->PreparedTemplates['db_password'],
					'db_port' => $this->PreparedTemplates['db_port'],
					'ftp' => 'ftp://'.$this->PreparedTemplates['ftp_user'].':'.$this->PreparedTemplates['ftp_password'].'@'.$this->PreparedTemplates['ftp_host'].'/%2f'.$this->PreparedTemplates['ftp_folder'],
					'url' => $this->PreparedTemplates['path'],
				);
				$rc = new curl();
				$report = array();
				$begin_time = currentTime();
				$report['start'][] = "<table align=center cellpadding=0 cellspacing=0>";
				if (isset($this->Request['DatabaseCheck'])){
					toReport($report, 'start', 1, date('H:i:s', $begin_time), 'begin database check on server', $Trans_field['server_name']);
					if (!$this->databasesMatch (&$report, getSignature ($rc, $report, $Trans_field), $Trans_field))
						toReport($report, 'start', 4, '&nbsp;', "Databases' structures mismatch. See below for details.");
					$end_time = currentTime();
					toReport($report, 'finish', 2, date('H:i:s',$end_time), 'end database check on server', $Trans_field['server_name']);
					toReport($report, 'finish', 2, round($end_time-$begin_time,2).' sec.', 'execution time');
					$this->Action->processEvent($this->SectionID, 'log', array('type' => 4,'entity' => 3,'event' => 16, 'value' => 'Database structure check on server: #'.$Trans_field['report_id'].' "'.$Trans_field['server_name'].'"'), $this);
				}
				if (isset($this->Request['DatabaseUpdate'])){
					toReport($report, 'start', 1, date('H:i:s', $begin_time), 'begin database transfer on server', $Trans_field['server_name']);
					if ($this->databasesMatch (&$report, getSignature ($rc, $report, $Trans_field), $Trans_field, true))
						toReport($report, 'start', 4, '&nbsp;', "Changes marked by different color. See below for details.");
					else
						toReport($report, 'start', 4, '&nbsp;', "Databases' structures mismatch. See below for details.");
					$end_time = currentTime();
					toReport($report, 'finish', 2, round($end_time-$begin_time,2).' sec.', 'execution time');
					toReport($report, 'finish', 2, '&nbsp;', 'to be sure check again database on', $Trans_field['server_name']);
					$this->Action->processEvent($this->SectionID, 'log', array('type' => 4,'entity' => 3,'event' => 16, 'value' => 'Database structure update on server: #'.$Trans_field['report_id'].' "'.$Trans_field['server_name'].'"'), $this);
				}
				if (isset($this->Request['SequencesValidate'])){
					toReport($report, 'start', 1, date('H:i:s', $begin_time), 'begin validate sequences on server', $Trans_field['server_name']);
					if ($this->sequencesValidate (&$report, $Trans_field))
						toReport($report, 'start', 3, '&nbsp;', 'No invalid sequences founded');
					else
						toReport($report, 'start', 4, '&nbsp;', "Founded invalid sequences' value. See below for details.");
					$end_time = currentTime();
					toReport($report, 'finish', 2, date('H:i:s',$end_time), 'end validate sequences on server', $Trans_field['server_name']);
					toReport($report, 'finish', 2, round($end_time-$begin_time,2).' sec.', 'execution time');
					$this->Action->processEvent($this->SectionID, 'log', array('type' => 4,'entity' => 3,'event' => 16, 'value' => 'Sequences validate on server: #'.$Trans_field['report_id'].' "'.$Trans_field['server_name'].'"'), $this);
				}
				if (isset($this->Request['SequencesFix'])){
					toReport($report, 'start', 1, date('H:i:s', $begin_time), 'begin fix sequences on server', $Trans_field['server_name']);
					if ($this->sequencesValidate(&$report, $Trans_field, true))
						toReport($report, 'start', 3, '&nbsp;', 'No invalid sequences founded');
					else
						toReport($report, 'start', 4, '&nbsp;', "Changes marked by different color. See below for details.");
					$end_time = currentTime();
					toReport($report, 'finish', 2, round($end_time-$begin_time,2).' sec.', 'execution time');
					toReport($report, 'finish', 2, '&nbsp;', 'to be sure validate again sequences on', $Trans_field['server_name']);
					$this->Action->processEvent($this->SectionID, 'log', array('type' => 4,'entity' => 3,'event' => 16, 'value' => 'Sequences fix on server: #'.$Trans_field['report_id'].' "'.$Trans_field['server_name'].'"'), $this);
				}
				if (isset($this->Request['EngineCheck']) || isset($this->Request['SendEngineUpdate'])){
					include_once($TOOLS_PATH.'/remoteFF.php');
					include_once($TOOLS_PATH.'/common.inc');
					$begin_time = currentTime();
					$report['start'][] = "<table align=center cellpadding=0 cellspacing=0>";
					toReport($report, 'start', 1, date('H:i:s', $begin_time), 'begin check files & folders on server', '<nobr>'.$Trans_field['server_name'].'</nobr>');
					$engine_snapshot = makeFFSnapshot ($CORE_PATH, array('.', '..'), '');
					if(isset($engine_snapshot['DIR/Tools']['common.inc']))
						unset($engine_snapshot['DIR/Tools']['common.inc']);
					$js_snapshot = makeFFSnapshot ($ROOT_PATH.'/registarJS', array('.', '..'), '');
					$img_snapshot = makeFFSnapshot ($ROOT_PATH.'/registarImg', array('.', '..'), '');
					$ajax_snapshot = makeFFSnapshot($ROOT_PATH.'/AjaxProxy', array('.', '..'), array('.php', '.inc',));
					$snapshot = array_merge(array('DIR/engine' => $engine_snapshot), array('DIR/registarJS' => $js_snapshot), array('DIR/registarImg' => $img_snapshot), array('DIR/AjaxProxy' => $ajax_snapshot));
					foreach($snapshot['DIR/engine']['DIR/Templates'] as $k => $v)
						if(!strstr($k, 'DIR/') && ereg('[a-zA-Z0-9_-].layout.html', $k))
							unset($snapshot['DIR/engine']['DIR/Templates'][$k]);
					$snapshot = array_merge($snapshot, $Path['engine']['dirs_exist']);
					//unset($snapshot['DIR/engine']['.htaccess']);
					unset($snapshot['DIR/engine']['signature.inc']);
					unset($snapshot['DIR/engine']['Registry.inc']);
					unset($snapshot['DIR/engine']['Registry2.inc']);
					unset($snapshot['DIR/engine']['RegistryAdd.inc']);
					$snapshot['eng'] = md5_file($ROOT_PATH.'/eng');
					$snapshot['index.php'] = md5_file($ROOT_PATH.'/index.php');
					$snapshot['receiver.php'] = md5_file($ROOT_PATH.'/receiver.php');
					$snapshot['get_session.php'] = md5_file($ROOT_PATH.'/get_session.php');
					$snapshot['chowner'] = md5_file($ROOT_PATH.'/chowner');
					$snapshot['CCURequest.pl'] = md5_file($ROOT_PATH.'/CCURequest.pl');
					$snapshot['DIR/enginepacket']['.htaccess'] = md5_file($ROOT_PATH.'/enginepacket/.htaccess');
					$snapshot['DIR/package']['.htaccess'] = md5_file($ROOT_PATH.'/package/.htaccess');
					$snapshot['DIR/temporary']['.htaccess'] = md5_file($ROOT_PATH.'/temporary/.htaccess');
					$file_temp = fopen($Path['temp_dir'].$Path['ffsnapshot_file'], "w+");
					if (fputs($file_temp, '$FFSnapshot = '.var_export($snapshot, true).'; ')
					and fputs($file_temp, '$WritableDirs = '.var_export($Path['engine']['dirs_writable'], true).'; ')
					and fputs($file_temp, '$WritableFiles = '.var_export($Path['engine']['files_writable'], true).'; ')
					and fputs($file_temp, '$UnwritableDirs = '.var_export($Path['engine']['dirs_unwritable'], true).'; ')
					and fputs($file_temp, '$UnwritableFiles = '.var_export($Path['engine']['files_unwritable'], true).'; ')
					and send($report, $rc, $Trans_field['ftp'].$Path['ftp_upload_dir'], $Path['temp_dir'], $Path['ffsnapshot_file'], 'snapshot', true)
					and send($report, $rc, $Trans_field['ftp'], $TOOLS_PATH."/", $Path['remoteff_file'], 'check script', false)){
						if (isset($this->Request['EngineCheck'])){
							launchScript($Trans_field['url'].$Path['remoteff_file'].'?engine=true', $report);
							removeRemoteFile($report, $Trans_field['ftp'], $Path['remoteff_file'], 'check script');
							$end_time = currentTime();
							toReport($report, 'finish', 2, date('H:i:s',$end_time), 'end check files & folders on server', '<nobr>'.$Trans_field['server_name'].'</nobr>');
							$this->Action->processEvent($this->SectionID, 'log', array('type' => 4,'entity' => 3,'event' => 16, 'value' => 'Engine check on server: #'.$Trans_field['report_id'].' "'.$Trans_field['server_name'].'"'), $this);
						}
						if (isset($this->Request['SendEngineUpdate'])){
							toReport($report, 'begin_script', 1, date('H:i:s', time()), 'begin processing', 'script');
							$curl = curl_init();
							curl_setopt($curl, CURLOPT_URL, $Trans_field['url'].$Path['remoteff_file'].'?engine=true&get_mismatches=true');
							curl_setopt($curl, CURLOPT_HEADER, 0);
							curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
							$result = curl_exec($curl);
							$status = curl_getinfo($curl);
							curl_close($curl);
							removeRemoteFile($report, $Trans_field['ftp'], $Path['remoteff_file'], 'check script');
							if(empty($result)){
								toReport($report, 'end_script', 0, date('H:i:s', time()), "processing script failed.");
								toReport($report, 'end_script', 3, date('H:i:s', time()), $status);
							}
							eval('$mismatches = '.$result.';');
							if(isset($mismatches))
								toReport($report, 'end_script', 2, date('H:i:s', time()), 'end processing', 'script');
							else{
								toReport($report, 'end_script', 0, date('H:i:s', time()), "unexpected error! processing script failed.");
								toReport($report, 'end_script', 3, date('H:i:s', time()), 'remote script return: <br>'.$result);
							}
							if(!isset($report['end_script']['err'])){
								if(empty($mismatches))
									toReport($report, 'finish', 2, date('H:i:s', time()), 'script has not found', 'any mismatches');
								else{
									toReport($report, 'engine_update_archiving', 1, date('H:i:s', time()), 'begin archiving', 'engine update');
									if(!isset($mismatches['content']))
										$mismatches['content'] = array();
									if(!isset($mismatches['dir']))
										$mismatches['dir'] = array();
									if(!isset($mismatches['file']))
										$mismatches['file'] = array();
									if(($Archive = new Archive($ROOT_PATH.'/', $Path['temp_dir'], $Path['engine_update_archiv'], false))
									and $Archive->setFilesNames(array_merge($mismatches['content'], $mismatches['dir'], $mismatches['file']))
									and $Archive->createArchive()){
										toReport($report, 'engine_update_archiving', 1, date('H:i:s', time()), 'end archiving', 'engine update');
										if(send($report, $rc, $Trans_field['ftp'].$Path['ftp_upload_dir'], $Path['temp_dir'], $Path['engine_update_archiv'], 'engine update', true))
											toReport($report, 'finish', 3, '&nbsp;', 'Engine Update has been successfully sent to:<br>'.$Trans_field['server_name'].'<br>ftp://'.$this->PreparedTemplates['ftp_host'].'/%2f'.$this->PreparedTemplates['ftp_folder'].'<br>'.$Path['ftp_upload_dir'].'<br>'.$Path['engine_update_archiv']);
										else
											toReport($report, 'start', 0, date('H:i:s', time()), 'Engine Update sending failed. See below for details.');
									}
									else{
										if(is_object($Archive))
											foreach($Archive->errors as $value)
												toReport($report, 'engine_update_archive_error', 3, '', $value);
										toReport($report, 'start', 0, date('H:i:s', time()), 'Engine Update sending failed. See below for details.');
									}
								}
							}
							$this->Action->processEvent($this->SectionID, 'log', array('type' => 4,'entity' => 3,'event' => 16, 'value' => 'Engine synchronize on server: #'.$Trans_field['report_id'].' "'.$Trans_field['server_name'].'"'), $this);
						}
					}
					else
						toReport($report, 'start', 0, date('H:i:s', time()), 'Checking files & folders failed. See below for details.');
					(!isset($end_time)) and $end_time = currentTime();
					toReport($report, 'finish', 1, '<nobr>'.round($end_time-$begin_time,2).' sec.</nobr>', 'execution time');
					$report['finish'][] = "</table>";
				}
				$report['finish'][] = "</table>";
				foreach ($report as $key => $value)
					foreach ($value as $k => $v)
						echo $v;
				echo "<br><hr width='90%' style='color: navy;'><br>";
			}
		}
	}
	
	function databasesMatch (&$report, $signature_src, $Trans_field, $update = false) {
		if(!$signature_src) return false;
		$flag = true;
		$obj_src = new DataCl("dbname=".$signature_src['db_name']." user=".$signature_src['db_user']." host=".$signature_src['db_host']." port=".$signature_src['db_port']." password=".$signature_src['db_password']);
		$obj_dest = new DataCl("dbname=".$Trans_field['db_name']." user=".$Trans_field['db_user']." host=".$Trans_field['db_host']." port=".$Trans_field['db_port']." password=".$Trans_field['db_password']);
		$fl = $this->sequencesMatch ($report, $obj_src, $obj_dest, $Trans_field, $superfl_sequences, $update);
		$flag = ($flag ? $fl : $flag);
		$fl = $this->tablesMatch ($report, $obj_src, $obj_dest, $Trans_field, $superfl_tables, $update);
		$flag = ($flag ? $fl : $flag);
		$fl = $this->indexesMatch ($report, $obj_src, $obj_dest, $Trans_field, $superfl_indexes, $update);
		$flag = ($flag ? $fl : $flag);
//////// removing superfluous indexes
		if (count($superfl_indexes)){
			foreach ($superfl_indexes as $key => $value){
				if ($update){
					toReport($report, 'superfl_'.$key, 4, '&nbsp;', "superfluous index '".$key."'", "removing");
					$query = 'DROP INDEX "'.$key.'";';
					$obj_dest->query($query);
				}
				else{
					toReport($report, 'superfl_'.$key, 4, '&nbsp;', "superfluous index '".$key."'", "is founded");
					$flag = false;
				}
			}
		}
//////// removing superfluous tables
		if (count($superfl_tables)){
			foreach ($superfl_tables as $key => $value){
				if ($update){
					toReport($report, 'superfl_'.$key, 4, '&nbsp;', "superfluous table '".$key."'", "removing");
					$query = 'DROP TABLE "'.$key.'";';
					$obj_dest->query($query);
				}
				else{
					toReport($report, 'superfl_'.$key, 4, '&nbsp;', "superfluous table '".$key."'", "is founded");
					$flag = false;
				}
			}
		}
//////// removing superfluous sequences
		if (count($superfl_sequences)){
			foreach ($superfl_sequences as $key => $value){
				if ($update){
					toReport($report, 'superfl_'.$value, 4, '&nbsp;', "superfluous sequence '".$value."'", "removing");
					$query = 'DROP SEQUENCE "'.$value.'";';
					$obj_dest->query($query);
				}
				else{
					toReport($report, 'superfl_'.$value, 4, '&nbsp;', "superfluous sequence '".$value."'", "is founded");
					$flag = false;
				}
			}
		}
		return $flag;
	}
	
	function sequencesMatch (&$report, &$obj_src, &$obj_dest, $Trans_field, &$superfluous, $update){
		$flag = true;
		$sequences_src = $obj_src->SelectQuery("SELECT relname FROM pg_statio_all_sequences WHERE schemaname='public'");
		$sequences_dest = $obj_dest->SelectQuery("SELECT relname FROM pg_statio_all_sequences WHERE schemaname='public'");
		for ($i=0; $i<count($sequences_src); $i++)
			$sequences_src[$i] = $sequences_src[$i]['relname'];
		if (empty($sequences_src))
			$sequences_src = array();
		for ($i=0; $i<count($sequences_dest); $i++)
			$sequences_dest[$i] = $sequences_dest[$i]['relname'];
		if (empty($sequences_dest))
			$sequences_dest = array();
		foreach ($sequences_src as $key => $value){
			if (array_search($value, $sequences_dest) === false) {
				if ($update){
					toReport($report, $value, 4, date('H:i:s', time()), "sequence '".$value."'", "creating");
					$seq_src = $obj_src->SelectQuery('SELECT * FROM '.$value);
					$res = $obj_dest->query('CREATE SEQUENCE "'.$value.'" INCREMENT '.$seq_src[0]['increment_by'].' MINVALUE '.$seq_src[0]['min_value'].' MAXVALUE '.$seq_src[0]['max_value'].' START '.$seq_src[0]['last_value']. ' CACHE '.$seq_src[0]['cache_value'].($seq_src[0]['is_cycled']=='t' ? ' CYCLE ' : ' ').';');
				}
				else{
					toReport($report, $value, 4, date('H:i:s', time()), "sequence '".$value."'", "doesn't exist");
					$flag = false;
				}
				continue;
			}
			else
				toReport($report, $value, 1, date('H:i:s', time()), "sequence '".$value."'", 'exists');
			/*$seq_param_src = $obj_src->SelectQuery("SELECT last_value FROM ".$value);
			$seq_param_dest = $obj_dest->SelectQuery("SELECT last_value FROM ".$value);
			if ($seq_param_dest[0]['last_value'] != $seq_param_src[0]['last_value']){
				if ($update){
					toReport($report, $value, 4, '&nbsp;', "sequence '".$value."' last value", "changing");
					$res = $obj_dest->query("SELECT setval('".$value."', ".$seq_param_src[0]['last_value'].")");
					//toReport($report, $value, 3, '&nbsp;', '<font color=red><b>I don\'t think that you really want to change sequence\'s last value!</b></font>');
				}
				else{
					toReport($report, $value, 4, '&nbsp;', "sequence '".$value."' last value", "doesn't match");
					toReport($report, $value, 3, '', "Parameter value on current server: ".$seq_param_src[0]['last_value']."<br>Parameter value on '".$Trans_field['server_name']."' server: ".$seq_param_dest[0]['last_value']);
					$flag = false;
				}
			}*/
			unset($sequences_dest[array_search($value, $sequences_dest)]);
		}
		$superfluous = $sequences_dest;
		return $flag;
	}
	
	function tablesMatch (&$report, &$obj_src, &$obj_dest, $Trans_field, &$superfluous, $update){
		$flag = true;
		$tables_src = $obj_src->SelectQuery("SELECT relname, relid from pg_statio_all_tables WHERE schemaname='public'");
		$tables_dest = $obj_dest->SelectQuery("SELECT relname, relid from pg_statio_all_tables WHERE schemaname='public'");
		foreach ($tables_src as $key => $value){
			$tables_src[$value['relname']] = $value;
			unset($tables_src[$key]);
		}
		if (empty($tables_src))
			$tables_src = array();
		foreach ($tables_dest as $key => $value){
			$tables_dest[$value['relname']] = $value;
			unset($tables_dest[$key]);
		}
		if (empty($tables_dest))
			$tables_dest = array();
		foreach ($tables_src as $key => $value) {
			// getting all default values of columns from current server
			$def_src = $obj_src->SelectQuery('SELECT adnum, adsrc FROM pg_attrdef WHERE adrelid = '.$value['relid']);
			$temp = array();
			foreach ($def_src as $k => $v)
				$temp[$v['adnum']] = $v['adsrc'];
			$def_src = $temp;
			// getting all names of constraints with unique values from current server
			$unique_src = $obj_src->SelectQuery("SELECT conname FROM pg_constraint WHERE (contype = 'u') AND (conrelid = ".$value['relid'].")");
			if (!empty($unique_src)){
				foreach ($unique_src as $k => $v){
					// getting column's OID of constraint with unique value from current server
					$unique_col_oid_src = $obj_src->SelectQuery("SELECT indexrelid FROM pg_stat_all_indexes WHERE indexrelname = '".$v['conname']."'");
					// getting column's name of constraint with unique value from current server
					$unique_col_src = $obj_src->SelectQuery("SELECT attname FROM pg_attribute WHERE attrelid = ".$unique_col_oid_src[0]['indexrelid']);
					$unique_src[$unique_col_src[0]['attname']] = $v['conname'];
					unset($unique_src[$k]);
				}
			}
			// getting primary key name from current server
			$pkey_name_src = $obj_src->SelectQuery("SELECT conname FROM pg_constraint WHERE (contype = 'p') AND (conrelid = ".$value['relid'].")");
			if (!empty($pkey_name_src)){
				// getting OID of primary key column from current server
				$pkey_col_oid_src = $obj_src->SelectQuery("SELECT indexrelid FROM pg_stat_all_indexes WHERE indexrelname = '".$pkey_name_src[0]['conname']."'");
				// getting name of primary key column from current server
				$pkey_col_src = $obj_src->SelectQuery("SELECT attname FROM pg_attribute WHERE attrelid = ".$pkey_col_oid_src[0]['indexrelid']);
			}
			// getting all columns with those properties from current server
			$meta_data_src = pg_meta_data($obj_src->dbn, $key);
			// checking table existing / creating table
			if (array_key_exists($key, $tables_dest) === false) {
				if ($update){
					toReport($report, $key, 4, date('H:i:s', time()), "table '".$key."'", "creating");
					$query = 'CREATE TABLE "'.$key.'"';
					if (!empty($meta_data_src)){
						$query .= ' (';
						foreach ($meta_data_src as $k => $v){
							$query .= ' "'.$k.'" '.($v['type'] == 'bpchar' ? 'char' : $v['type']);
							$param_src = $obj_src->SelectQuery("SELECT atttypmod, attnotnull FROM pg_attribute WHERE (attname = '".$k."') AND (attrelid = ".$value['relid'].")");
							if ($param_src[0]['atttypmod'] != -1 && !(stristr($v['type'], 'char') === false))
								$query .= '('.($param_src[0]['atttypmod']-4).') ';
							if ($v['has default'])
								$query .= ' DEFAULT ('.stripslashes($def_src[$v['num']]).') ';
							if ($param_src[0]['attnotnull'] == 't')
								$query .= ' NOT NULL ';
							if (isset($unique_src[$k]))
								$query .= ' UNIQUE ';
							$query .= ' ,';
						}
						if (!empty($pkey_name_src))
							$query .= ' CONSTRAINT "'.$pkey_name_src[0]['conname'].'" PRIMARY KEY ("'.$pkey_col_src[0]['attname'].'") ,';
						$query = substr($query, 0, strlen($query) - 2).') ';
					}
					$query .= 'WITH OIDS;';
					//echo $query.'<br>';
					$obj_dest->query($query);
				}
				else{
					toReport($report, $key, 4, date('H:i:s', time()), "table '".$key."'", "doesn't exist");
					$flag = false;
				}
				continue;
			}
			else
				toReport($report, $key, 1, date('H:i:s', time()), "table '".$key."'", 'exists');
			// getting all default values of columns from remote server
			$def_dest = $obj_dest->SelectQuery('SELECT adnum, adsrc FROM pg_attrdef WHERE adrelid = '.$tables_dest[$key]['relid']);
			$temp = array();
			foreach ($def_dest as $k => $v)
				$temp[$v['adnum']] = $v['adsrc'];
			$def_dest = $temp;
			// getting all names of constraints with unique values from remote server
			$unique_dest = $obj_dest->SelectQuery("SELECT conname FROM pg_constraint WHERE (contype = 'u') AND (conrelid = ".$tables_dest[$key]['relid'].")");
			if (!empty($unique_dest)){
				foreach ($unique_dest as $k => $v){
					// getting column's OID of constraint with unique value from remote server
					$unique_col_oid_dest = $obj_dest->SelectQuery("SELECT indexrelid FROM pg_stat_all_indexes WHERE indexrelname = '".$v['conname']."'");
					// getting column's name of constraint with unique value from remote server
					$unique_col_dest = $obj_dest->SelectQuery("SELECT attname FROM pg_attribute WHERE attrelid = ".$unique_col_oid_dest[0]['indexrelid']);
					$unique_dest[$unique_col_dest[0]['attname']] = $v['conname'];
					unset($unique_dest[$k]);
				}
			}
			// getting primary key name from remote server
			$pkey_name_dest = $obj_dest->SelectQuery("SELECT conname FROM pg_constraint WHERE (contype = 'p') and (conrelid = ".$tables_dest[$key]['relid'].")");
			if (!empty($pkey_name_dest)){
				// getting OID of primary key column from current server
				$pkey_col_oid_dest = $obj_dest->SelectQuery("SELECT indexrelid FROM pg_stat_all_indexes WHERE indexrelname = '".$pkey_name_dest[0]['conname']."'");
				// getting name of primary key column from current server
				$pkey_col_dest = $obj_dest->SelectQuery("SELECT attname FROM pg_attribute WHERE attrelid = ".$pkey_col_oid_dest[0]['indexrelid']);
			}
			// checking / changing / creating / removing columns and those properties
			$meta_data_dest = pg_meta_data($obj_dest->dbn, $key);
			foreach ($meta_data_src as $meta_key => $meta_value) {
				if (array_key_exists($meta_key, $meta_data_dest)){
					toReport($report, $key, 1, '&nbsp;', "field '".$meta_key."' from table '".$key."'", "exists");
					// checking / changing / creating / removing default value
					if ($meta_value['has default']){
						if (isset($def_dest[$meta_data_dest[$meta_key]['num']])){
							if ($def_dest[$meta_data_dest[$meta_key]['num']] != $def_src[$meta_value['num']]){
								$array_src = explode("\'", $def_src[$meta_value['num']]);
								$array_dest = explode("\'", $def_dest[$meta_data_dest[$meta_key]['num']]);
								// if default value is nextval calling for sequence and difference is just 'public.' there is no mismatch else warning/changing
								if($array_src[0] == 'nextval(' && $array_dest[0] == 'nextval('){
									if (str_replace('public.', '', $def_dest[$meta_data_dest[$meta_key]['num']]) != str_replace('public.', '', $def_src[$meta_value['num']])){
										if ($update){
											toReport($report, $key, 4, '&nbsp;', "default value in field '".$meta_key."' from table '".$key."'", "changing");
											$query = 'ALTER TABLE "'.$key.'" ALTER COLUMN "'.$meta_key.'" SET DEFAULT ('.stripslashes($def_src[$meta_value['num']]).') ;';
											$obj_dest->query($query);
										}
										else{
											toReport($report, $key, 4, '&nbsp;', "default value in field '".$meta_key."' from table '".$key."'", "doesn't match");
											toReport($report, $key, 3, '', "Parameter value on current server: ".stripslashes($def_src[$meta_value['num']])."<br>Parameter value on '".$Trans_field['server_name']."' server: ".stripslashes($def_dest[$meta_data_dest[$meta_key]['num']]));
											$flag = false;
										}
									}
								}
								else{
									if ($update){
										toReport($report, $key, 4, '&nbsp;', "default value in field '".$meta_key."' from table '".$key."'", "changing");
										$query = 'ALTER TABLE "'.$key.'" ALTER COLUMN "'.$meta_key.'" SET DEFAULT ('.stripslashes($def_src[$meta_value['num']]).') ;';
										$obj_dest->query($query);
									}
									else{
										toReport($report, $key, 4, '&nbsp;', "default value in field '".$meta_key."' from table '".$key."'", "doesn't match");
										toReport($report, $key, 3, '', "Parameter value on current server: ".stripslashes($def_src[$meta_value['num']])."<br>Parameter value on '".$Trans_field['server_name']."' server: ".stripslashes($def_dest[$meta_data_dest[$meta_key]['num']]));
										$flag = false;
									}
								}
							}
						}
						else{
							if ($update){
								toReport($report, $key, 4, '&nbsp;', "default value in field '".$meta_key."' from table '".$key."'", "creating");
								$query = 'ALTER TABLE "'.$key.'" ALTER COLUMN "'.$meta_key.'" SET DEFAULT ('.stripslashes($def_src[$meta_value['num']]).') ;';
								$obj_dest->query($query);
							}
							else{
								toReport($report, $key, 4, '&nbsp;', "default value in field '".$meta_key."' from table '".$key."'", "doesn't exist");
								$flag = false;
							}
						}
					}
					else if ($meta_data_dest[$meta_key]['has default']){
						if ($update){
							toReport($report, $key, 4, '&nbsp;', "superfluous default value in field '".$meta_key."' from table '".$key."'", "removing");
							$query = 'ALTER TABLE "'.$key.'" ALTER COLUMN "'.$meta_key.'" DROP DEFAULT;';
							$obj_dest->query($query);
						}
						else{
							toReport($report, $key, 4, '&nbsp;', "default value in field '".$meta_key."' from table '".$key."'", "is superfluous");
							$flag = false;
						}
					}
					// checking / changing not null
					if ($meta_data_dest[$meta_key]['not null'] != $meta_value['not null']){
						if ($meta_value['not null']){
							if ($update){
								toReport($report, $key, 4, '&nbsp;', "not null in field '".$meta_key."' from table '".$key."'", "changing");
								$null_records = $obj_dest->SelectQuery('SELECT "'.$meta_key.'" FROM "'.$key.'" WHERE "'.$meta_key.'" IS NULL ;');
								if (!empty($null_records)){
									toReport($report, $key, 0, '&nbsp;', "field '".$meta_key."' from table '".$key."' has NULL values");
									toReport($report, $key, 3, '', 'Can\'t set \'NOT NULL\'.');
									unset($meta_data_dest[$meta_key]);
									continue;
								}
								$query = 'ALTER TABLE "'.$key.'" ALTER COLUMN "'.$meta_key.'" SET NOT NULL;';
								$obj_dest->query($query);
							}
							else{
								toReport($report, $key, 4, '&nbsp;', "not null in field '".$meta_key."' from table '".$key."'", "doesn't match");
								toReport($report, $key, 3, '', "Parameter value on current server: true<br>Parameter value on '".$Trans_field['server_name']."' server: false");
								$flag = false;
							}
						}
						else{
							if ($update){
								toReport($report, $key, 4, '&nbsp;', "not null in field '".$meta_key."' from table '".$key."'", "changing");
								$query = 'ALTER TABLE "'.$key.'" ALTER COLUMN "'.$meta_key.'" DROP NOT NULL;';
								$obj_dest->query($query);
							}
							else{
								toReport($report, $key, 4, '&nbsp;', "not null in field '".$meta_key."' from table '".$key."'", "doesn't match");
								toReport($report, $key, 3, '', "Parameter value on current server: false<br>Parameter value on '".$Trans_field['server_name']."' server: true");
								$flag = false;
							}
						}
					}
					// checking / changing unique
					if (isset($unique_src[$meta_key]) && !(isset($unique_dest[$meta_key]))){
						if ($update){
							toReport($report, $key, 4, '&nbsp;', "unique in field '".$meta_key."' from table '".$key."'", "changing");
							$duplicate_count = $obj_dest->SelectQuery('SELECT count("'.$meta_key.'") FROM "'.$key.'" GROUP BY "'.$meta_key.'" HAVING (count("'.$meta_key.'")>1) ;');
							if (!empty($duplicate_count)){
								toReport($report, $key, 0, '&nbsp;', "field '".$meta_key."' from table '".$key."' has duplicate values");
								toReport($report, $key, 3, '', 'Can\'t set \'UNIQUE\'.');
								unset($meta_data_dest[$meta_key]);
								continue;
							}
							$query = 'ALTER TABLE "'.$key.'" ADD UNIQUE ("'.$meta_key.'");';
							$obj_dest->query($query);
						}
						else{
							toReport($report, $key, 4, '&nbsp;', "unique in field '".$meta_key."' from table '".$key."'", "doesn't match");
							toReport($report, $key, 3, '', "Parameter value on current server: true<br>Parameter value on '".$Trans_field['server_name']."' server: false");
							$flag = false;
						}
					}
					else if(!(isset($unique_src[$meta_key])) && isset($unique_dest[$meta_key])){
						if ($update){
							toReport($report, $key, 4, '&nbsp;', "unique in field '".$meta_key."' from table '".$key."'", "changing");
							$query = 'ALTER TABLE "'.$key.'" DROP CONSTRAINT "'.$unique_dest[$meta_key].'" RESTRICT;';
							$obj_dest->query($query);
						}
						else{
							toReport($report, $key, 4, '&nbsp;', "unique in field '".$meta_key."' from table '".$key."'", "doesn't match");
							toReport($report, $key, 3, '', "Parameter value on current server: false<br>Parameter value on '".$Trans_field['server_name']."' server: true");
							$flag = false;
						}
					}
					unset($meta_data_dest[$meta_key]);
				}
				else{
					if ($update){
						toReport($report, $key, 4, '&nbsp;', "field '".$meta_key."' from table '".$key."'", "creating");
						$query = 'ALTER TABLE "'.$key.'" ADD COLUMN "'.$meta_key.'" ';
						$query .= ($meta_value['type'] == 'bpchar' ? 'char' : $meta_value['type']);
						$param_src = $obj_src->SelectQuery("SELECT atttypmod FROM pg_attribute WHERE (attname = '".$meta_key."') AND (attrelid = ".$value['relid'].")");
						if ($param_src[0]['atttypmod'] != -1 && !(stristr($meta_value['type'], 'char') === false))
							$query .= '('.($param_src[0]['atttypmod']-4).') ';
						$query .= (isset($unique_src[$meta_key]) ? ' UNIQUE ' : ' ');
						$query .= ';';
						$obj_dest->query($query);
						if ($meta_value['has default']){
							$query = 'ALTER TABLE "'.$key.'" ALTER COLUMN "'.$meta_key.'" SET DEFAULT ('.stripslashes($def_src[$meta_value['num']]).');';
							$obj_dest->query($query);
						}
						if ($meta_value['not null']){
							if (isset($unique_src[$meta_key])){
								if (isset($pkey_col_dest[0]['attname']))
									$all_records = $obj_dest->SelectQuery('SELECT '.$pkey_col_dest[0]['attname'].' FROM '.$key.' ;');
								else
									$all_records = $obj_dest->SelectQuery('SELECT * FROM '.$key.' ;');
								if (!(stristr($meta_value['type'], 'bool') === false) && (count($all_records)>2)){
									toReport($report, $key, 0, '&nbsp;', "field '".$meta_key."' from table '".$key."' is bool, unique and not null");
									toReport($report, $key, 3, '', 'Type \'BOOL\' can hold only 2 values: true, false. There are more than 2 records in table. Can\'t set \'not null\'.');
									continue;
								}
								$now_unix = getdate();
								$now_unix = $now_unix[0];
								$bool = false;
								foreach ($all_records as $num => $rec){
									if (!(stristr($meta_value['type'], 'date') === false)){
										$val = '\''.date('Y-m-d H:i:s', $now_unix).'\'';
										$now_unix = $now_unix - 86400;
									}
									else if (!(stristr($meta_value['type'], 'time') === false)){
										$val = '\''.date('Y-m-d H:i:s', $now_unix).'\'';
										$now_unix = $now_unix - 60;
									}
									else if (!(stristr($meta_value['type'], 'bool') === false)){
										$val = ($bool ? 'true' : 'false');
										$bool = ($bool ? false : true);
									}
									else if (!(stristr($meta_value['type'], 'char') === false) || !(stristr($meta_value['type'], 'text') === false))
										$val = '\''.$num.'\'';
									else
										$val = $num;
									$query = 'UPDATE "'.$key.'" SET "'.$meta_key.'" = '.$val.' WHERE ';
									foreach ($rec as $k => $v)
										$query .= ' ("'.$k.'" = '.$v.') AND ';
									$query = substr($query, 0, strlen($query)-5).' ;';
									$obj_dest->query($query);
								}
							}
							else{
								if ($meta_value['has default']){
									$query = 'UPDATE "'.$key.'" SET "'.$meta_key.'" = '.stripslashes($def_src[$meta_value['num']].' ;');
									$obj_dest->query($query);
								}
								else{
									if (!(stristr($meta_value['type'], 'date') === false) || !(stristr($meta_value['type'], 'time') === false))
										$val = 'now()';
									else if (!(stristr($meta_value['type'], 'char') === false) || !(stristr($meta_value['type'], 'text') === false))
										$val = '\' \'';
									else if (!(stristr($meta_value['type'], 'bool') === false))
										$val = 'false';
									else
										$val = 0;
									$query = 'UPDATE "'.$key.'" SET "'.$meta_key.'" = '.$val.';';
									$obj_dest->query($query);
								}
							}
							$query = 'ALTER TABLE "'.$key.'" ALTER COLUMN "'.$meta_key.'" SET NOT NULL;';
							$obj_dest->query($query);
						}
					}
					else{
						toReport($report, $key, 4, '&nbsp;', "field '".$meta_key."' from table '".$key."'", "doesn't exist");
						$flag = false;
					}
				}
			}
			// checking / changing / creating / removing primary key
			if (isset($pkey_name_src) && isset($pkey_name_dest)){
				if ($pkey_col_src[0]['attname'] != $pkey_col_dest[0]['attname']){
						if ($update){
							toReport($report, $key, 4, date('H:i:s', time()), "primary key '".$pkey_name_src[0]['conname']."' table '".$key."'", "changing");
							$query = 'ALTER TABLE "'.$key.'" DROP CONSTRAINT "'.$pkey_name_dest[0]['conname'].'" RESTRICT;';
							$obj_dest->query($query);
							$query = 'ALTER TABLE "'.$key.'" ADD CONSTRAINT "'.$pkey_name_src[0]['conname'].'" PRIMARY KEY ("'.$pkey_col_src[0]['attname'].'");';
							$obj_dest->query($query);
						}
						else{
							toReport($report, $key, 4, '&nbsp;', "primary key column from table '".$key."'", "doesn't match");
							toReport($report, $key, 3, '', "Parameter value on current server: ".$pkey_col_src[0]['attname']."<br>Parameter value on '".$Trans_field['server_name']."' server: ".$pkey_col_dest[0]['attname']);
						}
				}
			}
			else if (isset($pkey_name_src) && !isset($pkey_name_dest)){
				if ($update){
					toReport($report, $key, 4, date('H:i:s', time()), "primary key '".$pkey_name_src[0]['conname']."' table '".$key."'", "creating");
					$query = 'ALTER TABLE "'.$key.'" ADD CONSTRAINT "'.$pkey_name_src[0]['conname'].'" PRIMARY KEY ("'.$pkey_col_src[0]['attname'].'");';
					$obj_dest->query($query);
				}
				else
					toReport($report, $key, 4, '&nbsp;', "primary key from table '".$key."'", "doesn't exist");
			}
			foreach ($meta_data_dest as $meta_key => $meta_value){
				if ($update){
					toReport($report, $key, 4, '&nbsp;', "superfluous field '".$meta_key."' in  table '".$key."'", "removing");
					$query = 'ALTER TABLE "'.$key.'" DROP COLUMN "'.$meta_key.'";';
					$obj_dest->query($query);
				}
				else{
					toReport($report, $key, 4, '&nbsp;', "superfluous field '".$meta_key."' in  table '".$key."'", "is founded");
					$flag = false;
				}
			}
			unset($tables_dest[$key]);
		}
		$superfluous = $tables_dest;
		return $flag;
	}
	
	function indexesMatch (&$report, &$obj_src, &$obj_dest, $Trans_field, &$superfluous, $update){
		$flag = true;
		$indexes_src = $obj_src->SelectQuery('SELECT * FROM pg_indexes WHERE (schemaname = \'public\') AND (indexname NOT IN (SELECT conname FROM pg_constraint)) ;');
		$indexes_dest = $obj_dest->SelectQuery('SELECT * FROM pg_indexes WHERE (schemaname = \'public\') AND (indexname NOT IN (SELECT conname FROM pg_constraint)) ;');
		foreach ($indexes_src as $key => $value){
			$indexes_src[$value['indexname']] = $value;
			unset($indexes_src[$key]);
		}
		if (empty($indexes_src))
			$indexes_src = array();
		foreach ($indexes_dest as $key => $value){
			$indexes_dest[$value['indexname']] = $value;
			unset($indexes_dest[$key]);
		}
		if (empty($indexes_dest))
			$indexes_dest = array();
		foreach ($indexes_src as $key => $value){
			if  (array_key_exists($key, $indexes_dest) === false){
				if ($update){
					toReport($report, $key, 4, date('H:i:s', time()), "index '".$key."'", "creating");
					$obj_dest->query(stripslashes($value['indexdef']));
				}
				else{
					toReport($report, $key, 4, date('H:i:s', time()), "index '".$key."'", "doesn't exist");
					$flag = false;
				}
				continue;
			}
			else
				toReport($report, $key, 1, date('H:i:s', time()), "index '".$key."'", 'exists');
			foreach ($value as $param_key => $param_value){
				if (str_replace(array('"', "'"), '', stripslashes($indexes_dest[$key][$param_key])) != str_replace(array('"', "'"), '', stripslashes($param_value))){
					if ($update){
						toReport($report, $key, 4, date('H:i:s', time()), "index '".$key."'", "changing");
						$query = 'DROP INDEX "'.$key.'";';
						$obj_dest->query($query);
						$obj_dest->query(stripslashes($value['indexdef']));
						break;
					}
					else{
						toReport($report, $key, 4, '&nbsp;', "parameter '".$param_key."' in index '".$key."'", "doesn't match");
						toReport($report, $key, 3, '', "Parameter value on current server: ".stripslashes($param_value)."<br>Parameter value on '".$Trans_field['server_name']."' server: ".stripslashes($indexes_dest[$key][$param_key]));
						$flag = false;
					}
				}
			}
			unset($indexes_dest[$key]);
		}
		$superfluous = $indexes_dest;
		return $flag;
	}
	
	function sequencesValidate (&$report, $Trans_field, $update = false){
		$flag = true;
		$obj = new DataCl("dbname=".$Trans_field['db_name']." user=".$Trans_field['db_user']." host=".$Trans_field['db_host']." port=".$Trans_field['db_port']." password=".$Trans_field['db_password']);
		$tables = $obj->SelectQuery("SELECT relname, relid from pg_statio_all_tables WHERE schemaname='public'");
		foreach ($tables as $key => $value){
			$tables[$value['relname']] = $value;
			unset($tables[$key]);
		}
		foreach ($tables as $key => $value){
			$default_values = $obj->SelectQuery('SELECT adnum, adsrc FROM pg_attrdef WHERE adrelid = '.$value['relid']);
			if (!empty($default_values)){
				foreach($default_values as $k => $v){
					if (strpos(rtrim(ltrim($v['adsrc'])), 'nextval') === 0){
						$sequence_name = explode("\'", $v['adsrc']);
						$column_name = $obj->SelectQuery('SELECT attname FROM pg_attribute WHERE (attrelid = '.$value['relid'].') AND (attnum = '.$v['adnum'].')');
						$max_value = $obj->SelectQuery('SELECT max('.$column_name[0]['attname'].') as max_value FROM '.$key);
						if (empty($max_value[0]['max_value']))
							$max_value[0]['max_value'] = 0;
						$sequence = $obj->SelectQuery('SELECT last_value FROM '.$sequence_name[1]);
						if ($max_value[0]['max_value'] >= $sequence[0]['last_value']+1){
							if ($update){
								toReport($report, $key, 4, date('H:i:s', time()), "sequence '".$sequence_name[1]."' last value", "changing");
								$obj->query("SELECT setval('".$sequence_name[1]."', ".($max_value[0]['max_value']).")");
								$flag = false;
							}
							else{
								toReport($report, $key, 4, '&nbsp;', "sequence '".$sequence_name[1]."' last value", "is invalid");
								toReport($report, $key, 3, '', "Table: '".$key."'<br>Column '".$column_name[0]['attname']."' max value: ".$max_value[0]['max_value']."<br>Sequence '".$sequence_name[1]."' last value: ".$sequence[0]['last_value']);
								$flag = false;
							}
						}
					}
				}
			}
		}
		return $flag;
	}
}
?>