<?
/*
 * Copyright (c) 2000-2001, Patrick Duplouy
 * Copyright (c) 2001-2003, Cartel Securite et Patrick Duplouy
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * -Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 * -Redistributions in binary form must reproduce the above copyright notice,
 *  this list of conditions and the following disclaimer in the documentation
 *  and/or other materials provided with the distribution.
 * -Neither the name of the theWSG nor the names of its
 *  contributors may be used to endorse or promote products derived from this
 *  software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 */

	//
	// All is snippet, so only object in library is the loader
	// for snippet
	//
	// Current implementation is tested on 7.0.3 and I hope it work
	// with upper version
	//
	// Define a class, snippet, for loading snippets object
	// This class stop loading loop with an array of loaded snippet
	// base on id. This array can be very large, so take care.
	//
	class MOTOR_loader_for_postgres {
		var $loaded_snippet = array();
		var $connected = false;
		var $host = "localhost";
		var $port = 5432;
		var $socket = "";
		var $tty = "";
		var $options = "";
		var $user = "nobody";
		var $password = "";
		var $dbname = "";
		var $debug = 0;
		var $load_error = 0;

		// Setting internal object values
		function set_host($value) {
			if ($this->debug) {
				echo "MOTOR_loader: moving host from '$this->host' to '$value'.<br>\n";
				}
			$this->host = $value;
			}

		function set_port($value) {
			if ($this->debug) {
				echo "MOTOR_loader: moving port from '$this->port' to '$value'.<br>\n";
				}
			$this->port = $value;
			}

		function set_socket($value) {
			if ($this->debug) {
				echo "MOTOR_loader: moving socket from '$this->socket' to '$value'.<br>\n";
				}
			$this->socket = $value;
			}

		function set_tty($value) {
			if ($this->debug) {
				echo "MOTOR_loader: moving tty from '$this->tty' to '$value'.<br>\n";
				}
			$this->tty = $value;
			}

		function set_options($value) {
			if ($this->debug) {
				echo "MOTOR_loader: moving options from '$this->options' to '$value'.<br>\n";
				}
			$this->options = $value;
			}

		function set_dbname($value) {
			if ($this->debug) {
				echo "MOTOR_loader: moving dbname from '$this->dbname' to '$value'.<br>\n";
				}
			$this->dbname = $value;
			}

		function set_user($value) {
			if ($this->debug) {
				echo "MOTOR_loader: moving user from '$this->user' to '$value'.<br>\n";
				}
			$this->user = $value;
			}

		function set_password($value) {
			// A secret one, no from debug
			if ($this->debug) {
				echo "MOTOR_loader: moving user from '********' to '$value'.<br>\n";
				}
			$this->password = $value;
			}

		function set_debug($value) {
			if ($this->debug) {
				echo "MOTOR_loader: Setting debug to $value.<br>\n";
				}
			$this->debug = $value;
			}

		function set_production($value) {
			$reporting = E_ERROR + E_WARNING + E_CORE_ERROR + E_CORE_WARNING;
			if ($value) {
				$reporting = 0;
				}
			error_reporting($reporting);
			}

		// Getting internal object values
		function get_host() {
			if ($this->debug) {
				echo "MOTOR_loader: getting host: '$this->host'.<br>\n";
				}
			 return $this->host; }

		function get_port() {
			if ($this->debug) {
				echo "MOTOR_loader: getting port: '$this->port'.<br>\n";
				}
			 return $this->port; }

		function get_socket() {
			if ($this->debug) {
				echo "MOTOR_loader: getting socket: '$this->socket'.<br>\n";
				}
			 return $this->socket; }

		function get_tty() {
			if ($this->debug) {
				echo "MOTOR_loader: getting tty: '$this->tty'.<br>\n";
				}
			 return $this->tty; }

		function get_options() {
			if ($this->debug) {
				echo "MOTOR_loader: getting options: '$this->options'.<br>\n";
				}
			 return $this->options; }

		function get_dbname() {
			if ($this->debug) {
				echo "MOTOR_loader: getting dbname: '$this->dbname'.<br>\n";
				}
			 return $this->dbname; }

		function get_user() {
			if ($this->debug) {
				echo "MOTOR_loader: getting user: '$this->user'.<br>\n";
				}
			 return $this->user; }

		function get_debug() {
			if ($this->debug) {
				echo "MOTOR_loader: getting debug: '$this->debug'.<br>\n";
				}
			 return $this->debug; }

		function get_connected() {
			if ($this->debug) {
				echo "MOTOR_loader: getting connected: '$this->connected'.<br>\n";
				}
			 return $this->connected; }

		function get_error() {
			if ($this->debug) {
				echo "MOTOR_loader: getting error: '" . pg_errormessage($this->connected) . "'.<br>\n";
				}
			return pg_errormessage($this->connected); }

		// I'm not sure to give easyly this informations
		// function get_password() { return $this->password; }

		function connect() {
			$commande = "";
			if ($this->host != "") { $commande .= "host=$this->host "; }
			if ($this->port != "") { $commande .= "port=$this->port "; }
			if ($this->tty != "") { $commande .= "tty=$this->tty "; }
			if ($this->options != "") { $commande .= "options=$this->options "; }
			if ($this->user != "") { $commande .= "user=$this->user "; }
			if ($this->dbname != "") { $commande .= "dbname=$this->dbname "; }
			if ($this->debug) {
				// don't display password
				echo "MOTOR_loader: connect: '$commande'. (sorry, you can't have information about password) ...<br>\n";
				}
			if ($this->password != "") { $commande .= "password=$this->password "; }
			$this->connected = pg_connect($commande);
			return $this->connected;
			}

		function close() {
			$closed = pg_close($this->connected);
			if ($closed) {
				$this->connected = FALSE;
				if ($this->debug) {
					echo "MOTOR_loader: connection closed.<br>\n";
					}
				}
			else if ($this->debug) {
				echo "MOTOR_loader: can't close this connection.<br>\n";
				}
			return($closed);
			}

		// TODO: version
		// version use a table 'gestion' with a timestamp for the
		// last update (insert, update, delete) of the tables. We
		// will use this version for updating distributed functions

		// The SQL centralized access
		// Using this point, offer sample modification of
		// the storage backend (all access is from motor
		// TODO: LDAP backend (use $options)

		function accessDATA($query,&$result,&$nombre,$options = "") {
			if (!$this->connected) {
				if (!$this->connect()) {
					return $this->connected;
					}
				}
			$result = array();
			$nombre = 0;
			if (($resultQuery = pg_exec($this->connected,$query)) == FALSE) {
				return FALSE;
				}
			if (preg_match("/Resource/i",$resultQuery,$ignore)) {
				$nombre = pg_numrows($resultQuery);
				for ($i = 0; $i < $nombre; ++$i) {
					$result[$i] = pg_fetch_array($resultQuery,$i);
					}
				pg_freeresult($resultQuery);
				}
			return TRUE;
			}

		//////////////////////////////////////////////////////////
		// This part is specific to snippet 
		function internal_load($snippet) {
			if ($this->loaded_snippet[$snippet]) {
				return TRUE;
				}
			$this->loaded_snippet[$snippet] = 1;
			if ($this->accessDATA("select code, depend from snippet where name='$snippet' and language='php'",$result,$nombre) == FALSE) {
				if ($this->debug) {
					echo "MOTOR_loader: can't load '$snippet' for 'php'<br>\n";
					}
				++$this->load_error;
				return FALSE;
				}
			if ($nombre > 1) {
				if ($this->debug) {
					echo "MOTOR_loader: too much rows.<br>\n";
					}
				++$this->load_error;
				return FALSE;
				}
			if (!$nombre) {
				if ($this->debug) {
					echo "MOTOR_loader: missing snippet '$snippet'.<br>\n";
					}
				++$this->load_error;
				return FALSE;
				}
			$arr = $result[0];
			$needed = explode(",",$arr["depend"]);
			$number = count($needed);
			for ($i = 0; $i < $number; ++$i) {
				$which = trim($needed[$i]);
				if ($which) {
					$this->internal_load($which);
					}
				}
			$code = "?>" . $arr["code"] . "<?";
			eval($code);
			if ($this->debug) {
				echo "MOTOR_loader: snippet '$snippet' Ok.<br>\n";
				}
			return TRUE;
			}

		function get($snippet,$lang,&$code,&$error) {
			$error = "";
			if (!$this->connected) {
				if (!$this->connect()) {
					return $this->connected;
					}
				}
			if ($this->accessDATA("select code, depend from snippet where name='$snippet' and language='$lang'",$result,$nombre) == FALSE) {
				if ($this->debug) {
					echo "MOTOR_loader: can't get '$snippet' for 'php'<br>\n";
					}
				++$this->load_error;
				return FALSE;
				}
			if ($nombre > 1) {
				if ($this->debug) {
					echo "MOTOR_loader: too much rows.<br>\n";
					}
				++$this->load_error;
				return FALSE;
				}
			if (!$nombre) {
				if ($this->debug) {
					echo "MOTOR_loader: missing snippet '$snippet'.<br>\n";
					}
				++$this->load_error;
				return FALSE;
				}
			$arr = $result[0];
			$code = $arr["code"];
			if ($this->debug) {
				echo "MOTOR_loader: snippet '$snippet' Ok.<br>\n";
				}
			return TRUE;
			}

		function load($snippet,&$error) {
			if ($this->debug) {
				echo "MOTOR_loader: loading $snippet...<br>\n";
				}
			if (!$this->connected) {
				if (!$this->connect()) {
					return $this->connected;
					}
				}
			$this->load_error = 0;
			$this->internal_load($snippet);
			if ($this->load_error) {
				if ($this->debug) {
					echo "MOTOR_loader: found $this->load_error error(s).<br>\n";
					}
				$error = "MOTOR_loader: There are $this->load_error error(s) during snippet loading.<br>\n";
				return FALSE;
				}
			if ($this->debug) {
				echo "MOTOR_LOADER: snippet : $snippet is loaded.<br>\n";
				}
			return(TRUE);
			}

		function loadTree($root,$lang,&$result,&$nombre) {
			// This functions load a complete subtree from
			// the database (principal use: template)
			if ($this->debug) {
				echo "MOTOR_loader: loading tree...<br>\n";
				}
			$result = array();
			$nombre = 0;
			if (!$this->connected) {
				if (!$this->connect()) {
					return $this->connected;
					}
				}
			// Get root
			if ($this->accessDATA("select name, code from snippet where name='$root' and language='$lang'",$reponse,$counter) == FALSE) {
				if ($this->debug) {
					echo "MOTOR_loader: can't get root...<br>\n";
					}
				return FALSE;
				}
			$row = $reponse[0];
			$result[$nombre] = $row;
			++$nombre;
			///////////////////////////////////
			// Loop until parent array is empty
			$parent[0] = $row["name"];
			while(($nbr = count($parent)) > 0) {
				$temp = $parent;
				unset($parent);
				$parent = array();
				$j = 0;
				for ($i = 0; $i < $nbr; ++$i) {
					if ($deja_lu[$temp[$i]]) {
						continue;
						}
					if ($this->accessDATA("select name, code from snippet where up='$temp[$i]' and language='$lang'",$reponse,$counter) == FALSE) {
						if ($this->debug) {
							echo "MOTOR_loader: can't get leaf '" . $temp[$i] . "'<br>\n";
							}
						unset($result);
						$result = array();
						$nombre = 0;
						return FALSE;
						}
					for ($k = 0; $k < $counter; ++$k) {
						$row = $reponse[$k];
						$parent[$j] = $row["name"];
						++$j;
						$result[$nombre] = $row;
						++$nombre;
						}
					$deja_lu[$temp[$i]] = 1;
					}
				unset($temp);
				}
			return TRUE;
			}

		function openTransaction() {
			if (!$this->connected) {
				if (!$this->connect()) {
					return $this->connected;
					}
				}
			if ($this->accessDATA("begin transaction",$reponse,$counter) == FALSE) {
				if ($this->debug) {
					echo "MOTOR_loader: begin transaction...<br>\n";
					}
				return FALSE;
				}
			return TRUE;
			}

		function commitTransaction() {
			if (!$this->connected) {
				if (!$this->connect()) {
					return $this->connected;
					}
				}
			if ($this->accessDATA("commit transaction",$reponse,$counter) == FALSE) {
				if ($this->debug) {
					echo "MOTOR_loader: commit transaction<br>\n";
					}
				return FALSE;
				}
			return TRUE;
			}

		function rollbackTransaction() {
			if (!$this->connected) {
				if (!$this->connect()) {
					return $this->connected;
					}
				}
			if ($this->accessDATA("rollback",$reponse,$counter) == FALSE) {
				if ($this->debug) {
					echo "MOTOR_loader: rollback transaction<br>\n";
					}
				return FALSE;
				}
			return TRUE;
			}

		function getSpecific($which) {
			if ($which == 'timestamp') {
				return(___theTIMESTAMP___);
				}
			return '';
			}
		}
$theMotorClass = 'MOTOR_loader_for_postgres';
// Don't add new line after PHP tag
?>
