<?php
final class MySQLiClass {
    private $mysqlic;

    public function __construct($hostname, $username, $password, $database) {
        $this->mysqlic = new mysqli($hostname, $username, $password, $database);

        if ($this->mysqlic->connect_error) {
            trigger_error('Error: Could not make a database link (' . $this->mysqlic->connect_errno . ') ' . $this->mysqlic->connect_error);
        }

        $this->mysqlic->query("SET NAMES 'utf8'");
        $this->mysqlic->query("SET CHARACTER SET utf8");
        $this->mysqlic->query("SET CHARACTER_SET_CONNECTION=utf8");
        $this->mysqlic->query("SET SQL_MODE = ''");

    }

    public function setTimezone($timezone){
        $this->mysqlic->query("SET @@session.time_zone = '$timezone'");
    }

    public function query($sql) {
        $query = $this->mysqlic->query($sql);

        if (!$this->mysqlic->errno) {
            if ($query instanceof mysqli_result) {
                $data = array();

                while ($row = $query->fetch_assoc()) {
                    $data[] = $row;
                }

                $result = new stdClass();
                $result->num_rows = $query->num_rows;
                $result->row = isset($data[0]) ? $data[0] : array();
                $result->rows = $data;

                $query->close();

                return $result;
            } else {
                return true;
            }
        } else {
            throw new Exception('Error: ' . $this->mysqlic->error  . '<br />Error No: ' . $this->mysqlic->errno . '<br />' . $sql);
        }
    }

    public function escape($value) {
        return $this->mysqlic->real_escape_string($value);
    }

    public function escapeArray($data) {
        $array = array();
        foreach ($data as $key => $value) {
            if(!is_null($value)){
                $array[$key] = $this->escape($value);
            }else{
                $array[$key] = $value;
            }
        }
        return $array;
    }

    public function countAffected() {
        return $this->mysqlic->affected_rows;
    }

    public function getLastId() {
        return $this->mysqlic->insert_id;
    }

    public function __destruct() {
        $this->mysqlic->close();
    }

    public function getConnectError(){
        return $this->mysqlic->connect_error;
    }

    public function startTransaction(){
        $this->mysqlic->query("START TRANSACTION;");
    }

    public function commit(){
        $this->mysqlic->query("COMMIT;");
    }

    public function rollback(){
        $this->mysqlic->query("ROLLBACK;");
    }

    public function dataAtual(){
        $data = $this->query("SELECT current_timestamp");

        return $data->row['current_timestamp'];
    }

    public function executeSql($query, array $args) {

        $stmt   = $this->mysqlic->prepare($query);

        if (!$stmt){
            throw new Exception('Error: ' . $this->mysqlic->error  . '<br />Error No: ' . $this->mysqlic->errno . '<br />' . $query);
        }

        if($args){
            $params = [];
            $types  = array_reduce($args, function ($string, $arg) use (&$params) {
                $params[] = $arg;
                if (is_float($arg))      $string .= 'd';
                elseif (is_integer($arg) || is_null($arg) || is_bool($arg))   $string .= 'i';
                elseif (is_string($arg))    $string .= 's';
                else{
                    trigger_error("Parâmetro não suportado pela função, por favor verifique as informações!");
                    exit;
                }
                return $string;
            }, '');

            array_unshift($params, $types);

            call_user_func_array([$stmt, 'bind_param'], $this->makeValuesReferenced($params));
        }

        if($stmt->execute()){
            $result = $stmt->get_result();
        }else{
            $vErro = "";
            if(sizeof($stmt->error_list)){
                $vErro = 'Erro original: ';

                foreach($stmt->error_list as $error){
                    $vErro .= " " . $error['error'];
                }
            }


            trigger_error("Query não executada!
			                        " . $vErro);
            exit;
        }

        $stmt->close();

        return $result;

    }

    function makeValuesReferenced($arr){
        $refs = array();
        foreach($arr as $key => $value)
            $refs[$key] = &$arr[$key];
        return $refs;
    }


}
