<?

/**
 * $Id: DB.class.php 982 2008-07-31 15:25:34Z dakl $
 * Interfejs polaczenia z baza v2.2
 *
 */
interface DBConnection {

	public function Prepare($query);

	public function Execute($query);
}

/**
 * Interfejs danych w bazie
 *
 */
interface DBStatement {

	public function Execute();

	public function BindParam($key, $value);

	public function FetchRow();

	public function FetchAssoc();

	public function FetchAllAssoc();
}

/**
 * Klasa do obslugi bazy mysql
 *
 */
class DBMysql implements DBConnection {

	protected $user;
	protected $pass;
	protected $dbHost;
	protected $dbName;
	protected $dbh;
	private $query;
	protected $characterset = 'utf8';

	/**
	 * Konstruktor klasy
	 *
	 * @param string $user
	 * @param string $pass
	 * @param string $dbHost
	 * @param string $dbName
	 */
	public function __construct($user, $pass, $dbHost, $dbName) {
		$this->user = $user;
		$this->pass = $pass;
		$this->dbHost = $dbhost;
		$this->dbName = $dbname;
	}

	/* Nawiazywanie polaczenia z baza */

	public function Connect($method = null) {

		if (!Core::GetAppSafeMode()) {
			try { //echo $method;
				$this->DbConnect();
				//Utils::ArrayDisplay($this);
				$this->SelectDb();
				$this->SetCharacterset();
			} catch (Exception $e) {
				MFLog::Fatal("Line: " . $e->getLine() . " Message: " . $e->getMessage() . " Referer: " . getenv('HTTP_REFERER'));
				MFLog::Error("Switching app to safe mode");
				Core::SetAppSafeMode();
			}
		}
	}

	protected function DbConnect() {
		//echo"konekt";
		Profiler::log('mysqlStart', '', microtime());
		$this->dbh = new mysqli($this->dbHost, $this->user, $this->pass, $this->dbName);
		if ($this->dbh->connect_errno) {
			echo "Failed to connect to MySQL: (" . $mysqli->connect_errno . ") " . $mysqli->connect_error;
		}
//		echo $this->dbh->host_info . "\n";
//		$this->dbh = new mysqli($this->dbHost, $this->user, $this->pass);
//		//$this->dbh = mysqli_connect($this->dbHost, $this->user, $this->pass);
//		$this->dbh = new PDO('mysql:host='.$this->dbHost.';dbname='.$this->dbName.';charset='.$this->characterset, $this->user, $this->pass);
//		
//        if(empty($this->dbh)) {
//            throw new MysqlException('Cannot connect to database!');
//        }
	}

	protected function SelectDb() {
		if (!mysqli_select_db($this->dbh, $this->dbName)) {
			throw new MysqlException('Cannot select database!');
		}
	}

	protected function SetCharacterset() {
		mysqli_query($this->dbh, "SET CHARACTER SET " . $this->characterset);
		mysqli_query($this->dbh, "SET NAMES '" . $this->characterset . "'");
		mysqli_query($this->dbh, "SET CHARACTER_SET_CLIENT = " . $this->characterset);
		mysqli_query($this->dbh, "SET character_set_results = " . $this->characterset);
		mysqli_query($this->dbh, "SET character_set_connection = " . $this->characterset);
	}

	public function Escape($string) {

//	    if(Enviroment::CheckMagicQuotes()) {
//			$return = mysqli_real_escape_string($string);
//	    } else {
//			$return = $string;
//	    }
		$return = mysqli_real_escape_string($this->dbh, $string);

		return $return;
	}

	/* Wykonanie zapytania */

	public function Execute($query) {

		if (!$this->dbh) {
			$this->Connect(__METHOD__);
		}
		MFLog::Debug($query);
		$ret = 'unexecuted';
		if ($this->dbh) {
			$startTime = microtime();
			$ret = $this->dbh->query($query);
			$endTime = microtime();
                        $deltaTime = (int)$endTime - (int)$startTime;
                        //Utils::ArrayDisplay( abs((int)$deltaTime));
			Profiler::log('mysql', $query, abs($deltaTime));
		}
		if (!$ret && $ret != 'unexecuted') {
			throw new MysqlException(mysqli_error($this->dbh) . $query);
		} else {
			$this->setQuery($query);
			$stmt = new DBMysqlStatement($this);
			$stmt->result = $ret;
			return $stmt;
		}
	}

	/* Przygotowanie zapytania zwraca obiekt klasy DBMysqlStatement */

	public function Prepare($query) {
		if (!$this->dbh) {
			//$this->Connect(__METHOD__);
		}
		$this->setQuery($query);
		return new DBMysqlStatement($this);
	}

	/**
	 * Rozpoczyna transakcje
	 *
	 */
	public function BeginTransaction() {
		if (!$this->dbh) {
			$this->Connect(__METHOD__);
		}
		@mysqli_query($this->dbh, "START TRANSACTION ");
	}

	/**
	 * Zartwierdza transakcje
	 *
	 */
	public function CommitTransaction() {
		if (!$this->dbh) {
			$this->Connect(__METHOD__);
		}
		@mysqli_query($this->dbh,"COMMIT");
	}

	/**
	 * Wycofuje transakcje
	 *
	 */
	public function Rollback() {
		if (!$this->dbh) {
			$this->Connect(__METHOD__);
		}
		@mysqli_query($this->dbh,"ROLLBACK");
	}

	/**
	 * Destruktor zamykajacy polaczenie
	 *
	 */
	public function __destruct() {
		if (isset($this->dbh) && is_resource($this->dbh)) {

			Profiler::log('mysqlEnd', '', microtime());
		}
	}

	public function GetDbh() {
		return $this->dbh;
	}

	public function getQuery() {
		return $this->query;
	}

	public function setQuery($query) {
		$this->query = $query;
	}

}

/**
 * Klasa implementujaca interfejs DBStatement dla mysqla
 *
 */
class DBMysqlStatement implements DBStatement {

	public $result;
	public $binds;
	public $query;
	public $dbh;
	private $cacheTime = 30;
	private $cacheFile;
	private $cachePath = DBCACHE_PATH;
	private $cacheEnable = DBCACHE_ENABLE;
	private $cacheQuery = false;
	private $dbMysql;

	/**
	 * KOnstruktor klasy
	 *
	 * @param mysql $dbh
	 * @param string $query
	 */
	public function __construct(DBMysql $dbMysql) {
		$this->query = $dbMysql->getQuery();
		$this->dbh = $dbMysql->GetDbh();
		$this->dbMysql = $dbMysql;
		if (!$this->dbh) {
//			$this->dbMysql->Connect();
			//throw new MysqlException("No db connection");
		}
	}

	/**
	 * Zwraca tresc zapytania
	 *
	 * @return unknown
	 */
	public function GetQuery() {
		return $this->query;
	}

	/* Zamienia zmienne w zapytaniu na podane wartosci */

	public function BindParam($ph, $pv) {
		$this->binds[$ph] = $pv;
		return $this;
	}

	/* Wykonanie zapytania */

	public function Execute($q = null) {
		//echo $q.":";
		//var_dump($this->CacheCheck());
		//var_dump(Core::GetAppSafeMode());
		if (!$this->CacheCheck() && !Core::GetAppSafeMode()) {
			//echo"qq";
			if (!$this->dbh) {
				$this->dbMysql->Connect(__METHOD__ . $this->query);
			}
			$binds = func_get_args();
			foreach ($binds as $index => $name) {
				$this->binds[$index + 1] = $name;
			}
			$cnt = count($binds);
			$query = $this->query;


			$binds = func_get_args();
			foreach ($binds as $index => $name) {
				$this->binds[$index + 1] = $name;
			}
			$cnt = count($binds);
			$query = $this->query;

			//Utils::ArrayDisplay($query);

                        if(is_countable($this->binds)) {
                            if (count($this->binds) > 0) {
                                    foreach ($this->binds as $ph => $pv) {
                                            //                $query = str_replace(":$ph", "'".mysqli_escape_string($pv)."'", $query);

                                            $query = str_replace(":$ph", '\'' . mysqli_real_escape_string($this->dbh, $pv) . '\'', $query);
                                    }
                            }//echo ">>".$query;
                        }
			MFLog::Debug(__FUNCTION__ . ' query: ' . $query);


			$startTime = microtime();
			$this->result = $this->dbh->query($query);
			$endTime = microtime();
                        $deltaTime = (int)$endTime - (int)$startTime;
			Profiler::log('mysql', $query, abs($deltaTime));


			if (!$this->result) {
				throw new MysqlException($query . "<br /><br />" . mysqli_error($this->dbh));
			}
		}

		return $this;
	}

	/* Zwraca wiersz */

	public function FetchRow() {
		if (!$this->result) {
			throw new MysqlException("Query failed");
		}
		$this->SetCacheFile($this->query . 'FetchRow');

		if ($this->cacheQuery == false) {
			if (!$this->result)
				$this->Execute();

			$result = mysqli_fetch_row($this->result);
			mysqli_free_result($this->result);
		}

		else if ($this->cacheQuery == true && !$this->CacheCheck() && !Core::GetAppSafeMode()) {
			if (!$this->result)
				$this->Execute();

			$result = mysqli_fetch_row($this->result);
			mysqli_free_result($this->result);
			$this->CacheWrite($result);
		} else {
			$result = $this->CacheRead();
		}

		return $result;
	}

	/* Zwraca wiersz jako tablice asocjacyjna */

	public function FetchAssoc() {
		$this->SetCacheFile($this->query . 'FetchAssoc');

		if ($this->cacheQuery == false) {
			//$this->dbMysql->Connect();
			if (!$this->result)
				$this->Execute();
			//var_dump($this->result);
			//Utils::ArrayDisplay($this);
			$result = \mysqli_fetch_assoc($this->result);
		}

		else if (($this->cacheQuery == true && !$this->CacheCheck() && !Core::GetAppSafeMode())) {

			//$this->dbMysql->Connect(__METHOD__);
			$this->Execute();
			$result = mysqli_fetch_assoc($this->result);
			$this->CacheWrite($result);
		} else {
			$result = $this->CacheRead();
		}
		//Utils::ArrayDisplay($this->dbh);
		return $result;
	}

	/* Zwraca ca�y wynik jako tablica asocjacyjna */

	public function FetchAllAssoc() {
		$this->SetCacheFile($this->query . 'FetchAllAssoc');
		//Utils::ArrayDisplay($this);
		if ($this->cacheQuery == false) {
			$result = array();
			//$this->Execute();
			while ($row = $this->fetchAssoc()) {
				$result[] = $row;
			}
			
		} else if ($this->cacheQuery == true && !$this->CacheCheck() && !Core::GetAppSafeMode()) {
			$result = array();
			$this->cacheQuery = false;
			while ($row = $this->fetchAssoc()) {
				$result[] = $row;
			}
			$this->SetCacheFile($this->query . 'FetchAllAssoc');
			$this->CacheWrite($result);
		} else {
			$result = $this->CacheRead();
		}

		return $result;
	}

	/* Zwraca ca�y wynik jako tablica asocjacyjna */

	public function FetchAllRow() {
		$this->SetCacheFile($this->query . 'FetchAllRow');



		if ($this->cacheQuery == false) {
			$result = array();

			while ($row = $this->fetchRow()) {
				$result[] = $row;
			}
		} else if ($this->cacheQuery == true && !$this->CacheCheck() && !Core::GetAppSafeMode()) {
			$result = array();
			$this->cacheQuery = false;
			while ($row = $this->fetchRow()) {
				$result[] = $row;
			}
			$this->SetCacheFile($this->query . 'FetchAllRow');
			$this->CacheWrite($result);
		} else {
			$result = $this->CacheRead();
		}

		return $result;
	}

	/* Zwraca liczbe wierszy */

	public function NumRows() {
		if (!$this->result) {
			throw new MysqlException("Query failed");
		}
		$this->SetCacheFile($this->query . 'NumRows');

		if ($this->cacheQuery == false) {
			if (!$this->result)
				$this->Execute();

			$result = mysqli_num_rows($this->result);
		}

		else if ($this->cacheQuery == true && !$this->CacheCheck() && !Core::GetAppSafeMode()) {
			if (!$this->result)
				$this->Execute();

			$result = mysqli_num_rows($this->result);

			$this->CacheWrite($result);
		} else {
			$result = $this->CacheRead();
		}

		return $result;
	}

	/* Zwraca wiersz w postaci tablicy */

	public function FetchArray() {
		if (!$this->result) {
			throw new MysqlException("Query failed");
		}
		$this->SetCacheFile($this->query . 'FetchArray');



		if ($this->cacheQuery == false) {
			if (!$this->result)
				$this->Execute();

			$result = mysqli_fetch_array($this->result);
		}

		else if ($this->cacheQuery == true && !$this->CacheCheck() && !Core::GetAppSafeMode()) {

			if (!$this->result)
				$this->Execute();

			$result = mysqli_fetch_array($this->result);

			$this->CacheWrite($result);
		} else {
			$result = $this->CacheRead();
		}

		return $result;
	}

	/**
	 * Zwraca id ostatnio zmienionego rekordu
	 *
	 * @return integer
	 */
	public function GetInsertionId() {
		if (!$this->result) {
			throw new MysqlException("Query failed");
		}
		return mysqli_insert_id($this->dbh);
	}

	/**
	 * Zwraca liczb� zmienionych rekord�w w ostatnim zapytaniu modyfikuj�cym dane.
	 *
	 * @return integer
	 */
	public function GetAffectedRows() {
		if (!$this->result) {
			throw new MysqlException("Query failed");
		}
		return mysqli_affected_rows($this->dbh);
	}

	/**
	 * Sprawdza czy zaoytanie jest cacheowane
	 *
	 * @return boolean
	 */
	public function CacheCheck() {

		if (($this->cacheEnable == true && (is_file($this->cachePath . $this->cacheFile) && filemtime($this->cachePath . $this->cacheFile) > (time() - $this->cacheTime)))) {

			return true;
		} else {
			if (is_file($this->cachePath . $this->cacheFile)) {
				touch($this->cachePath . $this->cacheFile);
			}
			return false;
		}
	}

	/**
	 * Zapisuje cache do pliku
	 *
	 * @param obj $result
	 */
	public function CacheWrite($result) {
		if ($this->cacheEnable != false) {
			$records = serialize($result);
			$fp = fopen($this->cachePath . $this->cacheFile, "w");
			fputs($fp, $records);
			fclose($fp);
			$this->cacheQuery = false;
		}
	}

	/**
	 * Odczytuje cache z pliku
	 *
	 * @return obj
	 */
	public function CacheRead() {
		if (is_file($this->cachePath . $this->cacheFile)) {
			$records = unserialize(file_get_contents($this->cachePath . $this->cacheFile));
			$this->cacheQuery = false;
			return $records;
		} else {
			throw new MysqlException('File does not exist: ' . $this->cachePath . $this->cacheFile);
		}
	}

	/**
	 * Uruchamia cacheowanie
	 *
	 * @param integer $time
	 */
	public function CacheStart($time = null) {
		if ($time != null && $this->cacheEnable != false) {
			$this->cacheTime = $time;
		}
		if ($this->cacheEnable != false)
			$this->cacheQuery = true;
		else
			$this->cacheQuery = false;

		return $this;
	}

	/**
	 * Ustanawia nazw� pliku cache
	 *
	 * @param unknown_type $fileName
	 */
	public function SetCacheFile($fileName) {
		$this->cacheFile = md5($fileName);
	}

}

/**
 * Klasa obslugi wynikow zapytan
 *
 */
class DBResult {

	protected $stmt;
	protected $result = array();
	private $rowIndex = 0;
	private $currIndex = 0;
	private $done = false;

	/**
	 * Konstruktor
	 *
	 * @param DBStatement $stmt
	 */
	public function __construct(DBStatement $stmt) {
		$this->stmt = $stmt;
	}

	/* Zwraca pierwszy rekord */

	public function First() {
		if (!$this->result) {
			$this->result[$this->rowIndex++] = $this->stmt->FetchAssoc();
		}
		$this->currIndex = 0;
		return $this;
	}

	/* Zwraca ostatni rekord */

	public function Last() {
		if (!$this->done) {
			array_push($this->result, $this->stmt->FetchAllAssoc());
		}
		$this->done = true;
		$this->currIndex = $this->rowIndex = count($this->result) - 1;
		return $this;
	}

	/* Zwieksza index i zwraca kolejny rekord */

	public function Next() {
		if ($this->done) {
			return false;
		}
		$offset = $this->currIndex + 1;
		if (!$this->result[$offset]) {
			$row = $this->stmt->FetchAssoc();
			if (!$row) {
				$this->done = true;
				return false;
			}
			$this->result[$offset] = $row;
			++$this->rowIndex;
			++$this->currIndex;
			return $this;
		} else {
			++$this->currIndex;
			return $this;
		}
	}

	/* Zmniejsza index i zwraca poprzedni wiersz */

	public function Prev() {
		if ($this->currIndex == 0) {
			return false;
		}
		--$this->currIndex;
		return $this;
	}

	/**
	 * Getter dla pobieranych danych
	 *
	 * @param string $value
	 * @return string
	 */
	public function __get($value) {
		if (array_key_exists($value, $this->result[$this->currIndex])) {
			return $this->result[$this->currIndex][$value];
		}
	}

}

/**
 * Klasa oslonowa naszej bazy danych
 *
 */
class DBProd extends DBMysql {

	protected $user;
	protected $pass;
	protected $dbHost;
	protected $dbName;

	/**
	 * Pusty konstruktor
	 *
	 */
	public function __construct() {

		$db = Config::Get('db');
		$this->dbHost = $db['prodHost'];
		$this->dbName = $db['prodDb'];
		$this->user = $db['prodUser'];
		$this->pass = $db['prodPass'];
	}

	public function GetDbh() {
		if (empty($this->dbh)) {
			//$this->Connect(__METHOD__);
		}
		return $this->dbh;
	}

}

?>