namespace SharpCompress.Compressors.Shrink;

internal class BitStream
{
    private const int EOF = 1234;
    private byte[] _src;
    private int _srcLen;
    private int _byteIdx;
    private int _bitIdx;
    private int _bitsLeft;
    private ulong _bitBuffer;
    private static uint[] _maskBits = new uint[17]
    {
        0U,
        1U,
        3U,
        7U,
        15U,
        31U,
        63U,
        (uint)sbyte.MaxValue,
        byte.MaxValue,
        511U,
        1023U,
        2047U,
        4095U,
        8191U,
        16383U,
        (uint)short.MaxValue,
        ushort.MaxValue,
    };

    public BitStream(byte[] src, int srcLen)
    {
        _src = src;
        _srcLen = srcLen;
        _byteIdx = 0;
        _bitIdx = 0;
    }

    public int BytesRead => (_byteIdx << 3) + _bitIdx;

    private int NextByte()
    {
        if (_byteIdx >= _srcLen)
        {
            return EOF;
        }

        return _src[_byteIdx++];
    }

    public int NextBits(int nbits)
    {
        var result = 0;
        if (nbits > _bitsLeft)
        {
            int num;
            while (_bitsLeft <= 24 && (num = NextByte()) != 1234)
            {
                _bitBuffer |= (ulong)num << _bitsLeft;
                _bitsLeft += 8;
            }
        }
        result = (int)(_bitBuffer & _maskBits[nbits]);
        _bitBuffer >>= nbits;
        _bitsLeft -= nbits;
        return result;
    }

    public bool Advance(int count)
    {
        if (_byteIdx > _srcLen)
        {
            return false;
        }
        return true;
    }
}
