#pragma once

#include <map>
#include <set>
#include "Serialization.h"

// simple template class used to support OBSE custom data types (strings, arrays, etc)

template <class Var>
class VarMap
{
protected:
	typedef std::map<UInt32, Var*>	_VarMap;
	typedef std::set<UInt32>		_VarIDs;

	_VarMap		vars;
	_VarIDs		tempVars;		// set of IDs of unreferenced vars, makes for easy cleanup
	_VarIDs		availableVars;	// IDs < greatest used ID available as IDs for new vars

	UInt32	GetUnusedID()
	{
		UInt32 id = 1;

		if (availableVars.size())
		{
			id = *availableVars.begin();
			availableVars.erase(id);
		}
		else if (vars.size())
		{
			_VarMap::iterator iter = vars.end();
			--iter;
			id = iter->first + 1;
		}

		return id;

/*
		UInt32 id = 1;
		_VarMap::iterator itEnd = vars.end();
		while (vars.find(id) != itEnd)
		{
			id++;
		}
		return id;
*/
	}

public:
	VarMap()
	{
		//
	}

	~VarMap()
	{
		//
	}

	Var*	Get(UInt32 varID)
	{
		if (varID != 0) {
			_VarMap::iterator it = vars.find(varID);
			if (it != vars.end()) 
				return it->second;
		}
		return NULL;
	}

	bool	VarExists(UInt32 varID)
	{
		if (Get(varID))
			return true;
		else
		{
			_MESSAGE("Internal Error: initialized variable %d not found in varmap", varID);
			return false;
		}
	}

	void	Delete(UInt32 varID)
	{
		Var* var = Get(varID);
		if (var)
		{
			delete var;
			vars.erase(varID);
			availableVars.insert(varID);
		}
	}

	void Reset(OBSESerializationInterface* intfc)
	{
		_VarMap::iterator itEnd = vars.end();
		_VarMap::iterator iter = vars.begin();
		_VarMap::iterator toErase = iter;
		while (iter != itEnd)
		{
			delete iter->second;
			toErase = iter;
			++iter;
			vars.erase(toErase);
		}



		vars.clear();
		tempVars.clear();
		availableVars.clear();
	}

	void	MarkTemporary(UInt32 varID, bool bTemporary)
	{
		if (bTemporary)
			tempVars.insert(varID);
		else
			tempVars.erase(varID);
	}

	bool IsTemporary(UInt32 varID)
	{
		return (tempVars.find(varID) != tempVars.end()) ? true : false;
	}
};