#include <ZUtil/ZName.hpp>
#include <ZUtil/ZAssert.hpp>
#include <ZUtil/ZAlloc.hpp>

#include <SST/SST_Hash.h>

ZName::ZName()
: Length(0), Hash(0)
{

}

/*************************************************************************/

ZName::ZName( const char *_string )
: Length(0), Hash(0)
{
	Length = _string != NULL ? strlen(_string) : 0;

	if (Length > ZNAME_MAX_LENGTH)
	{
		ZASSERT_RUNTIME_FAIL("ZName: Constructed from string with > ZNAME_MAX_LEN characters!");
		Length = ZNAME_MAX_LENGTH;
	}

	MemCopyChar(String, _string, Length);
	MemSetChar(&String[Length], '\0', ZNAME_MAX_LENGTH - Length + 1);

	Hash = SST_Crypto_HashJCR2(String, Length);
}

/*************************************************************************/

ZName::ZName( const ZString& _string )
{
	Length = _string.Length();

	if (Length > ZNAME_MAX_LENGTH)
	{
		ZASSERT_RUNTIME_FAIL("ZName: Constructed from string with > ZNAME_MAX_LEN characters!");
		Length = ZNAME_MAX_LENGTH;
	}

	MemCopyChar(String, _string.Data(), Length);
	MemSetChar(&String[Length], '\0', ZNAME_MAX_LENGTH - Length + 1);

	Hash = SST_Crypto_HashJCR2(String, Length);
}

/*************************************************************************/

ZName::ZName( const ZName& _other )
: Length(0), Hash(0)
{
	MemCopyChar(String, _other.String, ZNAME_MAX_LENGTH);

	Length = _other.Length;
	Hash = _other.Hash;	
}

/*************************************************************************/

ZName::ZName( uint64_t _hash )
: Length(0), Hash(_hash)
{
	const char* precompStr = "<precomputed>";

	MemCopyChar(String, precompStr, sizeof(precompStr));

	Length = sizeof(precompStr) - 1;
}

/*************************************************************************/

ZName::~ZName()
{

}

/*************************************************************************/

ZName& ZName::operator = ( const ZName& _other )
{
	MemCopyChar(String, _other.String, ZNAME_MAX_LENGTH);

	Length = _other.Length;
	Hash = _other.Hash;	

	return *this;
}

/*************************************************************************/

ZName& ZName::operator = ( const ZString& _string )
{
	Length = _string.Length();

	if (Length > ZNAME_MAX_LENGTH)
	{
		ZASSERT_RUNTIME_FAIL("ZName: Assigned from string with > ZNAME_MAX_LEN characters!");
		Length = ZNAME_MAX_LENGTH;
	}

	MemCopyChar(String, _string.Data(), Length);
	MemSetChar(&String[Length], '\0', ZNAME_MAX_LENGTH - Length + 1);

	Hash = SST_Crypto_HashJCR2(String, Length);

	return *this;
}

/*************************************************************************/

ZName& ZName::operator = (const char* _string )
{
	Length = _string != NULL ? strlen(_string) : 0;

	if (Length > ZNAME_MAX_LENGTH)
	{
		ZASSERT_RUNTIME_FAIL("ZName: Assigned from string with > ZNAME_MAX_LEN characters!");
		Length = ZNAME_MAX_LENGTH;
	}

	MemCopyChar(String, _string, Length);
	MemSetChar(&String[Length], '\0', ZNAME_MAX_LENGTH - Length + 1);

	Hash = SST_Crypto_HashJCR2(String, Length);

	return *this;
}

/*************************************************************************/

bool ZName::operator == ( const ZName& _other ) const
{
	#if ZSTL_CHECK_NAME
	
	bool ret = (Hash == _other.Hash);
	
	if (ret == true)
	{
		int strcmpRet = strcmp(String, _other.String);

		ZASSERT_RUNTIME(strcmpRet == 0, "ZName: Hash reported same, but failed strcmp!\n");
		
		return (strcmpRet == 0);
	}
	
	return ret;
	
	#else
	
	return Hash == _other.Hash;
	
	#endif
}

/*************************************************************************/

bool ZName::operator == ( const ZHashValue hash ) const
{
	return Hash == hash;
}

/*************************************************************************/

bool ZName::operator==( const ZString& _other ) const
{
	return Hash == ZName(_other);
}

/*************************************************************************/

bool ZName::operator != ( const ZName& _other ) const
{
	return !((*this) == _other);
}

/*************************************************************************/

ZName::operator ZHashValue() const
{
	return (ZHashValue)Hash;
}

/*************************************************************************/

ZName::operator ZString() const
{
	return ToString();
}

/*************************************************************************/

ZString ZName::ToString() const
{
	return ZString(String);
}

/*************************************************************************/

const char* ZName::Data() const
{
	return String;
}

/*************************************************************************/
