<?php

class Database {
	private $conf;
	private $mysql;
	private $db_prefix;

	public function __construct($conf_file) {
		$this->conf = $conf_file;
	}
	
	// Low-Level SQL functions /////////////////////////////////////////////
	
	private function mysql() {
		if (!isset($this->mysql)) {
			$this->mysql_init();
		}
		return $this->mysql;
	}	
	private function mysql_init() {
		global $db_config;
		require($this->conf);
		$this->mysql = mysql_connect($db_config['host'],
		                              $db_config['user'],
		                              $db_config['password']);
		mysql_set_charset($db_config['charset'], $this->mysql);
		mysql_select_db($db_config['name'], $this->mysql);
		$this->db_prefix = $db_config['prefix'];
		unset($db_config);
	}
	private function mysql_table($table_name) {
		$mysql = $this->mysql();
		$prefix = $this->db_prefix;
		return $prefix.mysql_real_escape_string($table_name, $mysql);
	}
	private function mysql_escape($string) {
		$mysql = $this->mysql();
		return mysql_real_escape_string($string, $mysql);
	}
	private function mysql_query($query) {
		$mysql = $this->mysql();
		return mysql_query($query, $mysql);
	}
	public function mysql_error() {
		$mysql = $this->mysql();
		return mysql_error($mysql);
	}
	
	// High-Level SQL functions ////////////////////////////////////////////
	
	// The 'auth' table
	
	public function getUID($username) {
		$t = $this->mysql_table('auth');
		$v = $this->mysql_escape($username);
		$query =
			"SELECT *        \n".
			"FROM $t         \n".
			"WHERE name='$v' ;";
		$q = $this->mysql_query($query);
		$user = mysql_fetch_array($q);
		if (isset($user['uid'])) {
			return (int)$user['uid'];
		} else {
			return false;
		}
	}
	public function getUsername($uid) {
		if (!is_int($uid)) return false;
		$t = $this->mysql_table('auth');
		$query =
			"SELECT *      \n".
			"FROM $t       \n".
			"WHERE uid=$uid ;";
		$q = $this->mysql_query($query);
		$user = mysql_fetch_array($q);
		if (isset($user['name'])) {
			return $user['name'];
		} else {
			return false;
		}
	}
	public function setUsername($uid, $username) {
		if (!is_int($uid)) return false;
		if ($this->getUID($username) !== false) {
			return false;
		}
		$table = $this->mysql_table('auth');
		$name = $this->mysql_escape($username);
		$query =
			"UPDATE $table    \n".
			"SET name='$name' \n".
			"WHERE uid=$uid   ;";
		$q = $this->mysql_query($query);
		return ($q?true:false);
	}
	public function getPasswordHash($uid) {
		if (!is_int($uid)) return false;

		$table = $this->mysql_table('auth');
		$query =
			"SELECT *       \n".
			"FROM $table    \n".
			"WHERE uid=$uid ;";
		$q = $this->mysql_query($query);
		$user = mysql_fetch_array($q);
		if (isset($user['hash'])) {
			return $user['hash'];
		} else {
			return false;
		}
	}
	public function setPassword($uid, $password) {
		if (!is_int($uid)) return false;
		$table = $this->mysql_table('auth');
		
		global $mm;
		$hasher = $mm->hasher();
		@$hash = $hasher->HashPassword($password);
		$query =
			"UPDATE $table    \n".
			"SET hash='$hash' \n".
			"WHERE uid=$uid   ;";
		$q = $this->mysql_query($query);
		return ($q?true:false);
	}
	public function addUser($username, $password) {
		$user_exits = $this->getUID($username);
		if ($user_exists) {
			return false;
		}
		
		global $mm;
		
		$table = $this->mysql_table('auth');
		$user = $this->mysql_escape($username);
		$hasher = $mm->hasher();
		@$hash = $hasher->HashPassword($password);
		$status = 0;
		$query =
			"INSERT INTO $table (   name,   hash ,  status) \n".
			"VALUES             ('$user', '$hash', $status) ;";
		$this->mysql_query($query);
		$uid = $this->getUID($username);
		return $uid;
	}
	public function getStatus($uid) {
		if (!is_int($uid)) return false;
		$table = $this->mysql_table('auth');
		$query =
			"SELECT *       \n".
			"FROM $table    \n".
			"WHERE uid=$uid ;";
		$q = $this->mysql_query($query);
		$user = mysql_fetch_array($q);
		if (isset($user['status'])) {
			return (int)$user['status'];
		} else {
			return false;
		}
	}
	public function setStatus($uid, $status) {
		if (!is_int($uid)) return false;
		$table = $this->mysql_table('auth');
		$s = $this->mysql_escape($status);
		$query =
			"UPDATE $table  \n".
			"SET status=$s  \n".
			"WHERE uid=$uid ;";
		$q = $this->mysql_query($query);
		return ($q?true:false);
	}
	public function countUsers() {
		$table = $this->mysql_table('auth');
		$query = "SELECT COUNT(*) FROM $table;";
		$q = $this->mysql_query($query);
		$row = mysql_fetch_array($q);
		$count = $row[0];
		return $count;
	}
	public function listGroups() {
		$table = $this->mysql_table('auth');
		$query =
			"SELECT uid     \n".
			"FROM $table    \n".
			"WHERE status=3 ;";
		$q = $this->mysql_query($query);
		$groups = array();
		while (($row = mysql_fetch_array($q)) !==false) {
			$groups[] = (int)$row[0];
		}
		return $groups;
	}
	public function listGroupNames() {
		$table = $this->mysql_table('auth');
		$query =
			"SELECT name    \n".
			"FROM $table    \n".
			"WHERE status=3 ;";
		$q = $this->mysql_query($query);
		$groups = array();
		while (($row = mysql_fetch_array($q)) !==false) {
			$groups[] = $row[0].'';
		}
		return $groups;
	}
	public function listUsers() {
		$table = $this->mysql_table('auth');
		$query =
			"SELECT uid       \n".
			"FROM $table      \n".
			"WHERE status < 3 ;";
		$q = $this->mysql_query($query);
		$users = array();
		while (($row = mysql_fetch_array($q)) !==false) {
			$users[] = (int)$row[0];
		}
		return $users;
	}
	
	// The 'users' table
	
	public function findUser($setting, $value) {
		$t = $this->mysql_table('users');
		$k = $this->mysql_escape($setting);
		$v = $this->mysql_escape($value);
		$query =
			"SELECT *                 \n".
			"FROM $t                  \n".
			"WHERE     k =      '$k'  \n".
			"AND UPPER(v)=UPPER('$v') ;";
		$q = $this->mysql_query($query);
		$user = mysql_fetch_array($q);
		if (isset($user['uid'])) {
			return $user['uid'];
		} else {
			return false;
		}
	}
	public function getUserConf($uid, $setting) {
		if (!is_int($uid)) return false;
		$t = $this->mysql_table('users');
		$k = $this->mysql_escape($setting);
		$query =
			"SELECT *     \n".
			"FROM $t      \n".
			"WHERE k='$k' \n".
			"AND uid=$uid ;";
		$q = $this->mysql_query($query);
		$row = mysql_fetch_array($q);
		if (isset($row['v'])) {
			return $row['v'];
		} else {
			return false;
		}
	}
	public function setUserConf($uid, $setting, $value) {
		if (!is_int($uid)) return false;
		$isset = ($this->getUserConf($uid, $setting) !== false);
		$t = $this->mysql_table('users');
		$k = $this->mysql_escape($setting);
		$v = $this->mysql_escape($value);
		if ($isset) {
			$query =
				"UPDATE $t      \n".
				"SET   v = '$v' \n".
				"WHERE k = '$k' \n".
				"AND uid = $uid ;";
		} else {
			$query =
				"INSERT INTO $t ( uid,   k ,   v ) \n".
				"VALUES         ($uid, '$k', '$v') ;";
		}
		$q = $this->mysql_query($query);
		return ($q?true:false);
	}
	public function getUsersInGroup($groupname) {
		$table = $this->mysql_table('users');
		$group = $this->mysql_escape($groupname);
		$query = 
			"SELECT uid              \n".
			"FROM $table             \n".
			"WHERE k='groups'        \n".
			"AND v LIKE '%,$group,%' ;";
		$q = $this->mysql_query($query);
		$users = array();
		while (($row = mysql_fetch_array($q)) !==false) {
			$users[] = $row[0];
		}
		return $users;
	}
	
	// The 'plugins' table
	
	public function getPluginConf($plugin, $key) {
		$t = $this->mysql_table('plugins');
		$p = $this->mysql_escape($plugin);
		$k = $this->mysql_escape($key);
		$query =
			"SELECT *        \n".
			"FROM $t         \n".
			"WHERE k='$k'    \n".
			"AND plugin='$p' ;";
		$q = $this->mysql_query($query);
		$row = mysql_fetch_array($q);
		if (isset($row['v'])) {
			return $row['v'];
		} else {
			return false;
		}
	}
	public function setPluginConf($plugin, $key, $value) {
		$isset = ($this->getPluginConf($plugin, $key) !== false);
		$t = $this->mysql_table('plugins');
		$p = $this->mysql_escape($plugin);
		$k = $this->mysql_escape($key);
		$v = $this->mysql_escape($value);
		if ($isset) {
			$query =
				"UPDATE $t         \n".
				"SET   v = '$v'    \n".
				"WHERE k = '$k'    \n".
				"AND plugin = '$p' ;";
		} else {
			$query =
				"INSERT INTO $t (plugin,   k ,   v ) \n".
				"VALUES         ('$p'  , '$k', '$v') ;";
		}
		$q = $this->mysql_query($query);
		return ($q?true:false);		
	}
	
	// The 'conf' table
	
	public function getSysConf($key) {
		$t = $this->mysql_table('conf');
		$k = $this->mysql_escape($key);
		$query =
			"SELECT *     \n".
			"FROM $t      \n".
			"WHERE k='$k' ;";
		$q = $this->mysql_query($query);
		$row = mysql_fetch_array($q);
		if (isset($row['v'])) {
			return $row['v'];
		} else {
			return false;
		}
	}
	public function setSysConf($key, $value) {
		$isset = ($this->getSysConf($key) !== false);
		$t = $this->mysql_table('conf');
		$k = $this->mysql_escape($key);
		$v = $this->mysql_escape($value);
		if ($isset) {
			$query =
				"UPDATE $t      \n".
				"SET   v = '$v' \n".
				"WHERE k = '$k' ;";
		} else {
			$query =
				"INSERT INTO $t (  k ,   v ) \n".
				"VALUES         ('$k', '$v') ;";
		}
		$q = $this->mysql_query($query);
		return ($q?true:false);
	}

	/**
	 * Strip out empty group names and duplicates, sort.
	 */
	private static function sanitizeArray($in) {
		$out = array();
		foreach ($in as $item) {
			if (($item !== '')&&(!in_array($item, $out))) {
				$out[] = $item;
			}
		}
		natsort($out);
		return $out;
	}
	/**
	 * Translate an array into a value suitable to be stored into a
	 * key-value store in the database.
	 */
	public static function arrayToValue($list) {
		$out_list = self::sanitizeArray($list);
		return ','.implode(',', $out_list).',';
	}
	/**
	 * Translate a value from arrayToValue() back into an array.
	 */
	public static function valueToArray($value) {
		$raw_list = explode(',', $value);
		$out_list = self::sanitizeArray($raw_list);
		return $out_list;
	}

}