/*
文件名:MysqlClass.nut
路径:Dps_A/BaseClass/MysqlClass/MysqlClass.nut
创建日期:2024-09-16	21:23
文件用途:数据库类
*/
class Mysql extends Base_C_Object {

    // 0空闲 1任务中 2死亡
    State = 0;

    constructor(Ip, Port, Name, Account, Password) {
        if (!Open(Ip, Port, Name, Account, Password)) error("数据库连接失败");
    }

    /*
     * 读取mysql返回的数据，读取binary类型的字段
     * @param this.C_Object mysql数据库句柄
     * @param columnIndex 要读取的字段的位置
     */
    function Open(db_ip, db_port, db_name, db_username, db_password) {
        base.constructor(Sq_New_Point(0x80000));
        Sq_CallFunc(S_Ptr("0x83F3AC8"), "pointer", ["pointer"], this.C_Object);
        Sq_CallFunc(S_Ptr("0x83F3CE4"), "int", ["pointer"], this.C_Object);
        //打开数据库句柄
        if (Sq_CallFunc(S_Ptr("0x83F4024"), "int", ["pointer", "pointer", "int", "pointer", "pointer", "pointer"],
                this.C_Object, db_ip, db_port, db_name, db_username, db_password)) {
            return true;
        }
        return false;
    }

    function Fetch() {
        return Sq_CallFunc(S_Ptr("0x83F44BC"), "int", ["pointer"], this.C_Object);
    }

    function Close() {
        Sq_CallFunc(S_Ptr("0x83F3E74"), "int", ["pointer"], this.C_Object);
        Sq_Delete_Point(this.C_Object);
        State = 2;
    }


    /*
     * 读取mysql返回的数据，读取string类型的字段
     * @param this.C_Object mysql数据库句柄
     * @param columnIndex 要读取的字段的位置
     */
    function ReadStringColumn(columnIndex) {
        //MySQL_get_binary_length
        local binary_length = Sq_CallFunc(S_Ptr("0x81253DE"), "int", ["pointer", "int"], this.C_Object, columnIndex);
        local binary_length_point = Sq_New_Point(binary_length);
        //MySQL_get_binary
        if (1 == Sq_CallFunc(S_Ptr("0x812531A"), "int", ["pointer", "int", "pointer", "int"], this.C_Object, columnIndex, binary_length_point, binary_length)) {
            //读取string类型的数据
            local result = Sq_ReadAddressString(binary_length_point, binary_length);
            Sq_Delete_Point(binary_length_point);
            return result;
        }
        Sq_Delete_Point(binary_length_point);
        return null;
    }

    /*
     * 读取mysql返回的数据，读取有符号int类型的字段
     * @param this.C_Object mysql数据库句柄
     * @param columnIndex 要读取的字段的位置
     */
    function ReadIntColumn(columnIndex) {
        local intSizePoint = Sq_New_Point(4);
        //MySQL_get_int
        if (1 == Sq_CallFunc(S_Ptr("0x811692C"), "int", ["pointer", "int", "pointer"], this.C_Object, columnIndex, intSizePoint)) {
            //转为blob
            local blob = Sq_Point2Blob(intSizePoint, 4);
            //读取8位有符号整数
            local result = blob.readn('i');
            Sq_Delete_Point(intSizePoint);
            return result;
        }
        // Sq_Delete_Point(intSizePoint);
        return null;
    }


    /*
     * 读取mysql返回的数据，读取无符号int类型的字段
     * @param this.C_Object mysql数据库句柄
     * @param columnIndex 要读取的字段的位置
     */
    function ReadUIntColumn(columnIndex) {
        local intSizePoint = Sq_New_Point(4);
        //MySQL_get_uint
        if (1 == Sq_CallFunc(S_Ptr("0x80E22F2"), "int", ["pointer", "int", "pointer"], this.C_Object, columnIndex, intSizePoint)) {
            //转为blob
            local blob = Sq_Point2Blob(intSizePoint, 4);
            //读取8位无符号整数
            local result = blob.readn('b');
            Sq_Delete_Point(intSizePoint);
            return result;
        }
        Sq_Delete_Point(intSizePoint);
        return null;
    }

    /*
     * 读取mysql返回的数据，读取float类型的字段
     * @param this.C_Object mysql数据库句柄
     * @param columnIndex 要读取的字段的位置
     */
    function ReadFloatColumn(columnIndex) {
        local intSizePoint = Sq_New_Point(4);
        //MySQL_get_float
        if (1 == Sq_CallFunc(S_Ptr("0x844D6D0"), "int", ["pointer", "int", "pointer"], this.C_Object, columnIndex, intSizePoint)) {
            //转为blob
            local blob = Sq_Point2Blob(intSizePoint, 4);
            //读取32位浮点数
            local result = blob.readn('f');
            Sq_Delete_Point(intSizePoint);
            return result;
        }
        Sq_Delete_Point(intSizePoint);
        return null;
    }

    /*
     * 读取mysql返回的数据，读取binary类型的字段
     * @param this.C_Object mysql数据库句柄
     * @param columnIndex 要读取的字段的位置
     */
    function ReadBinaryColumn(columnIndex) {
        //MySQL_get_binary_length
        local binary_length = Sq_CallFunc(S_Ptr("0x81253DE"), "int", ["pointer", "int"], this.C_Object, columnIndex);
        if (binary_length > 0) {
            local binary_length_point = Memory.alloc(binary_length);
            //MySQL_get_binary
            if (1 == Sq_CallFunc(S_Ptr("0x812531A"), "int", ["pointer", "int", "pointer", "int"], this.C_Object, columnIndex, binary_length_point.C_Object, binary_length)) {
                return binary_length_point;
            }
        }
        return null;
    }

    /**
     * mysql查询，带返回结果，返回一个二维数组
     * @param {*} db_pointer 数据库句柄
     * @param {*} select_sql 要执行的查询语句
     * @param {*} column_type_list 返回结果的类型list，按select的column顺序，int，string，unit，float，binary
     * @returns
     */
    function Select(select_sql, column_type_list) {
        local result_list = [];
        if (Exec_Sql(select_sql)) {
            //获取查询到的数据总数
            local row_count = Sq_CallFunc(S_Ptr("0x80E236C"), "int", ["pointer"], this.C_Object);
            if (row_count > 0) {
                for (local i = 0; i< row_count; i++) {
                    Fetch();
                    local row = [];
                    for (local j = 0; j< column_type_list.len(); j++) {
                        //判断是否为空值
                        if (!Sq_CallFunc(S_Ptr("0x85F41B2"), "bool", ["pointer", "int"], this.C_Object, j)) {
                            row.push(null);
                        } else if (column_type_list[j] == "int") {
                            row.push(ReadIntColumn(j));
                        } else if (column_type_list[j] == "string") {
                            row.push(ReadStringColumn(j));
                        } else if (column_type_list[j] == "uint") {
                            row.push(ReadUIntColumn(j));
                        } else if (column_type_list[j] == "float") {
                            row.push(ReadFloatColumn(j));
                        } else if (column_type_list[j] == "binary") {
                            row.push(ReadBinaryColumn(j));
                        }
                    }
                    result_list.push(row);
                }
            }
        }
        return result_list;
    }

    //执行查询返回执行是否成功
    function Exec_Sql(sql) {
        local sql_ptr = Str_Ptr(sql);
        //set query
        local set_query = Sq_CallFunc(S_Ptr("0x83F41C0"), "int", ["pointer", "pointer"], this.C_Object, sql_ptr);
        //执行sql
        local sql_exec_result = Sq_CallFunc(S_Ptr("0x83F4326"), "int", ["pointer", "int"], this.C_Object, 1);
        return sql_exec_result;
    }


    //获取服务端版本
    function GetServerVersion() {
        return Sq_CallFunc(S_Ptr("0x83F460C"), "int", ["pointer"], this.C_Object);
    }
    //获取客户端版本
    function GetClientVersion() {
        return Sq_CallFunc(S_Ptr("0x83F4622"), "int", ["pointer"], this.C_Object);
    }
}

class MysqlPool {

    // 用于存储数据库的 IP 地址
    db_ip = null;
    // 用于存储数据库的端口号
    db_port = null;
    // 用于存储数据库的名称
    db_name = null;
    // 用于存储数据库的用户名
    db_username = null;
    // 用于存储数据库的密码
    db_password = null;

    //连接池大小
    PoolSize = 10;
    //连接编码
    Charset = "latin1";
    //连接池
    PoolList = null;

    //是否已经初始化
    IsInit = false;

    constructor() {
        PoolList = [];
        getroottable()._MysqlPoolObject <- this;
    }

    function GetInstance() {
        if (!(getroottable().rawin("_MysqlPoolObject"))) MysqlPool();
        // MysqlPool();
        return getroottable()._MysqlPoolObject;
    }

    //设置基础配置
    function SetBaseConfiguration(Ip, Port, Account, Password) {
        db_ip = Str_Ptr(Ip);
        db_port = Port;
        db_name = Str_Ptr("taiwan_cain");
        db_username = Str_Ptr(Account);
        db_password = Str_Ptr(Password);
    }

    //初始化连接池
    function Init() {
        if(IsInit)return;
        for (local i = 0; i< PoolSize; i++) {
            local Buffer = Mysql(db_ip, db_port, db_name, db_username, db_password);
            Buffer.Exec_Sql(format("SET NAMES %s", Charset));
            PoolList.append(Buffer);
            // print("创建了一条连接,编号: " + i + ",地址: " + Buffer + ",  指针地址: " + Buffer.C_Object);
        }
        IsInit = true;
    }

    function GetConnect() {
        local _Connect = PoolList.pop();
        if (_Connect.State == 0) {
            _Connect.State = 1;
            return _Connect;
        }
    }

    function PutConnect(_Connect) {
        if (_Connect.State == 1) {
            _Connect.State = 0;
            PoolList.append(_Connect);
        }
    }
}