/// @file compressormanager.cpp
/// Compression/Decompression manager classes
///
/// @remarks
/// These classes holds a collection of Compressor derived classes
///  and is used for runtime selection of which algorithm to test.
///
/// @author mouser
/// @author Jibz
/// @date   2003.07.29
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
// application includes
#include "compressormanager.hpp"
// system includes
#include <iostream>
#include <iomanip>
using namespace std;
//---------------------------------------------------------------------------



//---------------------------------------------------------------------------
// global single instance of the CompressorManager.
//  this is the object that all compressors will register with.
// because this is a global, it will be initialized to NULL on startup
//  according to ansi c.
CompressorManager* global_compressormanagerp;
//---------------------------------------------------------------------------



//---------------------------------------------------------------------------
CompressorManager::CompressorManager()
{
	// constructor
	Initialize();
}

CompressorManager::~CompressorManager()
{
	// destructor
	// free registered compressors?
	DeInitialize();
}

void CompressorManager::Initialize()
{
	// This is called by code on startup, after all compressors have
	//  registered with us.  now we select a default compressor for testing.
}

void CompressorManager::DeInitialize()
{
	// Called on shutdown
	// We don't have to free the globally auto-registered base types, BUT we do need to free the dynamically allocated instantiated types
	vector<OctaneCompressor*>::iterator index;
	for (index=compressorvector_instantiated.begin();index!=compressorvector_instantiated.end();++index)
		delete (*index);
	compressorvector_instantiated.clear();
}
//---------------------------------------------------------------------------



//---------------------------------------------------------------------------
void CompressorManager::RegisterBaseCompressor(OctaneCompressor* compressorp)
{
	// register a new compressor
	// show some debug info?
	//   cout << "$DEBUG Registering compressor '" << compressorp->get_compressor_name() << "'."<<endl;
	compressorvector_basetypes.push_back(compressorp);
	// should we set this new compressor to be our current compressor?
	//	if (currentcompressorp==NULL || true)
	//		currentcompressorp=compressorp;
}

void CompressorManager::UnRegisterBaseCompressor(OctaneCompressor* compressorp)
{
	// remove a compressor from our list of registered components.
	// you don't have to call this on exit of the program, only if you are for some reason
	//  removing compressors during the execution of the program.
	vector<OctaneCompressor*>::iterator index;
	for (index=compressorvector_basetypes.begin();index!=compressorvector_basetypes.end();++index)
		{
		if (*index==compressorp)
			{
			// found it, so remove it
			compressorvector_basetypes.erase(index);
			break;
			}
		}
}

OctaneCompressor* CompressorManager::FindBaseCompressorClass(const std::string &compressorname)
{
	// remove a compressor from our list of registered components.
	// you don't have to call this on exit of the program, only if you are for some reason
	//  removing compressors during the execution of the program.
	vector<OctaneCompressor*>::iterator index;
	for (index=compressorvector_basetypes.begin();index!=compressorvector_basetypes.end();++index)
		{
		if ((*index)->GetClassName()==compressorname)
			return (*index);
		}
	return NULL;
}
//---------------------------------------------------------------------------



//---------------------------------------------------------------------------
// Create a new compressor based on file info and load state
OctaneCompressor* CompressorManager::CreateCompressorFromSavedStream(bitreader &from)
	{
	// in the saved stream we expect to find a 'header' which tells us the 1)compressorclass, 2)compressorname, and 3)compressorguid
	// then we create a compressor of that type, and tell it to read its state info from the remainder of stream

	// read standard compressor header (see OctaneCompressor::Save() for where this is written)
	string compressorclassname;
	string compressorname;
	short int compressorguid;
	from.get(compressorclassname);
	from.get(compressorname);
	from.get(compressorguid);
	
	// select base compressor class type
	OctaneCompressor *compressorp = FindBaseCompressorClass(compressorclassname);
	if (compressorp==NULL)
		{
		// couldn't find base class
		cout << "ERROR: compressor in file is based on compressor class '"<<compressorclassname<<"' which is not known."<<endl;
		return NULL;
		}

	// ask base class to make us a derived class
	compressorp=compressorp->MakeCompressorInstantiation();
	if (compressorp==NULL)
		{
		// couldn't find base class
		cout << "ERROR: failed to instantiate a derived compressor from base class '"<<compressorclassname<<"'."<<endl;
		return NULL;
		}

	// now set details (compressor name and guid) from file
	compressorp->SetInfo(compressorname,compressorguid);

	// now load the details from the file
	bool bretv=compressorp->LoadState(from);
	if (!bretv)
		{
		delete compressorp;
		compressorp=NULL;
		}

	// return pointer to newly created compressor
	return compressorp;
	}


// Add an instantiated compressor to our instantiated list
bool CompressorManager::AddCompressor (OctaneCompressor *compressorp)
	{
	// just add a compressor to the instantiated vector
	// show some debug info?
	//   cout << "$DEBUG Adding instantiated compressor '" << compressorp->get_compressor_name() << "'."<<endl;
	compressorvector_instantiated.push_back(compressorp);
	return true;
	}


// Delete an instantiated compressor to our instantiated list
bool CompressorManager::DeleteCompressor (OctaneCompressor *compressorp)
	{
	// just add a compressor to the instantiated vector
	vector<OctaneCompressor*>::iterator index;
	for (index=compressorvector_instantiated.begin();index!=compressorvector_instantiated.end();++index)
		{
		if (*index==compressorp)
			{
			// found it, so remove it
			compressorvector_instantiated.erase(index);
			return true;
			}
		}
	return false;
	}


// Find the pointer to the instantiated compressor referred to by idstring
// idstring can be [$name|$num|G$guid]
OctaneCompressor* CompressorManager::FindInstantiatedCompressorpFromStringId(string idstring)
	{
	// look up a compressor based on different strings
	if (idstring=="")
		return NULL;

	// there are 3 ways to specify an instantiated compressor
	OctaneCompressor* compressorp=NULL;
	int indexnum;
	indexnum = atoi(idstring.c_str());
	
	if (indexnum>0 || idstring=="0")
		{
		// user gave us an index
		if (indexnum<0 || (unsigned int)indexnum>=compressorvector_instantiated.size())
			return NULL;
		compressorp=compressorvector_instantiated[indexnum];
		return compressorp;
		}

	// ok its either a full name or a guid
	// first we try to look it up by name
	vector<OctaneCompressor*>::iterator index;
	for (index=compressorvector_instantiated.begin();index!=compressorvector_instantiated.end();++index)
		{
		if ((*index)->GetInstantiatedName()==idstring)
			return (*index);
		}

	// we didn't find it, so try to check its guid
	if (idstring[0]!='g' && idstring[0]!='G')
		return NULL;
	idstring=idstring.substr(1,idstring.length()-1);
	indexnum=atoi(idstring.c_str());
	if (indexnum>0 || idstring=="0")
		{
		for (index=compressorvector_instantiated.begin();index!=compressorvector_instantiated.end();++index)
			{
			if ((*index)->GetGuid()==indexnum)
				return (*index);
			}
		}
	return NULL;
	}


OctaneCompressor* CompressorManager::FindInstantiatedCompressorpFromGuid(unsigned short int guidindex)
{
	// Find the pointer to the instantiated compressor referred to by a guid
	// return NULL if not found
	vector<OctaneCompressor*>::iterator index;
	for (index=compressorvector_instantiated.begin();index!=compressorvector_instantiated.end();++index)
		{
		if ((*index)->GetGuid()==guidindex)
			return (*index);
		}
	return NULL;
}
//---------------------------------------------------------------------------
