/** @file stringtable.cpp
 *	Definition of string table for EABaseTypes
 *	@headerfile stringtable.h "EABaseTypes/stringtable.h"
 *	@author Chris Burns (cburns@ea.com)
 *
 *	EABaseTypes
 *	(c) 2012 Electronic Arts Inc.
 */

#include "EABaseTypes/stringtable.h"

namespace EA
{
	StringTable::StringTable(EA::Allocator::ICoreAllocator* allocator):
		mLock(),
		mAllocator(allocator),
		mTable(allocator),
		mEmptyString(allocator, "")
	{
	}

	StringTable::~StringTable()
	{
	}

	//lint -efunc(904, EA::StringTable::Intern) 
	const RawString* StringTable::Intern(const char* val)
	{
		if(mEmptyString.compare(val) == 0)
		{
			return &mEmptyString;
		}
		else
		{
			EA::Thread::AutoFutex autoLock(mLock);

			StringInternMap::iterator it = mTable.find_as(val, eastl::hash<char*>(),  eastl::equal_to_2<EA::RawString, const char*>());
			if( it != mTable.end() )
			{
				++((*it).second);

				return &((*it).first);
			}
			else
			{
				StringInternMap::insert_return_type result = mTable.insert(RawString(mAllocator, val));
				result.first->second = 1;

				return &(result.first->first);
			}
		}
	}
	
	const RawString* StringTable::Intern(const char* val, size_t length)
	{
		if(length == 0)
		{
			return &mEmptyString;
		}
		else
		{
			EA::Thread::AutoFutex autoLock(mLock);
			
			RawString str(mAllocator);
			str.assign(val, static_cast<RawString::size_type>(length));

			StringInternMap::iterator it = mTable.find(str);
			if( it != mTable.end() )
			{
				++((*it).second);

				return &((*it).first);
			}
			else
			{	
				StringInternMap::insert_return_type result = mTable.insert(str);
				result.first->second = 1;

				return &(result.first->first);
			}
		}
	}

	void StringTable::Release(const RawString* str)
	{
		if(str != &mEmptyString)
		{
			EA::Thread::AutoFutex autoLock(mLock);

			StringInternMap::iterator it = mTable.find((*str));
			int refCount = (*it).second;
			if(refCount <= 1)
			{
				mTable.erase(it);
			}
			else
			{
				(*it).second = refCount - 1;
			}
		}
	}

#if defined(EA_RUNTIME_TESTING)
	int StringTable::GetRefCount(const RawString* str)
	{
		int refCount = -1;

		if(str != &mEmptyString)
		{
			EA::Thread::AutoFutex autoLock(mLock);

			StringInternMap::iterator it = mTable.find((*str));
			refCount = (*it).second;
		}

		return refCount;
	}

	unsigned int StringTable::GetSize()
	{
		return mTable.size();
	}
#endif
}
