<?php
ApplicationSettings::RegisterDefaultSetting("database", "host", "localhost");
ApplicationSettings::RegisterDefaultSetting("database", "database", "php-mvc");
ApplicationSettings::RegisterDefaultSetting("database", "username", "root");
ApplicationSettings::RegisterDefaultSetting("database", "password", "");


class DBObject implements ISavableObject{
	protected static $PDO=null;
	protected static $PREPARED_STATEMENTS=array();
	
	private static $_classFields=array();
	
	protected $_fields=array();
	protected $_changedFields=array();
	
	private $_table,$_key,$_id;

	protected static function SetupPDO(){
		if (self::$PDO!=null)
			return;
		$host=ApplicationSettings::GetSetting("database", "host");
		$db=ApplicationSettings::GetSetting("database", "database");
		$username=ApplicationSettings::GetSetting("database", "username");
		$password=ApplicationSettings::GetSetting("database", "password");
		self::$PDO=new PDO("mysql:host=$host;dbname=$db",$username,$password);
		self::$PDO->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE,PDO::FETCH_ASSOC);
	}
	
	public static function GetPDO(){
		self::SetupPDO();
		return self::$PDO;
	}
	
	public static function VariableToDBField($variableName) {
		$parts=preg_split('/(?=[A-Z])/', $variableName);
		for ($i=0;$i<count($parts);$i++)
			$parts[$i]=strtolower($parts[$i]);
		return trim(implode("_", $parts),"_"); // If the variable name start with upper case then we get an extra blank entry in the array causing an extra _
	}
	
	public static function DBFieldToVariable($fieldName) {
		$parts=explode("_",$fieldName);
		for ($i=0;$i<count($parts);$i++)
			$parts[$i]=ucfirst($parts[$i]);
		return implode("", $parts);
	}
	
	function __construct($table, $key, $id) {
		$this->_table=$table;
		$this->_key=$key;
		$this->_id=$id;
		
		self::SetupPDO();
		
		$this->Load();
	}
	
	public function __get($name) {
		if (array_key_exists($name,$this->_fields))
			return $this->_fields[$name];
		return null;
	}
	
	public function __set($name, $value) {
		if (array_key_exists($name,$this->_fields) && $this->_fields[$name]!=$value){
			$this->_changedFields[$name]=$name;
			$this->_fields[$name]=$value;
		}
	}
	
	public function __isset($name) {
		return array_key_exists($name, $this->_fields);
	}
	
	public function Load(){
		$class=get_class($this);
		
		if (!isset(self::$_classFields[$class])){
			self::$_classFields[$class]=self::$PDO->query("DESCRIBE `{$this->_table}`")->fetchAll(PDO::FETCH_COLUMN);
		}
		
		$statementKey=$class.'_construct_'.$this->_key;
		if (!isset(self::$PREPARED_STATEMENTS[$statementKey])){
			$fields=implode(", ", self::$_classFields[$class]);
			$sql="SELECT $fields FROM `{$this->_table}` WHERE `{$this->_key}`=?";
			self::$PREPARED_STATEMENTS[$statementKey]=self::$PDO->prepare($sql);
		}
		$prep=self::$PREPARED_STATEMENTS[$statementKey];
		$prep->execute(array($this->_id));
		$record=$prep->fetch();
		if ($record!==false)
			foreach ($record as $key=>$value)
				$this->_fields[self::DBFieldToVariable($key)]=$value;
		else {
			foreach (self::$_classFields[$class] as $field)
				$this->_fields[self::DBFieldToVariable($field)]=null;
			$this->_id=0;
		}
	}
	
	public function Save() {
		if (count($this->_changedFields)==0)
			return;
		
		$fields=array();
		$execData=array();
		foreach ($this->_changedFields as $field){
			$fields[]=self::VariableToDBField($field).'=:'.$field;
			$execData[':'.$field]=$this->_fields[$field];
		}
		
		if ($this->_id!==0){
			$sql="UPDATE `{$this->_table}` SET ".implode(", ", $fields)." WHERE `{$this->_key}`=:soi5yh58y";
			$execData[':soi5yh58y']=$this->_id;
		}else{
			$sql="INSERT INTO `{$this->_table}` SET ".implode(", ", $fields);
		}
		
		$prep=self::$PDO->prepare($sql);
		$prep->execute($execData);
		
		//var_dump($prep->errorInfo());
		/*$errorInfo=$prep->errorInfo();
		if ($errorInfo[0]!='00000')
			trigger_error($errorInfo[2]);*/
		
		if ($this->_id===0){ // If this is a new object we want to reload fromt he DB to make sure all fields are correct.
			// In order to do so we need to find the value for the key we're using
			$id=self::$PDO->lastInsertId();
			$key=self::$PDO->query("SHOW INDEX FROM `{$this->_table}` WHERE Key_name='PRIMARY'")->fetch()['Column_name'];
			$this->_id=self::$PDO->query("SELECT `{$this->_key}` FROM `{$this->_table}` WHERE `$key`=$id")->fetchColumn();
			$this->Load();
		}
	}
}
