<?php
	namespace Juju;
	require_once('SQL/query.class.php');
	require_once('Data/securestring.class.php');
	use \Juju\{SQL\Query, Data\SecureString};

	/**
	* SQL class. Used for handling SQL connections
	*
	* @module sql
	* @class SQL
	* @constructor
	*/
	class SQL {
		/**
		* This is the mysqli connection beneath everything
		* 
		* @property sql
		* @type {mysqli}
		* @private
		* @required
		*/
		private $guid;
		private $sql;
		public $queries = [];
		private static $connections = [];
		public static function FromDSN(string $dsnstring){
			$dsnstring = explode(':', $dsnstring)[1];
			$dsn = explode(';', $dsnstring);
			$dsn = array_reduce($dsn, function($dsn, $item){
				$item = explode('=', $item);
				$dsn[$item[0]] = $item[1];
				return $dsn;
			});
			if(!isset($dsn['host'])){
				throw new \Exception("DSN '{$dsnstring}' missing host");
			}
			if(!isset($dsn['dbname'])){
				throw new \Exception("DSN '{$dsnstring}' missing dbname");
			}
			if(!isset($dsn['user'])){
				$dsn['user'] = $dsn['dbname'];
			}
			if(!isset($dsn['pass'])){
				$dsn['pass'] = $dsn['user'];
			}
			$dsn['pass'] = SecureString::from($dsn['pass']);
			return new SQL($dsn['host'], $dsn['user'], $dsn['pass'], $dsn['dbname']);
		}
		public function __construct($server,$user,$pass,$db){
			$this->guid = uniqid();
			$this->sql = new \mysqli('p:'.$server,$user,"{$pass}",$db);;
			if($this->sql->connect_error){
				throw new \Exception('Mysqli Connect Error (' . $mysqli->connect_errno . ') ' . $mysqli->connect_error);
			}
			self::$connections[] = $sql;
		}
		public function __destruct(){
			$this->sql->rollback();
			$this->sql->close();
			foreach($this->queries as $query){
				unset($query);
			}
			self::$connections = array_diff(self::$connections, [$this]);
		}
		public function __invoke(){
			return $this->sql;
		}
		public function __get($name){
			switch($name){
				case 'error':
					return $this->sql->error;
				break;
				case 'insert_id':
					return $this->sql->insert_id;
				break;
			}
		}
		public function __toString(){
			return $this->guid;
		}
		/**
		* Returns a Query object based on inputs
		*
		* @method query
		* @param {String} sql The sql expression to run
		* @param {String=null} [types] A string containing all the types of arguments being passed
		* @param {Mixed} [bindings]* The bindings to use in the sql statement
		* @return {Query} Returns the query object
		*/
		public function query(...$args){
			return new SQL\Query(...array_merge([$this], $args));
		}
		public function escape($s){
			return $this->sql->escape_string($s);
		}
		public function charset($charset){
			return $this->sql->set_charset($charset);
		}
		public static function make_referenced(&$arr){
			$refs = [];
			foreach($arr as $key => $value){
				$refs[$key] = &$arr[$key];
			}
			return $refs;
		}
		public static function shutdown(){
			foreach(self::$connections as $sql){
				unset($sql);
			}
		}
	}
	register_shutdown_function(function(){
		SQL::shutdown();
	});
?>