#include "gats/dictionary.h"

#include "gats/boolean.h"
#include "gats/integer.h"
#include "gats/float.h"
#include "gats/string.h"
#include "gats/list.h"

template<>
uint32_t Bu::__calcHashCode<Gats::String>( const Gats::String &s )
{
	return __calcHashCode( dynamic_cast<const Bu::FString &>(s) );
}

Gats::Dictionary::Dictionary()
{
}

Gats::Dictionary::~Dictionary()
{
	for( iterator i = begin(); i; i++ )
	{
		delete *i;
	}
}

void Gats::Dictionary::write( Bu::Stream &rOut ) const
{
	rOut.write("d", 1 );
	for( const_iterator i= begin(); i; i++ )
	{
		i.getKey().write( rOut );
		(*i)->write( rOut );
	}
	rOut.write("e", 1 );
}

void Gats::Dictionary::read( Bu::Stream &rIn, char cType )
{
	for(;;)
	{
		char cNext;
		rIn.read( &cNext, 1 );
		if( cNext == 'e' )
			break;
		if( cNext != 's' )
			throw Bu::ExceptionBase("You can only use strings as keys.");
		Gats::String sKey;
		sKey.read( rIn, cNext );

		((Bu::Hash<Gats::String, Gats::Object *> *)this)->insert(
			sKey, Gats::Object::read( rIn )
			);
	}
}

void Gats::Dictionary::insert( const Bu::FString &sKey, int32_t i )
{
	((Bu::Hash<Gats::String, Gats::Object *> *)this)->insert(
		sKey, new Gats::Integer( i )
		);
}

void Gats::Dictionary::insert( const Bu::FString &sKey, int64_t i )
{
	((Bu::Hash<Gats::String, Gats::Object *> *)this)->insert(
		sKey, new Gats::Integer( i )
		);
}

void Gats::Dictionary::insert( const Bu::FString &sKey, bool b )
{
	Bu::Hash<Gats::String, Gats::Object *>::insert(
		sKey, new Gats::Boolean( b )
		);
}

void Gats::Dictionary::insert( const Bu::FString &sKey, double d )
{
	Bu::Hash<Gats::String, Gats::Object *>::insert(
		sKey, new Gats::Float( d )
		);
}

void Gats::Dictionary::insert( const Bu::FString &sKey, const char *s )
{
	Bu::Hash<Gats::String, Gats::Object *>::insert(
		sKey, new Gats::String( s )
		);
}

void Gats::Dictionary::insert( const Bu::FString &sKey, const Bu::FString &s )
{
	Bu::Hash<Gats::String, Gats::Object *>::insert(
		sKey, new Gats::String( s )
		);
}

bool Gats::Dictionary::getBool( const Bu::FString &sKey )
{
	Gats::Boolean *pOb = dynamic_cast<Gats::Boolean *>( get( sKey ) );
	if( !pOb )
		throw Bu::ExceptionBase("Cannot cast item '%s' to bool.",
			sKey.getStr() );

	return pOb->getValue();
}

int64_t Gats::Dictionary::getInt( const Bu::FString &sKey )
{
	Gats::Integer *pOb = dynamic_cast<Gats::Integer *>( get( sKey ) );
	if( !pOb )
		throw Bu::ExceptionBase("Cannot cast item '%s' to int.",
			sKey.getStr() );

	return pOb->getValue();
}

double Gats::Dictionary::getFloat( const Bu::FString &sKey )
{
	Gats::Boolean *pOb = dynamic_cast<Gats::Boolean *>( get( sKey ) );
	if( pOb )
		throw Bu::ExceptionBase("Cannot cast item '%s' to bool.",
			sKey.getStr() );

	return pOb->getValue();
}

Bu::FString Gats::Dictionary::getStr( const Bu::FString &sKey )
{
	Gats::String *pOb = dynamic_cast<Gats::String *>( get( sKey ) );
	if( !pOb )
		throw Bu::ExceptionBase("Cannot cast item '%s' to string.",
			sKey.getStr() );

	return *pOb;
}

Gats::List *Gats::Dictionary::getList( const Bu::FString &sKey )
{
	Gats::List *pOb = dynamic_cast<Gats::List *>( get( sKey ) );
	if( !pOb )
		throw Bu::ExceptionBase("Cannot cast item '%s' to list.",
			sKey.getStr() );

	return pOb;
}

Gats::Dictionary *Gats::Dictionary::getDict( const Bu::FString &sKey )
{
	Gats::Dictionary *pOb = dynamic_cast<Gats::Dictionary *>( get( sKey ) );
	if( !pOb )
		throw Bu::ExceptionBase("Cannot cast item '%s' to dictionary.",
			sKey.getStr() );

	return pOb;
}