/* Copyright (C) Teemu Suutari */

#include "RangeDecoder.hpp"


namespace ancient::internal
{

RangeDecoder::BitReader::BitReader()
{
	// nothing needed
}

RangeDecoder::BitReader::~BitReader()
{
	// nothing needed
}

RangeDecoder::RangeDecoder(BitReader &bitReader,uint16_t initialValue) :
		_bitReader(bitReader),
		_stream(initialValue)
{
	// nothing needed
}

RangeDecoder::~RangeDecoder()
{
	// nothing needed
}

uint16_t RangeDecoder::decode(uint16_t length)
{
	return ((uint32_t(_stream-_low)+1)*length-1)/(uint32_t(_high-_low)+1);
}

void RangeDecoder::scale(uint16_t newLow,uint16_t newHigh,uint16_t newRange)
{
	uint32_t range=uint32_t(_high-_low)+1;
	_high=(range*newHigh)/newRange+_low-1;
	_low=(range*newLow)/newRange+_low;

	auto doubleContext=[&](uint16_t decr)
	{
		_low-=decr;
		_high-=decr;
		_stream-=decr;
		_low<<=1;
		_high=(_high<<1)|1U;
		_stream=(_stream<<1)|_bitReader.readBit();
	};

	for (;;)
	{
		if (_high<0x8000U)
		{
			doubleContext(0U);
		} else if (_low>=0x8000U) {
			doubleContext(0x8000U);
		} else if (_low>=0x4000U && _high<0xc000U) {
			doubleContext(0x4000U);
		} else break;
	}
}

}
