/*
 * 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 Stream = require("./../../../unisharp/Stream");
const MemoryStream = require("./../../../unisharp/MemoryStream");

class LzwDecoder {
    
    constructor() {
        this.m_AndTable = new Int32Array([511, 1023, 2047, 4095]);
        this.m_StringTable = null;
        this.m_Data = null;
        this.m_TableIndex = 0;
        this.m_BitsToGet = 9;
        this.m_BytePointer = 0;
        this.m_DataBuffer = 0;
        this.m_NextBits = 0;
    }
    
    decode(data) {
        let outputStream = new MemoryStream();
        this._initializeDictionary();
        this.m_Data = data;
        this.m_BytePointer = 0;
        this.m_DataBuffer = 0;
        this.m_NextBits = 0;
        let code = 0;
        let oldCode = 0;
        let str = [ ];
        let inits = 0;
        while ((((code = this._getNextCode()))) !== 257) {
            if (code === 256) {
                this._initializeDictionary();
                inits++;
                code = this._getNextCode();
                if (code === 257) 
                    break;
                if (code === 256) {
                }
                outputStream.write(this.m_StringTable[code], 0, this.m_StringTable[code].length);
                oldCode = code;
            }
            else if (code < this.m_TableIndex) {
                str = this.m_StringTable[code];
                outputStream.write(str, 0, str.length);
                this._addEntry(this.m_StringTable[oldCode], str[0]);
                oldCode = code;
            }
            else {
                str = this.m_StringTable[oldCode];
                outputStream.write(str, 0, str.length);
                this._addEntry(str, str[0]);
                outputStream.writeByte(str[0]);
                oldCode = code;
            }
        }
        if (outputStream.length > (0)) 
            return outputStream.toByteArray();
        return null;
    }
    
    _initializeDictionary() {
        if (this.m_StringTable === null) {
            this.m_StringTable = new Array();
            for (let i = 0; i < 8192; i++) {
                this.m_StringTable.push(null);
            }
            for (let i = 0; i < 256; i++) {
                this.m_StringTable[i] = new Uint8Array(1);
                this.m_StringTable[i][0] = i;
            }
        }
        else 
            for (let i = 256; i < this.m_StringTable.length; i++) {
                this.m_StringTable[i] = null;
            }
        this.m_TableIndex = 258;
        this.m_BitsToGet = 9;
    }
    
    _addEntry(oldstring, newstring) {
        let length = oldstring.length;
        let str = new Uint8Array(length + 1);
        for(let iii = 0; iii < (length); iii++) str[(0) + iii] = oldstring[(0) + iii];
        str[length] = newstring;
        this.m_StringTable[this.m_TableIndex++] = str;
        if (this.m_TableIndex === 511) 
            this.m_BitsToGet = 10;
        else if (this.m_TableIndex === 1023) 
            this.m_BitsToGet = 11;
        else if (this.m_TableIndex === 2047) 
            this.m_BitsToGet = 12;
    }
    
    _getNextCode() {
        if (this.m_BytePointer >= this.m_Data.length) 
            return 257;
        this.m_DataBuffer = (this.m_DataBuffer << 8) | (((this.m_Data[this.m_BytePointer++]) & 0xff));
        this.m_NextBits += 8;
        if (this.m_NextBits < this.m_BitsToGet) {
            if (this.m_BytePointer >= this.m_Data.length) 
                return 257;
            this.m_DataBuffer = (this.m_DataBuffer << 8) | (((this.m_Data[this.m_BytePointer++]) & 0xff));
            this.m_NextBits += 8;
        }
        let code = ((this.m_DataBuffer >> ((this.m_NextBits - this.m_BitsToGet)))) & this.m_AndTable[this.m_BitsToGet - 9];
        this.m_NextBits -= this.m_BitsToGet;
        if (code === 256) {
        }
        return code;
    }
}


module.exports = LzwDecoder