/// @file symbolweightvector.cpp
/// Helper classes for working with probability/weight vectors
///
/// @remarks
///
///- These classes are basically just wrappers around vectors of numbers
///  which represent the probability or occurrence count of symbols.
///
///- A typical use for one of these classes is as the vector of symbol
///  probabilities which is updated by the modeller and given to the
///  coder in order to perform arithmetic coding.
///
///- Alternatively it could be used as a vector of frequencies to be given
///  to a huffman coder.
///
///- This class implements the standard octane API, so can save/load state and
///  report on memory usage.
///
/// @author mouser
/// @date   2003.07.29
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
// application includes
#include "symbolweightvector.hpp"
// system includes
using namespace std;
//---------------------------------------------------------------------------



//---------------------------------------------------------------------------
// OCTANE PUBLIC API - AUXILIARY FUNCTIONS - these are supported by all derived classes

void SymbolWeightVector::ShowDebuggingInfo()
{
	// list the weight vectors
	cout << "Symbol Weight Vector ("<<symbolcount<<" symbols):"<<endl;
	for (int count=0;count<symbolcount;++count)
		cout << " " << count << ": " << weightvector[count] << "\n";
	cout << endl;
}

unsigned int SymbolWeightVector::GetMemoryUsed()
{
	// memory/file usage (in bytes)	
	// ATTN: this is only approximate - vector will actually use more - is there a way to get good memory usage info?
	return (unsigned int)(sizeof(this)+sizeof(TSymbolWeightVectorWeight)*weightvector.capacity());
}

unsigned int SymbolWeightVector::GetDiskspaceUsed(bool fortempdecompressiononly)
{
	// how much disk space will it take to save this vector?
	// its just size of an int and then the data
	return (unsigned int)(sizeof(int)+sizeof(TSymbolWeightVectorWeight)*symbolcount);
}

bool SymbolWeightVector::SaveState(bitwriter &to,bool fortempdecompressiononly)
{
	// save state
	// return true on success
	to.put(symbolcount);
	for (int count=0;count<symbolcount;++count)
		to.put(weightvector[count]);
	return true;
}

bool SymbolWeightVector::LoadState(bitreader &from)
{
	// load state
	from.get(symbolcount);
	// force size of vector
	SetSymbolCount(symbolcount);
	// read weights
	for (int count=0;count<symbolcount;++count)
		from.get(weightvector[count]);
	// return true on success
	return true;
}
//---------------------------------------------------------------------------


//---------------------------------------------------------------------------
// SYMBOLWEIGHTVECTOR PUBLIC API - SYMBOL ACCESS

void SymbolWeightVector::ResetWeights()
{
	// reset frequencies(probabilities)
	for (int count=0;count<symbolcount;++count)
		weightvector[count]=0;
}

void SymbolWeightVector::NormalizeToProbabilityDistribution()
{
	// normalize into a probability distribution

	// compute sum
	TSymbolWeightVectorWeight sumweight=0;
	for (int count=0;count<symbolcount;++count)
		sumweight+=weightvector[count];
	// now divide by sum to normalize
	if (sumweight>0)
		{
		for (int count=0;count<symbolcount;++count)
			weightvector[count]/=sumweight;
		}
}

void SymbolWeightVector::SetSymbolCount(int newsize)
{
	// set the number of symbols we should store weights for (this will contract or enlarge vector)
	weightvector.resize(newsize);
	symbolcount=newsize;
}

bool SymbolWeightVector::CountSymbolFrequencies(OctaneParser *parserp, bitreader &from)
{
	// higher level function for automatic setting of frequencies with help of parser; returns true on success
	bool bretv=true;
	int symbolnumber;

	// set our weight vector to size of symbolcount
	SetSymbolCount(parserp->GetSymbolCount());
	// reset probabilities
	ResetWeights();

	// now parse input and count frequencies, OOP parsing a symbol from parser until we hit end
	while (parserp->ParseNextSymbolFromInput(from,symbolnumber))
		IncremementSymbolWeight(symbolnumber);
		
	// return success
	return bretv;

}

void SymbolWeightVector::EnforceZeroCountFloor(TSymbolWeightVectorWeight symbolfloorval)
{
	// it's common that we may have symbols for characters we dont see for completeness
	// and it's common to want to force these to some minimal value (like 1)
	for (int count=0;count<symbolcount;++count)
		{
		if (weightvector[count]==0)
			weightvector[count]=symbolfloorval;
		}
}
//---------------------------------------------------------------------------

