<?php
/** Database driver; f0ska xCRUD v.1.6.26; 03/2015 */
class Xcrud_db
{
    private static $_instance = array();
    private $connect;
    public $result;
    private $dbhost;
    private $dbuser;
    private $dbpass;
    private $dbname;
    private $dbencoding;
    private $magic_quotes;

    public static function get_instance($params = false)
    {
        if (is_array($params))
        {
            list($dbuser, $dbpass, $dbname, $dbhost, $dbencoding, $dbport) = $params;
            $instance_name = sha1($dbuser . $dbpass . $dbname . $dbhost . $dbencoding . $dbport);
        }
        else
        {
            $instance_name = 'db_instance_default';
        }
        if (!isset(self::$_instance[$instance_name]) or null === self::$_instance[$instance_name])
        {
            if (!is_array($params))
            {
                $dbuser = Xcrud_config::$dbuser;
                $dbpass = Xcrud_config::$dbpass;
                $dbname = Xcrud_config::$dbname;
                $dbhost = Xcrud_config::$dbhost;
                $dbencoding = Xcrud_config::$dbencoding;
				 $dbport = Xcrud_config::$dbport; 
            }
            self::$_instance[$instance_name] = new self($dbuser, $dbpass, $dbname, $dbhost, $dbencoding, $dbport);
        }
        return self::$_instance[$instance_name];
    }

    private function __construct($dbuser, $dbpass, $dbname, $dbhost, $dbencoding, $dbport = '3306')
{
    $dbtype = Xcrud_config::$dbtype;  // Fetch database type from config
    $dsn = '';

    try {
        switch ($dbtype) {
            case 'mysql':
                $dsn = "mysql:host=$dbhost;port=$dbport;dbname=$dbname;charset=$dbencoding";
                $this->connect = new PDO($dsn, $dbuser, $dbpass);
                break;

            case 'pgsql':
                $dsn = "pgsql:host=$dbhost;dbname=$dbname";
                $this->connect = new PDO($dsn, $dbuser, $dbpass);
                break;

            case 'oci':
                $dsn = "oci:dbname=//$dbhost/$dbname";
                $this->connect = new PDO($dsn, $dbuser, $dbpass);
                break;

            case 'sqlite':
                $dsn = "sqlite:$dbname";
                $this->connect = new PDO($dsn);
                break;

            default:
                throw new Exception("Unsupported DB type: $dbtype");
        }

        // Set PDO attributes
        $this->connect->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        
        // Set the default timezone if needed
        if (Xcrud_config::$db_time_zone) {
            $this->connect->exec("SET time_zone = '" . Xcrud_config::$db_time_zone . "'");
        }
        
        // Fix NULL datetime error - Allow NULL values in datetime fields
        if ($dbtype === 'mysql') {
            $this->connect->exec("SET SESSION sql_mode = 'ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION'");
        }
        
    } catch (PDOException $e) {
        $this->error('Connection error: ' . $e->getMessage());
    }
}


    public function query($query = '')
    {
        try {
            // Execute query
			$query = preg_replace("/= 'NULL'([,\s]|WHERE)/i", "= NULL$1", $query);
            $this->result = $this->connect->query($query);
            return $this->result->rowCount();  // return number of affected rows
        } catch (PDOException $e) {
            $this->error('Query error: ' . $e->getMessage() . '<pre>' . $query . '</pre>');
        }
    }

    public function insert_id()
    {
        // Get the last inserted ID
        return $this->connect->lastInsertId();
    }

    public function result()
    {
        $out = array();
        if ($this->result)
        {
            while ($row = $this->result->fetch(PDO::FETCH_ASSOC))  // Fetch result as an associative array
            {
                $out[] = $row;
            }
        }
        return $out;
    }

    public function row()
    {
        // Fetch a single row as an associative array
        return $this->result->fetch(PDO::FETCH_ASSOC);
    }

    public function escape($val, $not_qu = false, $type = false, $null = false, $bit = false)
{
    // CRITICAL FIX: Convert 'NULL' string to SQL NULL keyword (no quotes)
    if ($val === 'NULL' || $val === 'null') {
        return 'NULL';
    }

    // In PDO, escaping is done automatically when using prepared statements, 
    // so this is just for compatibility if you still need it in non-prepared queries

    if ($type)
    {
        switch ($type)
        {
            case 'bool':
                return $val ? 'TRUE' : ($null ? 'NULL' : 'FALSE');
                break;
            case 'int':
                $val = preg_replace('/[^0-9\-]/', '', $val);
                if ($val === '')
                {
                    return $null ? 'NULL' : 0;
                }
                return $val;
                break;
            case 'float':
                if ($val === '')
                {
                    return $null ? 'NULL' : 0;
                }
                return $val;
                break;
            default:
                if (trim($val) == '')
                {
                    return $null ? 'NULL' : '\'\'';
                }
                return $val;
        }
    }

    if (is_array($val)){
        if ($not_qu)
            return $val;
        return $val;
    }

    if ($not_qu)
        return $val;
    return '\'' . $val . '\'';
}




    public function escape_like($val, $pattern = array('%', '%'))
    {
        if (is_int($val))
            return '\'' . $pattern[0] . (int)$val . $pattern[1] . '\'';
        if ($val == '')
        {
            return '\'\'';
        }
        else
        {
            return '\'' . $pattern[0] . $val . $pattern[1] . '\'';
        }
    }

    private function error($text = 'Error!')
    {
        exit('<div class="xcrud-error" style="position:relative;line-height:1.25;padding:15px;color:#BA0303;margin:10px;border:1px solid #BA0303;border-radius:4px;font-family:Arial,sans-serif;background:#FFB5B5;box-shadow:inset 0 0 80px #E58989;">
            <span style="position:absolute;font-size:10px;bottom:3px;right:5px;">xCRUD</span>' . $text . '</div>');
    }
}
