<?php

class DB {

	private static $instance = null;
	private $db = null;

	private function __construct() {
	}

	public static function getInstance() {
		if (DB::$instance == null) {
			DB::$instance = new DB;
		} 
		return DB::$instance;
	}

    public function connect($dbuser, $dbpass, $dbhost, $dbname) {
        $this->db = new \PDO("mysql:dbname=$dbname;host=$dbhost;charset=utf8mb4",$dbuser,$dbpass);
        //$this->query("SET NAMES 'utf8' COLLATE 'utf8_general_ci'");
    }

    function query($query,$params = array()) {
        $q = $this->db->prepare($query);
        $q->execute($params);
        $e = $q->errorInfo();
        if($e[0]!='00000') {
            print "<span class='error'>";
            print $e[2];
            print "</span>";
            return false;
        }
        return $q;
    }

    function nextRecord($query) {
        $next = $query->fetchObject();
        return $next;
    }

    function id() {
        return $this->db->lastInsertId();
    }

    function update($table,$id,$data) {
        $values = array();
        foreach($data as $k=>$v) {
            $values[] = "`" . $k . "`" . "=:" . $k;
        }
        $query = sprintf("UPDATE `%s` set " . implode(",",$values) . " WHERE id=:id",$table);
        $data['id'] = $id;

        $q = $this->query($query,$data);
        $id = $this->id();
        return $id;
    }

    function insert($table,$data) {
        $fields = array();
        $values = array();
        foreach($data as $k=>$v) {
            $fields[] = $k;
            $values[] = ":" . $k;
        }
        $query = sprintf("INSERT IGNORE INTO `%s` (" . implode(",",$fields) . ") VALUES (" . implode(",",$values) . ")",$table);
        $q = $this->query($query,$data);
        $id = $this->id();
        return $id;
    }

    function set($table,$record,$field,$value) {
        $this->query("UPDATE `$table` SET `$field`=:f WHERE id=:i",array(
            'f'=>$value,
            'i'=>$record
        ));
    }

    function select($table,$record) {
        $query = sprintf("SELECT * FROM `%s` WHERE id=:id",$table);
        $q = $this->query($query,array("id" => $record));
        $r = $this->nextRecord($q);
        return $r;
    }

	function getTableStructure($table) {
		$query = sprintf("DESCRIBE `%s`", $table);
		$q = $this->query($query);
		$fields = [];

		while ($r = $this->nextRecord($q)) {
			$field = $r['Field'];
			$type = $r['Type'];
			$extra = $r['Extra'];

			$fingerprint = trim("$type $extra");

			$f = new stdClass;
			$f->name = $field;

			if (preg_match('/^(.*)\((\d+)\)(.*)$/', $fingerprint, $m)) {
				$fingerprint = $m[1] . $m[3];
				$f->length = $m[2];
			}


			$f->type == -1;
			$f->unsigned = false;

			switch ($fingerprint) {
				case "bigint unsigned auto_increment": $f->type = MODEL_SERIAL; break;

				case "text": $f->type = MODEL_TEXT; break;
				case "longtext": $f->type = MODEL_TEXT; break;

				case "blob": $f->type = MODEL_TEXT; break;
				case "longblob": $f->type = MODEL_TEXT; break;

				case "tinyint": $f->type = MODEL_TINYINT; break;
				case "tinyint unsigned": $f->type = MODEL_TINYINT; $f->unsigned = true; break;

				case "int": $f->type = MODEL_INT; break;
				case "int unsigned": $f->type = MODEL_INT; $f->unsigned = true; break;

				case "bigint": $f->type = MODEL_BIGINT; break;
				case "bigint unsigned": $f->type = MODEL_BIGINT; $f->unsigned = true; break;

				case "char": $f->type = MODEL_CHAR; break;
				case "varchar": $f->type = MODEL_VARCHAR; break;
			}
		}
	}

	public function all($query) {
		$o = new Collection;
		while ($r = $this->nextRecord($query)) {
			$o->push($r);
		}
		return $o;
	}
}

