<?php

class DatabaseException extends Exception {}

class Database {
	public $conn = null;
	public $dbname = "";
	public $schema = "";
	public $debug = false;
	
	public static function InPlaceholder($count) {
		return "(".substr(str_repeat("?,", $count), 0, -1).")";
	}
	
	public static function IsInstance($object, $throwException = true) {
		$retval = is_object($object) === true ? get_class($object) == get_called_class() : false;
		if($retval == false && $throwException == true) 
			throw new DatabaseException("The given object is not a instance of ".get_called_class());
		return $retval;
	}
	
	public static function GetInstance($host, $username, $password, $dbname, $schema = "") {
		$obj = new self;
		$obj->Connect($host, $username, $password, $dbname, $schema);
		//$obj->conn->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, false); //PHP < 5.3 ist zu doof dafür
		return $obj;
	}
	
	public function Connect($connstr, $username, $password) {
		if($this->conn !== null) throw new DatabaseException("Already connected to the server");
		
		try {
			$this->conn = new PDO($connstr, $username, $password);
		} catch (PDOException $e) {
			throw new DatabaseException($e->getMessage());
		}
	}
	
	public function Close() {
		$this->conn = null;
	}
	
	public function CheckConnection($throwException = false) {
		if($this->conn === null) {
			if($throwException === true) throw new DatabaseException("Not connected to Database");
			return false;
		}
		return true;
	}
	
	public function Query($statement, $binding = null) {
		if(func_num_args() > 2) {
			$binding = func_get_args();
			array_splice($binding, 0, 1);
		} else {
			if($binding !== null) {
				$binding = is_array($binding) ? $binding : Array($binding);
			}
		}

		$this->CheckConnection(true);
		$retval = $this->conn->prepare($statement);
		if($retval->execute($binding) === false) {
			throw new DatabaseException("Failed to Execute statement");
		}
		
		return $retval;
	}
	
	public function FetchRowAssoc($sth) {
		$this->CheckConnection(true);
		$retval = $sth->fetch(PDO::FETCH_ASSOC);
		return $retval;
	}
	
	public function FetchFirstRowAssoc($query, $binding = null) {
		if(func_num_args() > 2) {
			$binding = func_get_args();
			array_splice($binding, 0, 1);
		} else {
			if($binding !== null) {
				$binding = is_array($binding) ? $binding : Array($binding);
			}
		}
		
		$this->CheckConnection(true);
		$sth = $this->Query($query, $binding);
		$retval = $this->FetchRowAssoc($sth);
		$sth = null;
		
		return $retval;
	}
	
	public function FetchAllRowsAssoc($query, $binding = null) {
		if(func_num_args() > 2) {
			$binding = func_get_args();
			array_splice($binding, 0, 1);
		} else {
			if($binding !== null) {
				$binding = is_array($binding) ? $binding : Array($binding);
			}
		}
		
		$this->CheckConnection(true);
		$sth = $this->Query($query, $binding);
		$retval = $sth->fetchAll(PDO::FETCH_ASSOC);
		return $retval;
	}
	
	public function GetError() {
		return "Error ".$this->conn->errorCode().": ".implode(", ", $this->conn->errorInfo());
	}
	
	public function TransactionBegin() {
		return $this->conn->beginTransaction();
	}
	
	public function TransactionCommit() {
		return $this->conn->commit();
	}
	
	public function TransactionRollback() {
		return $this->conn->rollBack();
	}
	
}