/*
 * SDK Pullenti Unitext, version 4.33, fabruary 2026. Copyright (c) 2013-2026, Pullenti. All rights reserved. 
 * Non-Commercial Freeware and Commercial Software. 
 * This class is generated using the converter UniSharping (www.unisharping.ru) from Pullenti C# project. 
 * The latest version of the code is available on the site www.pullenti.ru
 */

const Utils = require("./../unisharp/Utils");
const Stream = require("./../unisharp/Stream");
const FileStream = require("./../unisharp/FileStream");

const EncodingStandard = require("./EncodingStandard");
const MiscHelper = require("./MiscHelper");
const EncodingWrapper = require("./EncodingWrapper");

// Поддержка работы с таблицами DBF
class DbfTable {
    
    constructor(fileName) {
        this.rowsCount = 0;
        this.m_Stream = null;
        this.m_FirstRecPos = 0;
        this.columnnNames = new Array();
        this.columnLengths = new Array();
        this.bufRec = null;
        this.m_Enc = null;
        this.values = new Array();
        this.percent = 0;
        this.m_Stream = new FileStream(fileName, "r", false);
        let buf = new Uint8Array(1024);
        if (this.m_Stream.read(buf, 0, 0x20) !== 0x20 || buf[0] !== (3)) 
            throw new Error("Bad DBF format");
        let headLen = ((buf[9]) << 8) | (buf[8]);
        let recLen = ((buf[11]) << 8) | (buf[10]);
        for (; (this.m_Stream.position + (0x20)) <= headLen; ) {
            if (this.m_Stream.read(buf, 0, 0x20) !== 0x20) 
                throw new Error("Bad DBF format");
            let i = 0;
            for (; i < 11; i++) {
                if (buf[i] === (0)) 
                    break;
            }
            let nam = MiscHelper.decodeStringAscii(buf, 0, i).trim();
            this.columnnNames.push(nam);
            this.columnLengths.push(buf[0x10]);
            this.values.push(null);
        }
        this.m_Stream.position = headLen - 1;
        let b = this.m_Stream.readByte();
        if (b !== 13) 
            throw new Error("Bad DBF format (end of head not 13)");
        let vals = new Array();
        let le = 0;
        for (const v of this.columnLengths) {
            le += v;
            vals.push(null);
        }
        if ((le + 1) !== recLen) 
            throw new Error(("Total columns length " + (le + 1) + " != length of record " + recLen));
        this.m_Enc = new EncodingWrapper(EncodingStandard.CP1251);
        this.bufRec = new Uint8Array(recLen);
        this.m_FirstRecPos = this.m_Stream.position;
        this.rowsCount = (Utils.intDiv((this.m_Stream.length - this.m_FirstRecPos), recLen));
    }
    
    close() {
        if (this.m_Stream !== null) 
            this.m_Stream.close();
        this.m_Stream = null;
    }
    
    getString(columnName) {
        let i = this.columnnNames.indexOf(columnName);
        if (i < 0) 
            return null;
        if (Utils.isNullOrEmpty(this.values[i])) 
            return null;
        return this.values[i];
    }
    
    getGuid(columnName) {
        let val = this.getString(columnName);
        if (Utils.isNullOrEmpty(val)) 
            return null;
        try {
            return val;
        } catch (ex) {
            return null;
        }
    }
    
    readNext(onlyColumnIndex = -1) {
        if (this.m_Stream === null) 
            return false;
        if (this.m_Stream.read(this.bufRec, 0, this.bufRec.length) !== this.bufRec.length) 
            return false;
        if (this.bufRec[0] !== (0x20)) 
            return false;
        let d = 1;
        let i = 0;
        for (i = 0; i < this.bufRec.length; i++) {
            let j = this.bufRec[i];
            if (j >= 0xE0 && j <= 0xEF) 
                j -= 0x30;
            if (j >= 0x80 && j <= 0xDF) 
                this.bufRec[i] = (j + 0x40);
            if (j === 0xF1) 
                this.bufRec[i] = 0xB8;
            if (j === 0xF0) 
                this.bufRec[i] = 0xA8;
        }
        for (i = 0; i < this.columnnNames.length; i++) {
            if ((onlyColumnIndex < 0) || onlyColumnIndex === i) {
                let val = this.m_Enc.getString(this.bufRec, d, this.columnLengths[i]).trim();
                this.values[i] = val;
            }
            d += this.columnLengths[i];
        }
        if (this.m_Stream.length < (100000)) 
            this.percent = (Utils.intDiv(this.m_Stream.position * (100), this.m_Stream.length));
        else 
            this.percent = (Utils.intDiv(this.m_Stream.position, (Utils.intDiv(this.m_Stream.length, 100))));
        return true;
    }
    
    reread() {
        if (this.m_Stream !== null) 
            this.m_Stream.position = this.m_FirstRecPos;
    }
}


module.exports = DbfTable