<?php

require_once 'MDB.php';
require_once 'include/i18n.php';

class IRMDB
{
	var $dsn = NULL;
	
	var $_dbh = NULL;
	
	function IRMDB($dsn, $socket = NULL)
	{
		$this->dsn = $dsn;
		
		if ($socket !== NULL)
		{
			ini_set('mysql.default_socket', $socket);
		}
		
		$this->_dbh = MDB::Connect($dsn);
		
		if (MDB::isError($this->_dbh))
		{
			if (ini_get('display_errors') == 0)
			{
				echo "<b>"._('FATAL')."</b>: "
					.$this->_dbh->getMessage()."\n"
					.$this->_dbh->getUserInfo();
			}

			trigger_error(sprintf(_("Could not connect to %s: %s\n%s"),
						$this->dsn,
						$this->_dbh->getMessage(),
						$this->_dbh->getUserInfo()),
					E_USER_ERROR);
		}

		$this->_dbh->setErrorHandling(PEAR_ERROR_CALLBACK, 'DBDie');
		$this->_dbh->setFetchMode(MDB_FETCHMODE_ASSOC);
		$this->_dbh->setOption('seqname_format', '%s');
	}

	/** Create an insert query and run it on the database.
	 * Similar in concept to the autoExecute method in PEAR::DB --
	 * take an assoc. array of field => value pairs in $values, and create
	 * an INSERT INTO $table query from that.
	 */
	function InsertQuery($table, $values)
	{
		// The list of fields in the insert query
		$fields = array();
		
		// The quoted values ready for insertion
		$quoted = array();
		
		foreach ($values as $f => $v)
		{
			$fields[] = $f;
			$quoted[] = $this->_dbh->getTextValue($v);
		}
		
		$fields = join(',', $fields);
		$quoted = join(',', $quoted);
		
		$q = "INSERT INTO $table ($fields) VALUES ($quoted)";
		
		$this->query($q);
	}
	
	/** Create an update query and run it on the database.
	 * Similar in concept to the autoExecute method in PEAR::DB --
	 * take an assoc. array of field => value pairs in $values, and create
	 * an UPDATE $table query from that.
	 * Any criteria to select which records to update should be specified
	 * in $where.
	 */
	function UpdateQuery($table, $values, $where = NULL)
	{
		// The list of fields in the query
		$fields = array();
		
		foreach ($values as $f => $v)
		{
			$fields[] = "$f=".$this->_dbh->getTextValue($v);
		}
		
		$fields = join(',', $fields);
		
		if ($where !== NULL)
		{
			$where = "WHERE $where";
		}

		$q = "UPDATE $table SET $fields $where";
		
		$this->query($q);
	}
	
	function nextId()
	{
		$args = func_get_args();
		return call_user_func_array(array(&$this->_dbh, 'nextId'), $args);
	}
	
	function query()
	{
		$args = func_get_args();
		return call_user_func_array(array(&$this->_dbh, 'query'), $args);
	}
	
	function getOne()
	{
		$args = func_get_args();
		return call_user_func_array(array(&$this->_dbh, 'getOne'), $args);
	}
	
	function getRow()
	{
		$args = func_get_args();
		return call_user_func_array(array(&$this->_dbh, 'getRow'), $args);
	}
	
	function getCol()
	{
		$args = func_get_args();
		return call_user_func_array(array(&$this->_dbh, 'getCol'), $args);
	}
	
	function getAll()
	{
		$args = func_get_args();
		return call_user_func_array(array(&$this->_dbh, 'getAll'), $args);
	}
	
	function getTextValue()
	{
		$args = func_get_args();
		return call_user_func_array(array(&$this->_dbh, 'getTextValue'), $args);
	}
	
	function setErrorHandling()
	{
		$args = func_get_args();
		return call_user_func_array(array(&$this->_dbh, 'setErrorHandling'), $args);
	}

	function pushErrorHandling()
	{
		$args = func_get_args();
		return call_user_func_array(array(&$this->_dbh, 'pushErrorHandling'), $args);
	}

	function popErrorHandling()
	{
		$args = func_get_args();
		return call_user_func_array(array(&$this->_dbh, 'popErrorHandling'), $args);
	}

	function autoCommit()
	{
		$args = func_get_args();
		return call_user_func_array(array(&$this->_dbh, 'autoCommit'), $args);
	}

	function commit()
	{
		$args = func_get_args();
		return call_user_func_array(array(&$this->_dbh, 'commit'), $args);
	}

	function disconnect()
	{
		$args = func_get_args();
		return call_user_func_array(array(&$this->_dbh, 'disconnect'), $args);
		
		$this->_dbh = NULL;
	}

	/* Testing only: remove all tables from the database
	 * Not something you want to try at home, kids.
	 *
	 * This method has a kink -- since a table may fail to drop
	 * because of key constraints, we need to keep dropping tables over
	 * and over until they're all gone or we can't drop any more.  This
	 * problem makes this method about an order of magnitude more complex
	 * than it otherwise would need to be.
	 */
	function _EmptyDatabase()
	{
		$tbls = $this->_dbh->getCol('SHOW TABLES');

		$continue = true;
		$this->pushErrorHandling(PEAR_ERROR_RETURN);
		while ($continue)
		{
			$continue = false;
			$faileds = array();
			
			foreach ($tbls as $t)
			{
				$err = $this->_dbh->query("DROP TABLE $t");
				if (MDB::isError($err))
				{
					$faileds[] = $t;
				}
				else
				{
					$continue = true;
				}
			}
			
			$tbls = $faileds;
		}

		$this->popErrorHandling();

		if (count($tbls))
		{
			// Didn't drop all tables
			trigger_error("Failed to drop the following tables: ".join(' ', $tbls), E_USER_ERROR);
		}
	}
	
	/** Initialise a (presumably) empty database
	 */
	function InitDatabase()
	{
		global $INSTALL;
		require_once 'database/install.php';
		foreach ($INSTALL as $q)
		{
			$this->_dbh->query($q);
		}
	}
}

function DBDie($err)
{
	$msg = sprintf(_("Database Error: %s (%s)"),$err->getMessage(),$err->getUserInfo());
	
	trigger_error($msg, E_USER_ERROR);
}
