"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.TeradataConnection = void 0;
const koffi = __importStar(require("koffi"));
const fs = require("fs");
const path = require("path");
const os = require("os");
const teradata_cursor_1 = require("./teradata-cursor");
const teradata_logging_1 = require("./teradata-logging");
const teradata_exceptions_1 = require("./teradata-exceptions");
class TeradataConnection {
    constructor() {
        this.sVersionNumber = "";
        this.lib = {};
        if (!["arm64", "x64"].includes(process.arch)) {
            throw new Error("This package requires 64-bit Node.js. 32-bit Node.js is not supported.");
        }
        const sPackageJsonPathName = path.resolve(__dirname, "..", "package.json");
        try {
            const packageJson = fs.readFileSync(sPackageJsonPathName);
            JSON.parse(packageJson, (key, value) => {
                if (key === "version") {
                    this.sVersionNumber = value;
                }
            });
        }
        catch (error) {
            console.log(`sPackageJsonPathName=${sPackageJsonPathName}`);
            fs.stat(sPackageJsonPathName, (err, stat) => {
                if (err) {
                    console.log(err);
                }
                else {
                    if (stat.isFile()) {
                        console.log(stat);
                    }
                    else {
                        console.log(`${sPackageJsonPathName} is not a file.`);
                    }
                }
            });
            throw new teradata_exceptions_1.OperationalError(error.message);
        }
        this.nId = ++TeradataConnection.nInstanceCount;
        this.poolHandle = null;
        this.logLevel = 0;
        this.logger = new teradata_logging_1.TeradataLogging(this.logLevel);
        const osType = process.platform;
        const bARM = process.arch.startsWith("arm") || process.arch.startsWith("aarch");
        let sExtension = "";
        if (osType === "win32") {
            sExtension = "dll";
        }
        else if (osType === "darwin") {
            sExtension = "dylib";
        }
        else if (bARM) {
            sExtension = "arm.so";
        }
        else {
            sExtension = "so";
        }
        const sLibPathName = path.resolve(__dirname, "teradatasql." + sExtension);
        try {
            this.gosideLib = koffi.load(`${sLibPathName}`);
        }
        catch (error) {
            console.log(`sLibPathName=${sLibPathName}`);
            fs.stat(sLibPathName, (err, stat) => {
                if (err) {
                    console.log(err);
                }
                else {
                    if (stat.isFile()) {
                        console.log(stat);
                    }
                    else {
                        console.log(`${sLibPathName} is not a file.`);
                    }
                }
            });
            throw new teradata_exceptions_1.OperationalError(error.message);
        }
        try {
            this.lib.jsgoCreateConnection = this.gosideLib.func("void jsgoCreateConnection(uint64_t, _In_ char*, _In_ char*, _Out_ str*!, _Inout_ uint64_t*)");
            this.lib.jsgoCloseConnection = this.gosideLib.func("void jsgoCloseConnection(uint64_t, uint64_t, _Out_ str*!)");
            this.lib.jsgoCancelRequest = this.gosideLib.func("void jsgoCancelRequest(uint64_t, uint64_t, _Out_ str*!)");
            this.lib.jsgoCreateRows = this.gosideLib.func("void jsgoCreateRows(uint64_t, uint64_t, _In_ char*, uint64_t, _In_ void*, _Out_ str*!, _Inout_ uint64_t*)");
            this.lib.jsgoFetchRow = this.gosideLib.func("void jsgoFetchRow(uint64_t, uint64_t, _Out_ str*!, _Inout_ int64_t*, _Out_ void**!, int64_t)");
            this.lib.jsgoResultMetaData = this.gosideLib.func("void jsgoResultMetaData(uint64_t, uint64_t, _Out_ str*!, _Inout_ uint64_t*, _Inout_ int*, _Out_ void**!)");
            this.lib.jsgoNextResult = this.gosideLib.func("void jsgoNextResult(uint64_t, uint64_t, _Out_ str*!, _Inout_ char*)");
            this.lib.jsgoCloseRows = this.gosideLib.func("void jsgoCloseRows(uint64_t, uint64_t, _Out_ str*!)");
            this.lib.jsgoAsyncCreateRows = this.gosideLib.func("void jsgoAsyncCreateRows(uint64_t, uint64_t, _In_ char*, uint64_t, _In_ void*, _Out_ str*!, _Inout_ uint64_t*)");
            this.lib.jsgoPollRows = this.gosideLib.func("void jsgoPollRows(uint64_t, uint64_t, _Out_ str*!, _Inout_ uint64_t*)");
        }
        catch (error) {
            throw new teradata_exceptions_1.OperationalError(error.message);
        }
    }
    get Id() {
        return this.nId;
    }
    get uLog() {
        return this.logLevel;
    }
    get uPoolHandle() {
        return this.poolHandle;
    }
    get autocommit() {
        this.logger.traceLog("> enter autocommit getter");
        let result;
        try {
            const cur = this.cursor();
            cur.execute("{fn teradata_nativesql}{fn teradata_autocommit}");
            const row = cur.fetchone();
            if (row && row[0] === "true") {
                result = true;
            }
            else {
                result = false;
            }
            cur.close();
            return result;
        }
        finally {
            this.logger.traceLog("< leave autocommit getter");
        }
    }
    set autocommit(value) {
        this.logger.traceLog("> enter autocommit setter");
        if (typeof value !== "boolean") {
            throw new TypeError(`value unexpected type ${typeof value}`);
        }
        try {
            const s = value ? "on" : "off";
            const cur = this.cursor();
            cur.execute("{fn teradata_nativesql}{fn teradata_autocommit_" + s + "}");
            cur.close();
        }
        finally {
            this.logger.traceLog("< leave autocommit setter");
        }
    }
    cursor() {
        return new teradata_cursor_1.TeradataCursor(this, this.lib);
    }
    connect(connectParams = {}, sJSON = "{}") {
        const kwargs = { ...JSON.parse(sJSON) };
        Object.keys(kwargs).forEach((key) => {
            if (kwargs[key] === true) {
                kwargs[key] = "true";
            }
            else if (kwargs[key] === false) {
                kwargs[key] = "false";
            }
        });
        const traceback = Error().stack;
        let sFrame;
        let sFrames = [];
        let listFrames = [];
        if (traceback) {
            traceback.replace(path.sep, "/");
            sFrames = traceback.split("\n    at").slice(1);
            for (const fr of sFrames) {
                sFrame = fr.split("/").pop();
                if (sFrame) {
                    sFrame = sFrame.split(":")[0];
                    if (!listFrames.includes(sFrame)) {
                        listFrames.push(sFrame);
                    }
                }
            }
        }
        if (process.platform === "win32") {
            listFrames = listFrames.map((frame) => frame.split(" (C")[0].trim());
        }
        kwargs.client_kind = "S";
        kwargs.client_vmname = "Node.js " + process.version;
        kwargs.client_osname = os.version().split(":")[0] + " " + os.arch();
        kwargs.client_stack = listFrames.join(" ");
        kwargs.client_extra = "NODEJS=" + process.version + ";";
        const combinedConnectParams = { ...connectParams, ...kwargs };
        this.logLevel = combinedConnectParams.log ? Number(combinedConnectParams.log) : 0;
        this.logger = new teradata_logging_1.TeradataLogging(this.logLevel);
        this.logger.traceLog("> enter connect TeradataConnection");
        try {
            let outputPtrPtr = [null];
            let poolHandlePtr = [0];
            this.lib.jsgoCreateConnection(this.uLog, this.sVersionNumber, JSON.stringify(combinedConnectParams), outputPtrPtr, poolHandlePtr);
            const outputString = outputPtrPtr[0];
            if (outputString) {
                throw new teradata_exceptions_1.OperationalError(outputString);
            }
            this.poolHandle = poolHandlePtr[0];
        }
        finally {
            this.logger.traceLog("< leave connect TeradataConnection");
        }
    }
    close() {
        this.logger.traceLog("> enter close TeradataConnection");
        try {
            if (this.poolHandle === null) {
                throw new teradata_exceptions_1.OperationalError("null is not a valid connection pool handle");
            }
            let outputPtrPtr = [null];
            this.lib.jsgoCloseConnection(this.uLog, this.poolHandle, outputPtrPtr);
            const outputString = outputPtrPtr[0];
            if (outputString) {
                throw new teradata_exceptions_1.OperationalError(outputString);
            }
        }
        finally {
            this.logger.traceLog("< leave close TeradataConnection");
        }
    }
    cancel() {
        this.logger.traceLog("> enter cancel TeradataConnection");
        try {
            let outputPtrPtr = [null];
            this.lib.jsgoCancelRequest(this.uLog, this.poolHandle, outputPtrPtr);
            const outputString = outputPtrPtr[0];
            if (outputString) {
                throw new teradata_exceptions_1.OperationalError(outputString);
            }
        }
        finally {
            this.logger.traceLog("< leave cancel TeradataConnection");
        }
    }
    commit() {
        this.logger.traceLog("> enter commit TeradataConnection");
        try {
            this.cursor().execute("{fn teradata_commit}");
        }
        finally {
            this.logger.traceLog("< leave commit TeradataConnection");
        }
    }
    rollback() {
        this.logger.traceLog("> enter rollback TeradataConnection");
        try {
            this.cursor().execute("{fn teradata_rollback}");
        }
        finally {
            this.logger.traceLog("< leave rollback TeradataConnection");
        }
    }
}
exports.TeradataConnection = TeradataConnection;
TeradataConnection.nInstanceCount = 0;
//# sourceMappingURL=teradata-connection.js.map