<?php
# v2.1
class db {
    private static $pdo;
    private static $instance;

    private function __construct() {}

    public static function init() {
        if (!isset(self::$instance)) {
            $c = __CLASS__;
            self::$instance = new $c;
            try{
                if(!defined('DB_HOST')){
                    define("DB_HOST","localhost");
                }
                self::$pdo = new PDO(
                    "mysql:host=".DB_HOST.";dbname=".DB_NAME.";charset=utf8mb4",
                    DB_USER,
                    DB_PASS,
                    [
                        PDO::MYSQL_ATTR_INIT_COMMAND => 'SET sql_mode="ERROR_FOR_DIVISION_BY_ZERO"',
                        PDO::ATTR_EMULATE_PREPARES   => false,
                        PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
                        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
                    ]
                );
            } catch (PDOException $ex) {
                echo "Database conection error! check the database name and credentials.<br><br>";
                $error = $ex;
                if(strlen($error) > 180){
                    $error = substr($error, 0, 179);
                }
                echo $error;
            }
        }
        return self::$instance;
    }

    public static function fetch($sql,$params=NULL){
        $stmt = self::$pdo->prepare($sql);
        $stmt->execute($params);
        return $stmt->fetch();
    }

    public static function fetchColumn($sql,$params=NULL){
        $stmt = self::$pdo->prepare($sql);
        $stmt->execute($params);
        return $stmt->fetchColumn();
    }

    public static function fetchAll($sql,$params=NULL){
        $stmt = self::$pdo->prepare($sql);
        $stmt->execute($params);
        return $stmt->fetchAll();
    }

    public static function fetchAllColumn($sql,$params=NULL){
        $stmt = self::$pdo->prepare($sql);
        $stmt->execute($params);
        return $stmt->fetchAll(PDO::FETCH_COLUMN);
    }

    public static function fetchKeyPair($sql,$params=NULL){
        $stmt = self::$pdo->prepare($sql);
        $stmt->execute($params);
        return $stmt->fetchAll(PDO::FETCH_KEY_PAIR);
    }

    public static function exist($sql,$params=NULL){
        $stmt = self::$pdo->prepare($sql);
        $stmt->execute($params);
        return $stmt->rowCount() ? true:false;
    }

    public static function rowCount($sql,$params=NULL){
        $stmt = self::$pdo->prepare($sql);
        $stmt->execute($params);
        return $stmt->rowCount();
    }

    public static function query($sql,$params=NULL){
        $stmt = self::$pdo->prepare($sql);
        $stmt->execute($params);
        return $stmt->rowCount();
    }

    public static function rawQuery($sql){
        $stmt = self::$pdo->query($sql);
        return $stmt->fetchAll(PDO::FETCH_COLUMN);
    }

    public static function justQuery($sql){
        return self::$pdo->query($sql);
    }

    public static function exec($sql){
        return self::$pdo->exec($sql);
    }

    private static function queryBuilder($tblName, $insertItems, $ignore) {
        $ignore = $ignore? 'IGNORE':'';
        $c=''; $v='';
        foreach ($insertItems as $key => $value) {
            $c .= '`'.$key.'`,';
            $v .= ':'.$key.',';
        }
        $c = rtrim($c,',');
        $v = rtrim($v,',');
        $finalQuery = "INSERT {$ignore} INTO `{$tblName}` ({$c}) VALUES ({$v})";
        return $finalQuery;
    }

    public static function insert($tblName, $insertItems, $ignore = false) {
        $stmt = self::$pdo->prepare(
            self::queryBuilder($tblName, $insertItems, $ignore)
        );
        $stmt->execute($insertItems);
        return self::$pdo->lastInsertId();
    }


    // //saeed update method: 
    // private static function updateQueryBuilder($tblName, $updateItems ,$where) {
    //     $c='';
    //     foreach ($updateItems as $key => $value) {
    //         $c .= '`'.$key.'`'. ' = :'.$key .',';
    //     }
    //     $c = rtrim($c,',');
    //     $finalQuery = "UPDATE `{$tblName}` SET {$c}" .$where;
    //     return $finalQuery;
    // }

    // public static function update2($tblName, $updateItems ,$where) {
    //     $stmt = self::$pdo->prepare(
    //         self::updateQueryBuilder($tblName, $updateItems,$where)
    //     );
    //     $stmt->execute($updateItems);
    //     return $stmt->rowCount();
    // }

    //ehsan update method:
    public static function update($tableName, $updates, $where) {
        $params = [];
        $query = "UPDATE `$tableName`" . PHP_EOL . "SET" . PHP_EOL;
        foreach ($updates as $key => $value) {
            $query .= "`$key` = ?,";
            $params[] = $value;
        }
        $query = rtrim($query, ",");
        $query .= PHP_EOL . "WHERE " . $where;
        return self::query($query, $params);
    }
    
}