/** @file datatypes.cpp
* A set of typedefs and classes for generic, inspectable data
* @headerfile datatypes.h "EABaseTypes/datatypes.h"
* @author Nick Beatty (nbeatty@ea.com)
* (c) 2011 Electronic Arts Inc.
*/

#include "EABaseTypes/datatypes.h"

#include "EABase/eabase.h"
#include "EABaseTypes/factory.h"
#if !defined(EA_FINAL)
#include "EABaseTypes/typechecking.h"
#endif
#include "coreallocator/icoreallocatormacros.h"
#include "EAAssert/eaassert.h"

#include "EABaseTypes/iencoder.h"
#include "EABaseTypes/basetypeencoder.h"
#include "EABaseTypes/functioncallwrappers.h"

namespace EA
{
	namespace Types
	{
		BaseType::BaseType(Factory* factory, DataType eType)
			: mFactory(factory)
			, mType(eType)
			, mRefCount(1)
		{
		}

		BaseType::~BaseType()
		{
		}

		void BaseType::operator delete(void* p, EA::Types::Factory* factory)
		{
			factory->GetAllocator()->Free(p);
		}

		void BaseType::operator delete(void* p)
		{
			static_cast<BaseType*>(p)->GetFactory()->GetAllocator()->Free(p);
		}
		
		BooleanReturn BaseType::AsBoolean()
		{
			EA_ASSERT_MESSAGE(this == NULL || GetType() == BOOLEAN_TYPE, "BaseType must be a Boolean");
			if(this != NULL) AddRef();
			return static_cast<Boolean*>(this);
		}
		
		ConstBooleanReturn BaseType::AsBoolean() const
		{
			EA_ASSERT_MESSAGE(this == NULL || GetType() == BOOLEAN_TYPE, "BaseType must be a Boolean");
			if(this != NULL) AddRef();
			return static_cast<const Boolean*>(this);
		}
		
		bool BaseType::AsBool() const
		{
			EA_ASSERT_MESSAGE(GetType() == BOOLEAN_TYPE, "BaseType must be a Boolean");
			return bool(*static_cast<const Boolean*>(this));
		}
		
		NumberReturn BaseType::AsNumber()
		{
			EA_ASSERT_MESSAGE(this == NULL || GetType() == NUMBER_TYPE, "BaseType must be a Number");
			if(this != NULL) AddRef();
			return static_cast<Number*>(this);
		}
		
		ConstNumberReturn BaseType::AsNumber() const
		{
			EA_ASSERT_MESSAGE(this == NULL || GetType() == NUMBER_TYPE, "BaseType must be a Number");
			if(this != NULL) AddRef();
			return static_cast<const Number*>(this);
		}
		
		int BaseType::AsInt() const
		{
			EA_ASSERT_MESSAGE(this == NULL || GetType() == NUMBER_TYPE, "BaseType must be a Number");
			return int(*static_cast<const Number*>(this));
		}
		
		unsigned int BaseType::AsUnsignedInt() const
		{
			EA_ASSERT_MESSAGE(GetType() == NUMBER_TYPE, "BaseType must be a Number");
			return static_cast<unsigned int>((*static_cast<const Number*>(this)));
		}
		
		float BaseType::AsFloat() const
		{
			EA_ASSERT_MESSAGE(GetType() == NUMBER_TYPE, "BaseType must be a Number");
			return float(*static_cast<const Number*>(this));
		}

		BaseTypeFloat BaseType::AsBaseTypeFloat() const
		{
			EA_ASSERT_MESSAGE(GetType() == NUMBER_TYPE, "BaseType must be a Number");
			return BaseTypeFloat(*static_cast<const Number*>(this));
		}
		
		StringReturn BaseType::AsString()
		{
			EA_ASSERT_MESSAGE(this == NULL || GetType() == STRING_TYPE, "BaseType must be a String");
			if(this != NULL) AddRef();
			return static_cast<String*>(this);
		}
		
		ConstStringReturn BaseType::AsString() const
		{
			EA_ASSERT_MESSAGE(this == NULL || GetType() == STRING_TYPE, "BaseType must be a String");
			if(this != NULL) AddRef();
			return static_cast<const String*>(this);
		}
		
		const char* BaseType::AsCStr() const
		{
			EA_ASSERT_MESSAGE(GetType() == STRING_TYPE, "BaseType must be a String");
			return static_cast<const char*>(*static_cast<const String*>(this));
		}
	
		const EA::String& BaseType::AsEAString() const
		{
			EA_ASSERT_MESSAGE(GetType() == STRING_TYPE, "BaseType must be a String");
			return static_cast<const EA::String&>(*static_cast<const String*>(this));
		}
		
		FunctionReturn BaseType::AsFunction()
		{
			EA_ASSERT_MESSAGE(this == NULL || GetType() == FUNCTION_TYPE, "BaseType must be a Function");
			if(this != NULL) AddRef();
			return static_cast<Function*>(this);
		}
		
		ConstFunctionReturn BaseType::AsFunction() const
		{
			EA_ASSERT_MESSAGE(this == NULL || GetType() == FUNCTION_TYPE, "BaseType must be a Function");
			if(this != NULL) AddRef();
			return static_cast<const Function*>(this);
		}

		UserDataReturn BaseType::AsUserData()
		{
			EA_ASSERT_MESSAGE(this == NULL || GetType() == USERDATA_TYPE, "BaseType must be a UserData");
			if(this != NULL) AddRef();
			return static_cast<UserData*>(this);
		}
		
		ConstUserDataReturn BaseType::AsUserData() const
		{
			EA_ASSERT_MESSAGE(this == NULL || GetType() == FUNCTION_TYPE, "BaseType must be a UserData");
			if(this != NULL) AddRef();
			return static_cast<const UserData*>(this);
		}
		
		ArrayReturn BaseType::AsArray()
		{
			EA_ASSERT_MESSAGE(this == NULL || GetType() == ARRAY_TYPE, "BaseType must be an Array");
			if(this != NULL) AddRef();
			return static_cast<Array*>(this);
		}
		
		ConstArrayReturn BaseType::AsArray() const
		{
			EA_ASSERT_MESSAGE(this == NULL || GetType() == ARRAY_TYPE, "BaseType must be an Array");
			if(this != NULL) AddRef();
			return static_cast<const Array*>(this);
		}
		
		ObjectReturn BaseType::AsObject()
		{
			EA_ASSERT_MESSAGE(this == NULL || GetType() == OBJECT_TYPE, "BaseType must be an Object");
			if(this != NULL) AddRef();
			return static_cast<Object*>(this);
		}
		
		ConstObjectReturn BaseType::AsObject() const
		{
			EA_ASSERT_MESSAGE(this == NULL || GetType() == OBJECT_TYPE, "BaseType must be an Object");
			if(this != NULL) AddRef();
			return static_cast<const Object*>(this);
		}

		/* protected static */ void* BaseType::Alloc(size_t size, Factory* factory, const char* name, EA::Allocator::AllocFlags eFlags)
		{
			return CORE_ALLOC(factory->GetAllocator(), size, name, eFlags);
		}

		/* private */ void BaseType::DeleteThis() const
		{
			CORE_DELETE(mFactory->GetAllocator(), const_cast<BaseType*>(this));
		}

		/* explicit */ Number::Number(Factory* factory) 
			: BaseType(factory, NUMBER_TYPE)
			, mValue(0)
		{
		}

		Number::Number(Factory* factory, int val)	
			: BaseType(factory, NUMBER_TYPE)
			, mValue(val)
		{
		}

		Number::Number(Factory* factory, BaseTypeFloat val)
			: BaseType(factory, NUMBER_TYPE)
			, mValue(val)
		{
		}

		Number::Number(Factory* factory, unsigned int val)
			: BaseType(factory, NUMBER_TYPE)
			, mValue(val)
		{

		}

		/* virtual */ BaseTypeReturn Number::Clone()
		{
			return mFactory->Number(mValue);
		}

		Number& Number::operator=( int val )
		{
			mValue = val;
			return *this;
		}

		Number& Number::operator=( BaseTypeFloat val )
		{
			mValue = val;
			return *this;
		}

		Number::operator int() const
		{
			EA_ASSERT_MSG(IsInt() == true, ("Number BaseType is not an integer value\n"));
			return static_cast<int>(mValue);
		}

		Number::operator unsigned int() const
		{
			EA_ASSERT_MSG(IsUnsignedInt() == true, ("Number BaseType is not an unsigned integer value\n"));
			return static_cast<unsigned int>(mValue);
		}

		bool Number::IsInt() const
		{
			int val = static_cast<int>(mValue);
			return static_cast<BaseTypeFloat>(val) == mValue;
		}

		bool Number::IsUnsignedInt() const
		{
			unsigned int val = static_cast<unsigned int>(mValue);
			return static_cast<BaseTypeFloat>(val) == mValue;
		}

		/* explicit */ String::String(Factory* factory) 
			: BaseType(factory, STRING_TYPE)
			, mValue(factory)
		{
		}

		String::String(Factory* factory, const char* val)
			: BaseType(factory, STRING_TYPE)
			, mValue(factory, val)
		{
		}
		
		String::String(Factory* factory, const EA::String& val)
			: BaseType(factory, STRING_TYPE)
			, mValue(factory, val.c_str()) // whu?
		{
		}
		
		String::String(Factory* factory, const EA::RawString& val)
			: BaseType(factory, STRING_TYPE)
			, mValue(factory, val.c_str())
		{
		}
		
		String::String(Factory* factory, const char* val, size_t length)
			: BaseType(factory, STRING_TYPE)
			, mValue(factory)
		{
			mValue.assign(val, static_cast<eastl_size_t>(length));
		}

		/* virtual */ BaseTypeReturn String::Clone()
		{
			return mFactory->String(mValue.c_str());
		}

		bool String::operator==(const char* val)
		{
			return mValue == val;
		}

		bool String::operator==(const EA::String& val)
		{
			return mValue == val;
		}

		String& String::operator=( const char* val )
		{
			mValue = val;
			return *this;
		}

		String& String::operator=( const EA::String &val )
		{
			mValue = val;
			return *this;
		}
		
		void String::assign(const char* val, size_t length)
		{
			mValue.assign(val, static_cast<EA::String::size_type>(length));
		}

		/* explicit */ Boolean::Boolean(Factory* factory)
			: BaseType(factory, BOOLEAN_TYPE)
			, mValue(false)
		{

		}

		Boolean::Boolean(Factory* factory, bool val) 
			: BaseType(factory, BOOLEAN_TYPE)
			, mValue(val)
		{

		}

		/* virtual */ BaseTypeReturn Boolean::Clone()
		{
			return mFactory->Boolean(mValue);
		}

		Boolean& Boolean::operator=( bool val )
		{
			mValue = val;
			return *this;
		}

		/* explicit */ Array::Array(Factory* factory) 
			: BaseType(factory, ARRAY_TYPE)
			, mValue(factory->GetAllocator())
		{
		}

		Array::Array(Factory* factory, size_t reserveSize)
			: BaseType(factory, ARRAY_TYPE)
			, mValue(factory->GetAllocator())
		{
			if(reserveSize > 0) mValue.reserve(static_cast<EASTLICA::Vector<BaseTypeRef>::size_type>(reserveSize));
		}

		/* virtual */ Array::~Array()
		{
		}

		/* virtual */ BaseTypeReturn Array::Clone()
		{
			ArrayRef clone = mFactory->Array(static_cast<size_t>(size()));

			BaseTypeVector::const_iterator it = mValue.begin();
			BaseTypeVector::const_iterator end = mValue.end();

			for(; it != end; ++it)
			{
				clone->push_back((*it) != NULL ? (*it)->Clone() : BaseTypeRef());
			}

			return clone;
		}
		
		Array::iterator Array::begin()
		{
			return mValue.begin();
		}
		
		Array::const_iterator Array::begin() const
		{
			return mValue.begin();
		}
		
		Array::iterator Array::end()
		{
			return mValue.end();
		}
		
		Array::const_iterator Array::end() const
		{
			return mValue.end();
		}

		bool Array::empty() const
		{
			return mValue.empty();
		}
		
		size_t Array::size() const
		{
			return mValue.size();
		}
		
		BaseTypeRef& Array::push_back()
		{
			return mValue.push_back();
		}
		
		ArrayReturn Array::push_backArray()
		{
			ArrayRef result = mFactory->Array();
			push_back() = result;
			return result;
		}

		ArrayReturn Array::push_backArray(size_t reserveSize)
		{
			ArrayRef result = mFactory->Array(reserveSize);
			push_back() = result;
			return result;
		}
		
		ObjectReturn Array::push_backObject()
		{
			ObjectRef result = mFactory->Object();
			push_back() = result;
			return result;
		}

		BaseTypeRef& Array::at(size_t index)
		{
			return mValue[static_cast<eastl_size_t>(index)];
		}

		const BaseTypeRef& Array::at(size_t index) const
		{
			return mValue[static_cast<eastl_size_t>(index)];
		}

		Array::iterator Array::erase(iterator it)
		{
			return mValue.erase(it);
		}
		
		void Array::clear()
		{
			mValue.clear();
		}

		void Array::reserve(size_t reserveSize)
		{
			mValue.reserve(static_cast<EASTLICA::Vector<BaseTypeRef>::size_type>(reserveSize));
		}
		
		/* explicit */ Object::Object(Factory* factory) 
			: BaseType(factory, OBJECT_TYPE)
			, mValue(factory->GetAllocator())
		{
		}

		/* virtual */ Object::~Object()
		{
		}

		/* virtual */ BaseTypeReturn Object::Clone()
		{
			ObjectRef clone = mFactory->Object();

			BaseTypeMap::const_iterator it = mValue.begin();
			BaseTypeMap::const_iterator itEnd = mValue.end();

			for(; it != itEnd; ++it)
			{
				clone->insert((*it).first).first->second = (*it).second != NULL ? (*it).second->Clone() : BaseTypeRef();
			}

			return clone;
		}
		
		Object::iterator Object::begin()
		{
			return mValue.begin();
		}
		
		Object::const_iterator Object::begin() const
		{
			return mValue.begin();
		}
		
		Object::iterator Object::end()
		{
			return mValue.end();
		}
		
		Object::const_iterator Object::end() const
		{
			return mValue.end();
		}
		
		Object::iterator Object::find(const EA::String& key)
		{
			return mValue.find(key);
		}
		
		Object::iterator Object::find(const char* key)
		{
			return mValue.find(EA::String(mFactory, key));
		}
		
		Object::const_iterator Object::find(const EA::String& key) const
		{
			return mValue.find(key);
		}
		
		Object::const_iterator Object::find(const char* key) const
		{
			return mValue.find(EA::String(mFactory, key));
		}

		bool Object::empty() const
		{
			return mValue.empty();
		}
		
		size_t Object::size() const
		{
			return mValue.size();
		}

		BaseTypeRef& Object::get(const EA::String& key)
		{
			return mValue[key];
		}

		BaseTypeRef& Object::get(const char* key)
		{
			return mValue[EA::String(mFactory, key)];
		}

		const BaseTypeRef& Object::get(const EA::String& key) const
		{
			Object::const_iterator it = mValue.find(key);
			EA_ASSERT_FORMATTED(it != mValue.end(), ("key %s not found!", key.c_str()));
			return (*it).second;
		}

		const BaseTypeRef& Object::get(const char* key) const
		{
			Object::const_iterator it = mValue.find(EA::String(mFactory, key));
			EA_ASSERT_FORMATTED(it != mValue.end(), ("key %s not found!", key));
			return (*it).second;
		}
		
		Object::insert_return_type Object::insert(const EA::String& key)
		{
			return mValue.insert(key);
		}
		
		Object::insert_return_type Object::insert(const char* key)
		{
			return mValue.insert(EA::String(mFactory, key));
		}
		
		ArrayReturn Object::insertArray(const EA::String& key)
		{
			ArrayRef result = mFactory->Array();
			mValue.insert(key).first->second = result;
			return result;
		}
		
		ArrayReturn Object::insertArray(const char* key)
		{
			ArrayRef result = mFactory->Array();
			mValue.insert(EA::String(mFactory, key)).first->second = result;
			return result;
		}

		ArrayReturn Object::insertArray(const EA::String& key, size_t reserveSize)
		{
			ArrayRef result = mFactory->Array(reserveSize);
			mValue.insert(key).first->second = result;
			return result;
		}

		ArrayReturn Object::insertArray(const char* key, size_t reserveSize)
		{
			ArrayRef result = mFactory->Array(reserveSize);
			mValue.insert(EA::String(mFactory, key)).first->second = result;
			return result;
		}
			
		ObjectReturn Object::insertObject(const EA::String& key)
		{
			ObjectRef result = mFactory->Object();
			mValue.insert(key).first->second = result;
			return result;
		}
		
		ObjectReturn Object::insertObject(const char* key)
		{
			ObjectRef result = mFactory->Object();
			mValue.insert(EA::String(mFactory, key)).first->second = result;
			return result;
		}
		
		bool Object::contains(const EA::String& key) const
		{
			return find(key) != end();
		}
		
		bool Object::contains(const char* key) const
		{
			return find(key) != end();
		}
		
		void Object::erase(const EA::String& key)
		{
			mValue.erase(key);
		}
		
		void Object::erase(const char* key)
		{
			mValue.erase(EA::String(mFactory, key));
		}

		/* explicit */ Function::Function(Factory* factory)
			: BaseType(factory, FUNCTION_TYPE)
#if !defined(EA_FINAL)
			, mDataDef()
			, mDebugInfo()
#endif
		{
		}

		Function::~Function()
		{
		}

		/* virtual */ BaseTypeReturn Function::Call(ArrayIn pParams)
		{
			BaseTypeEncoder encoder(mFactory);
			IEncoderImpl<BaseTypeEncoder> defaultEncoder(&encoder);

			Call(CALLER_TYPE,
				 pParams.GetUnsafePointer(),
				 &encoder,
				 BaseTypeArrayDecoder<IEncoder>::Decode, 
				 &defaultEncoder);

			return encoder.AcquireRoot();
		}

		/* virtual */ void Function::Call(unsigned int id, 
										  void* decoderParams,
										  void* encoder,
										  DecodeFunction defaultDecode,
										  IEncoder* defaultEncoder)
		{
			ArrayRef arguments = GetFactory()->Array();
			BaseTypeArrayEncoder argumentEncoder(arguments.GetUnsafePointer());
			IEncoderImpl<BaseTypeArrayEncoder> defaultArgumentEncoder(&argumentEncoder);
			defaultDecode(&defaultArgumentEncoder, decoderParams);

			BaseTypeRef result = Call(arguments);

			BaseTypeDecoder<IEncoder>::Decode(defaultEncoder, result.GetUnsafePointer());
		}
        
        BaseTypeReturn Function::operator[](size_t index) { return Call<BaseTypeReturn>(static_cast<unsigned int>(index)); }
        
        BaseTypeReturn Function::operator[](const EA::String& key) { return Call<BaseTypeReturn>(key); }
        
        BaseTypeReturn Function::operator[](const char* key) { return Call<BaseTypeReturn>(key); }

		void Function::SetDataDef(ArrayIn pDataDef)
		{
#if !defined(EA_FINAL)
			mDataDef = pDataDef;
#endif
		}
		
		/* explicit */ UserData::UserData(Factory* factory)
			: BaseType(factory, USERDATA_TYPE)
		{

		}

		UserData::~UserData()
		{
		}


#if !defined(EA_FINAL)
		bool Function::CheckData(ArrayIn pParams) const
		{
			bool result = true;
			if(mDataDef != NULL)
			{
				if(pParams == NULL)
				{
					EA_FAIL_MESSAGE(("No paramaters passed in"));
					result = false;
				}
				else
				{
					size_t dataSize =  pParams->size();
					size_t defSize = mDataDef->size();
					if(dataSize != defSize)
					{
						EA_FAIL_FORMATTED(("Expected %u paramters received %u", defSize, dataSize));
						result = false;
					}
					else
					{
						Array::iterator dataIt = pParams->begin();
						Array::iterator defIt = mDataDef->begin();
						for(; dataIt != pParams->end(); ++dataIt, ++defIt)
						{
							EA::RawString message(mFactory->GetAllocator());

							if(!CheckType(mFactory->GetMetaTypes(), *dataIt, *defIt, message))
							{
								EA::RawString expected(mFactory->GetAllocator());
								DumpBaseType(expected, *defIt);

								EA::RawString actual(mFactory->GetAllocator());
								DumpBaseType(actual, *dataIt);

								EA_FAIL_FORMATTED(("Typechecking failure:%s\nUnexpected Data Passed to EA::Function\nExpected data: %s\nActualData: %s", message.c_str(), expected.c_str(), actual.c_str()));
								result = false;
								break;
							}
						}
					}
				}
			}

			return result;
		}

		bool Function::CheckData(void *decoderParams, DecodeFunction defaultDecode)
		{
			bool result = true;
			if(mDataDef != NULL)
			{
				ArrayRef data = GetFactory()->Array();
				
				BaseTypeArrayEncoder argumentEncoder(data.GetUnsafePointer());
				IEncoderImpl<BaseTypeArrayEncoder> defaultArgumentEncoder(&argumentEncoder);
				defaultDecode(&defaultArgumentEncoder, decoderParams);

				result = CheckData(data);
			}
			
			return result;
		}

		void DumpBaseType(EA::RawString& dst, ConstBaseTypeIn pVal )
		{
			dst.append("--------------BEGIN BASE TYPE DUMP---------------\n");

			if(pVal != NULL)
			{
				switch(pVal->GetType())
				{
				case(NUMBER_TYPE):
					{
						dst.append_sprintf("Number value %f\n", pVal->AsFloat());
					}
					break;
				case(BOOLEAN_TYPE):
					{
						dst.append_sprintf("Boolean value %s\n", pVal->AsBool() ? "TRUE" : "FALSE");
					}
					break;
				case(STRING_TYPE):
					{
						dst.append_sprintf("String value %s\n", pVal->AsCStr());
					}
					break;
				case(FUNCTION_TYPE):
					{						
						dst.append_sprintf("Function value %p", pVal.GetUnsafePointer());
					}
					break;
				case(USERDATA_TYPE):
					{						
						dst.append_sprintf("UserData value %p", pVal.GetUnsafePointer());
					}
					break;
				case(OBJECT_TYPE):
					{
						dst.append("Object value=\n");
						DumpObject(dst, pVal->AsObject(), "\t");	
					}
					break;
				case(ARRAY_TYPE):
					{
						dst.append("Array value=\n");
						DumpArray(dst, pVal->AsArray(), "\t");
					}
					break;
				default:
					break;
				}
			}
			dst.append("--------------END BASE TYPE DUMP---------------\n");
		}

		void DumpObject(EA::RawString& dst, ConstObjectIn pObj, const char* pTabs )
		{
			if(pObj != NULL)
			{
				Object::const_iterator it = pObj->begin();
				Object::const_iterator end = pObj->end();
				for(; it != end; ++it)
				{
					EA::String key = (*it).first;
					ConstBaseTypeRef pVal = (*it).second;
					
					switch(pVal->GetType())
					{
					case(NUMBER_TYPE):
						{
							dst.append_sprintf("%sNumber key = %s, value=%f\n", pTabs, key.c_str(), pVal->AsFloat());
						}
						break;
					case(BOOLEAN_TYPE):
						{
							dst.append_sprintf("%sBoolean key = %s, value=%s\n", pTabs, key.c_str(), pVal->AsBool() ? "TRUE" : "FALSE");
						}
						break;
					case(STRING_TYPE):
						{
							dst.append_sprintf("%sString key = %s, value=%s\n", pTabs, key.c_str(), pVal->AsCStr());
						}
						break;
					case(FUNCTION_TYPE):
						{						
							dst.append_sprintf("%sFunction key = %s, value=%p", pTabs, key.c_str(), pVal.GetUnsafePointer());
						}
						break;
					case(USERDATA_TYPE):
						{						
							dst.append_sprintf("%UserData key = %s, value=%p", pTabs, key.c_str(), pVal.GetUnsafePointer());
						}
						break;
					case(OBJECT_TYPE):
						{
							dst.append_sprintf("%sNested Object key = %s, value=\n", pTabs, key.c_str());
							EA::RawString tabs(dst.get_allocator().get_allocator());
							tabs.sprintf("%s\t", pTabs);
							DumpObject(dst, pVal->AsObject(), tabs.c_str());
						}
						break;
					case(ARRAY_TYPE):
						{
							dst.append_sprintf("%sNested Array key = %s, value=\n", pTabs, key.c_str());
							EA::RawString tabs(dst.get_allocator().get_allocator());
							tabs.sprintf("%s\t", pTabs);
							DumpArray(dst, pVal->AsArray(), tabs.c_str());
						}
						break;
					default:
						break;
					}
				}
			}
		}

		void DumpArray(EA::RawString& dst, ConstArrayIn pArray, const char* pTabs )
		{
			if(pArray != NULL)
			{
				Array::const_iterator it = pArray->begin();
				Array::const_iterator end = pArray->end();
				int i = 0;
				for(; it != end; ++it, ++i)
				{
					ConstBaseTypeRef pVal = (*it);
					switch(pVal->GetType())
					{
					case(NUMBER_TYPE):
						{
							dst.append_sprintf("%sNumber index = %d, value=%f\n", pTabs, i, pVal->AsFloat());
						}
						break;
					case(BOOLEAN_TYPE):
						{
							dst.append_sprintf("%sBoolean index = %d, value=%s\n", pTabs, i, pVal->AsBool() ? "TRUE" : "FALSE");
						}
						break;
					case(STRING_TYPE):
						{
							dst.append_sprintf("%sString index = %d, value=%s\n", pTabs, i, pVal->AsCStr());
						}
						break;
					case(FUNCTION_TYPE):
						{						
							dst.append_sprintf("%sFunction index = %d, value=%p", pTabs, i, pVal.GetUnsafePointer());
						}
						break;
					case(USERDATA_TYPE):
						{						
							dst.append_sprintf("%sUserData index = %d, value=%p", pTabs, i, pVal.GetUnsafePointer());
						}
						break;
					case(OBJECT_TYPE):
						{
							dst.append_sprintf("%sNested Object index = %d, value=\n", pTabs, i);
							EA::RawString tabs(dst.get_allocator().get_allocator());
							tabs.sprintf("%s\t", pTabs);
							DumpObject(dst, pVal->AsObject(), tabs.c_str());
						}
						break;
					case(ARRAY_TYPE):
						{
							dst.append_sprintf("%sNested Array index = %d, value=\n", pTabs, i);
							EA::RawString tabs(dst.get_allocator().get_allocator());
							tabs.sprintf("%s\t", pTabs);
							DumpArray(dst, pVal->AsArray(), tabs.c_str());
						}
						break;
					
					default:
						break;
					}
				}
			}
		}
#endif // #if !defined(EA_FINAL)
	} //namespace Types
} //namespace EA
