#include "BufferBitStream.h"

#include "ByteUtils.h"

#include <iostream>

bool BufferBitStream::isFinished() const
{
    return mByteOffset == static_cast<int>(mBuffer.size()) - 1;
}

std::vector<unsigned char> BufferBitStream::peekNextNBytes(unsigned n) const
{
    std::vector<unsigned char> ret (n, 0);
    unsigned count = 0;

    int start = mByteOffset;
    if (start<0)
    {
        start = 0;
    }

    for(unsigned idx=start; idx<start + n; idx++)
    {
        if (idx == mBuffer.size())
        {
            break;
        }

        ret[count] = mBuffer[idx];
        count ++;
    }
    return ret;
}

std::optional<unsigned char> BufferBitStream::readNextByte()
{
    if (mByteOffset + 1 == static_cast<int>(mBuffer.size()))
    {
        return std::nullopt;
    }
    else
    {
        mByteOffset++;
        mCurrentByte = mBuffer[mByteOffset];
        return mCurrentByte;
    }
}

void BufferBitStream::setBuffer(const std::vector<unsigned char>& data)
{
    mBuffer = data;
}

void BufferBitStream::writeByte(unsigned char data, bool checkOverflow)
{
    unsigned char out_byte{0};
    if (checkOverflow && mBitOffset > 0)
    {
        out_byte = ByteUtils::getLowerNBits(mCurrentByte, mBitOffset);
        out_byte |= data << mBitOffset;

        mCurrentByte = ByteUtils::getHigherNBits(data, mBitOffset);
    }
    else
    {
        out_byte = data;
    }

    if (mChecksumCalculator)
    {
        mChecksumCalculator->addValue(out_byte);
    }
    //std::cout << "Writing byte " << ByteUtils::toString(out_byte) << " had bitoffset of " << mBitOffset << std::endl;
    mBuffer.push_back(out_byte);
}


void BufferBitStream::writeBytes(const std::vector<unsigned char> data)
{
    std::copy(data.begin(), data.end(), std::back_inserter(mBuffer));
}

const std::vector<unsigned char>& BufferBitStream::getBuffer() const
{
    return mBuffer;
}

void BufferBitStream::reset()
{
    BitStream::reset();
    mBuffer.clear();
}

