/*
 * 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
 */

package com.pullenti.unitext.internal.zip;

// Huffman tree used for inflation
public class InflaterHuffmanTree {

    private static final int mAX_BITLEN = 15;

    private short[] tree;

    public static InflaterHuffmanTree DEFLITLENTREE;

    public static InflaterHuffmanTree DEFDISTTREE;


    public InflaterHuffmanTree(byte[] codeLengths) {
        this.buildTree(codeLengths);
    }

    private void buildTree(byte[] codeLengths) {
        int[] blCount = new int[mAX_BITLEN + 1];
        int[] nextCode = new int[mAX_BITLEN + 1];
        for (int i = 0; i < codeLengths.length; i++) {
            int bits = Byte.toUnsignedInt(codeLengths[i]);
            if (bits > 0) 
                blCount[bits]++;
        }
        int code = 0;
        int treeSize = 512;
        for (int bits = 1; bits <= mAX_BITLEN; bits++) {
            nextCode[bits] = code;
            code += blCount[bits] << ((16 - bits));
            if (bits >= 10) {
                int start = nextCode[bits] & 0x1ff80;
                int end = code & 0x1ff80;
                treeSize += (((end - start)) >> ((16 - bits)));
            }
        }
        tree = new short[treeSize];
        int treePtr = 512;
        for (int bits = mAX_BITLEN; bits >= 10; bits--) {
            int end = code & 0x1ff80;
            code -= blCount[bits] << ((16 - bits));
            int start = code & 0x1ff80;
            for (int i = start; i < end; i += 1 << 7) {
                tree[(int)DeflaterHuffman.bitReverse(i)] = (short)((((-treePtr) << 4) | bits));
                treePtr += 1 << ((bits - 9));
            }
        }
        for (int i = 0; i < codeLengths.length; i++) {
            int bits = Byte.toUnsignedInt(codeLengths[i]);
            if (bits == 0) 
                continue;
            code = nextCode[bits];
            int revcode = (int)DeflaterHuffman.bitReverse(code);
            if (bits <= 9) {
                do{
                    tree[revcode] = (short)(((i << 4) | bits));
                    revcode += 1 << bits;
                } while (revcode < 512); 
            }
            else {
                int subTree = (int)tree[revcode & 511];
                int treeLen = 1 << ((subTree & 15));
                subTree = -((subTree >> 4));
                do{
                    tree[subTree | ((revcode >> 9))] = (short)(((i << 4) | bits));
                    revcode += 1 << bits;
                } while (revcode < treeLen); 
            }
            nextCode[bits] = code + (1 << ((16 - bits)));
        }
    }

    public int getSymbol(StreamManipulator input) {
        int lookahead;
        int symbol;
        if ((((lookahead = input.peekBits(9)))) >= 0) {
            if ((((symbol = (int)tree[lookahead]))) >= 0) {
                input.dropBits(symbol & 15);
                return symbol >> 4;
            }
            int subtree = -((symbol >> 4));
            int bitlen = symbol & 15;
            if ((((lookahead = input.peekBits(bitlen)))) >= 0) {
                symbol = (int)tree[subtree | ((lookahead >> 9))];
                input.dropBits(symbol & 15);
                return symbol >> 4;
            }
            else {
                int bits = input.getAvailableBits();
                lookahead = input.peekBits(bits);
                symbol = (int)tree[subtree | ((lookahead >> 9))];
                if (((symbol & 15)) <= bits) {
                    input.dropBits(symbol & 15);
                    return symbol >> 4;
                }
                else 
                    return -1;
            }
        }
        else {
            int bits = input.getAvailableBits();
            lookahead = input.peekBits(bits);
            symbol = (int)tree[lookahead];
            if (symbol >= 0 && ((symbol & 15)) <= bits) {
                input.dropBits(symbol & 15);
                return symbol >> 4;
            }
            else 
                return -1;
        }
    }
    public InflaterHuffmanTree() {
    }
    
    static {
        try {
            byte[] codeLengths = new byte[288];
            int i = 0;
            while (i < 144) {
                codeLengths[i++] = (byte)8;
            }
            while (i < 256) {
                codeLengths[i++] = (byte)9;
            }
            while (i < 280) {
                codeLengths[i++] = (byte)7;
            }
            while (i < 288) {
                codeLengths[i++] = (byte)8;
            }
            DEFLITLENTREE = new InflaterHuffmanTree(codeLengths);
            codeLengths = new byte[32];
            i = 0;
            while (i < 32) {
                codeLengths[i++] = (byte)5;
            }
            DEFDISTTREE = new InflaterHuffmanTree(codeLengths);
        } catch (Exception ex) {
        }
    }
}
