<?php

/**
 * SQLite Database Wrapper
 * Works with PDO (sqlite) or SQLite3 - whichever is available
 */
class SQLiteDB
{
    private $pdo = null;
    private $sqlite3 = null;
    private $isPdo = false;

    public function __construct($dbPath)
    {
        if (class_exists('PDO') && in_array('sqlite', PDO::getAvailableDrivers())) {
            $this->pdo = new PDO('sqlite:' . $dbPath);
            $this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
            $this->isPdo = true;
        } elseif (class_exists('SQLite3')) {
            $this->sqlite3 = new SQLite3($dbPath);
        } else {
            throw new Exception('No SQLite driver available (need PDO with sqlite or SQLite3)');
        }
    }

    public function exec($sql)
    {
        if ($this->isPdo) {
            return $this->pdo->exec($sql);
        } else {
            return $this->sqlite3->exec($sql);
        }
    }

    public function query($sql)
    {
        if ($this->isPdo) {
            return new SQLiteDBResult($this->pdo->query($sql), true);
        } else {
            return new SQLiteDBResult($this->sqlite3->query($sql), false);
        }
    }

    public function prepare($sql)
    {
        if ($this->isPdo) {
            return new SQLiteDBStatement($this->pdo->prepare($sql), true);
        } else {
            return new SQLiteDBStatement($this->sqlite3->prepare($sql), false);
        }
    }

    public function lastInsertRowID()
    {
        if ($this->isPdo) {
            return $this->pdo->lastInsertId();
        } else {
            return $this->sqlite3->lastInsertRowID();
        }
    }

    public function close()
    {
        if ($this->isPdo) {
            $this->pdo = null;
        } else {
            $this->sqlite3->close();
        }
    }
}

class SQLiteDBStatement
{
    private $stmt;
    private $isPdo;

    public function __construct($stmt, $isPdo)
    {
        $this->stmt = $stmt;
        $this->isPdo = $isPdo;
    }

    public function bindValue($param, $value, $type = null)
    {
        if ($this->isPdo) {
            $pdoType = PDO::PARAM_STR;
            if ($type === SQLITE3_INTEGER) $pdoType = PDO::PARAM_INT;
            elseif ($type === SQLITE3_NULL) $pdoType = PDO::PARAM_NULL;
            return $this->stmt->bindValue($param, $value, $pdoType);
        } else {
            $sqliteType = SQLITE3_TEXT;
            if ($type !== null) $sqliteType = $type;
            return $this->stmt->bindValue($param, $value, $sqliteType);
        }
    }

    public function execute()
    {
        if ($this->isPdo) {
            $this->stmt->execute();
            return new SQLiteDBResult($this->stmt, true);
        } else {
            return new SQLiteDBResult($this->stmt->execute(), false);
        }
    }
}

class SQLiteDBResult
{
    private $result;
    private $isPdo;

    public function __construct($result, $isPdo)
    {
        $this->result = $result;
        $this->isPdo = $isPdo;
    }

    public function fetchArray($mode = null)
    {
        if ($mode === null) {
            $mode = SQLITE3_BOTH;
        }

        if ($this->isPdo) {
            $pdoMode = PDO::FETCH_BOTH;
            if ($mode === SQLITE3_ASSOC) $pdoMode = PDO::FETCH_ASSOC;
            elseif ($mode === SQLITE3_NUM) $pdoMode = PDO::FETCH_NUM;
            return $this->result->fetch($pdoMode);
        } else {
            return $this->result->fetchArray($mode);
        }
    }
}

// Define SQLite3 constants if not defined (for PDO-only environments)
if (!defined('SQLITE3_TEXT')) define('SQLITE3_TEXT', 3);
if (!defined('SQLITE3_INTEGER')) define('SQLITE3_INTEGER', 1);
if (!defined('SQLITE3_NULL')) define('SQLITE3_NULL', 5);
if (!defined('SQLITE3_ASSOC')) define('SQLITE3_ASSOC', 1);
if (!defined('SQLITE3_NUM')) define('SQLITE3_NUM', 2);
if (!defined('SQLITE3_BOTH')) define('SQLITE3_BOTH', 3);
