<?php
	namespace Juju {
		require_once('SQL/query.class.php');
		require_once('Data/securestring.class.php');
		use \Juju\SQL\Query;
		use \Juju\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();
		});
	}
?>