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

#ifndef EABASETYPES_DATATYPES_H_
#define EABASETYPES_DATATYPES_H_

#include "EABaseTypes/basetypefloat.h"
#include "EABaseTypes/autoref.h"
#include "EABaseTypes/string.h"
#include "EABaseTypes/factory.h"
#include "EABaseTypes/callermap.h"

#include "EASTLICA/vector.h"
#include "EASTLICA/hash_map.h"

#include "eatypeof/typeof.h"

namespace EA
{
	namespace Types
	{
		static const unsigned int CALLER_TYPE = 0x97475835;

		//! Supported data types
		enum DataType
		{
			UNKNOWN_TYPE, //!< initialization only
			BOOLEAN_TYPE,
			NUMBER_TYPE,
			STRING_TYPE,
			ARRAY_TYPE,
			OBJECT_TYPE,
			FUNCTION_TYPE,
			USERDATA_TYPE
		};

		/*! @class BaseType datatypes.h	"EABaseTypes/datatypes.h"
		*	@brief Base class definition for EABaseTypes data types.
		*	All instances are ref-counted, current ref count implementation is not thread safe.
		*	A BaseType should never be explicitly created, data providers should create the types defined below that extend BaseType 
		*/
		class BaseType
		{
		public:
			
			BaseType(Factory* factory, DataType eType);
			virtual ~BaseType();
			
			inline int AddRef() const { return ++mRefCount; }
			inline int Release() const
			{
				if(--mRefCount <= 0)
				{ this->DeleteThis(); return 0; }
				else
				{ return mRefCount; }
			}
			
			inline int GetRefCount() const { return mRefCount; }

			inline void* operator new(size_t size, EA::Types::Factory* factory) { return Alloc(size, factory, "EA::Types::BaseType", EA::Allocator::MEM_TEMP); }

			inline void* operator new(size_t size, EA::Types::Factory* factory, const char* name, EA::Allocator::AllocFlags eFlags) { return Alloc(size, factory, name, eFlags); }

			// this exists only for the case where exceptions are enabled and the constructor of the BaseType throws an exception
			// you should never call this under any circumstances
			void operator delete(void* p, EA::Types::Factory* factory);
			void operator delete(void *p);

			Factory* GetFactory() const { return mFactory; }

			/*!
			*	Gets the DataType of this BaseType instance 
			*	@return	DataType	The type of this BaseType instance
			*	@sa	Types::DataType
			*/
			DataType GetType() const { return mType; }

			/*!
			*	Create a deep copy of this object
			*	@return	BaseTypeReturn	A deep copy of this object
			*/
			virtual BaseTypeReturn Clone() = 0;
			
			BooleanReturn AsBoolean();
			ConstBooleanReturn AsBoolean() const;
			
			bool AsBool() const;
			
			NumberReturn AsNumber();
			ConstNumberReturn AsNumber() const;
			
			int AsInt() const;
			unsigned int AsUnsignedInt() const;
			float AsFloat() const;
			BaseTypeFloat AsBaseTypeFloat() const;
			
			StringReturn AsString();
			ConstStringReturn AsString() const;
			
			const char* AsCStr() const;
			const EA::String& AsEAString() const;
			
			FunctionReturn AsFunction();
			ConstFunctionReturn AsFunction() const;

			UserDataReturn AsUserData();
			ConstUserDataReturn AsUserData() const;
			
			ArrayReturn AsArray();
			ConstArrayReturn AsArray() const;
			
			ObjectReturn AsObject();
			ConstObjectReturn AsObject() const;

			template<typename T>
			T As() { return BaseTypeTraits1<T>::As(BaseTypeIn(this)); }

		protected:

			static void* Alloc(size_t size, Factory* factory, const char* name, EA::Allocator::AllocFlags eFlags);

			Factory*	mFactory;
			DataType	mType;

		private:
		
			void DeleteThis() const;

			BaseType();
			
			mutable int	mRefCount;
		};
		
		/*! @class Boolean datatypes.h	"EABaseTypes/datatypes.h"
		*	Provides a BaseType implementation for primitive type bool.
		*	@sa Types::BaseType
		*/
		class Boolean : public BaseType
		{
		public:
			Boolean(Factory* factory);
			Boolean(Factory* factory, bool val);

			/*!
			*	Create a deep copy of this object
			*	@return	BaseTypeReturn	A deep copy of this object
			*/
			virtual BaseTypeReturn Clone();

			Boolean& operator=(bool val);
			operator bool() const { return mValue; }
			
		private:
		
			bool mValue;
		};

		/*! @class Number datatypes.h	"EABaseTypes/datatypes.h"
		*	Provides a BaseType implementation for a Number
		*	@sa Types::BaseType
		*/
		class Number : public BaseType
		{
		public:
			explicit Number(Factory* factory);
			Number(Factory* factory, int val);
			Number(Factory* factory, unsigned int val);
			Number(Factory* factory, BaseTypeFloat val);

			/*!
			*	Create a deep copy of this object
			*	@return	BaseTypeReturn	A deep copy of this object
			*/
			virtual BaseTypeReturn Clone();
			
			bool IsInt() const;
			bool IsUnsignedInt() const;
			
			Number& operator=(int val);
			Number& operator=(BaseTypeFloat val);
			
			operator int() const;
			operator unsigned int() const;
			operator float() const { return static_cast<float>(mValue); }
			operator BaseTypeFloat() const { return mValue; }
			operator BaseTypeFloat&() { return mValue; }
			
		private:
		
			BaseTypeFloat mValue;
		};

		/*! @class String datatypes.h	"EABaseTypes/datatypes.h"
		*	Provides a BaseType implementation for a EA::String.
		*	@sa Types::BaseType	EA::String
		*/
		class String : public BaseType
		{
		public:
			explicit String(Factory* factory);
			String(Factory* factory, const char* val);
			String(Factory* factory, const EA::String& val);
			String(Factory* factory, const EA::RawString& val);
			String(Factory* factory, const char* val, size_t length);

			/*!
			*	Create a deep copy of this object
			*	@return	BaseTypeReturn	A deep copy of this object
			*/
			virtual BaseTypeReturn Clone();

			bool operator==(const char* val);
			bool operator==(const EA::String& val);
			
			String& operator=(const char* val);
			String& operator=(const EA::String &val);
			void assign(const char* val, size_t length);
			
			operator const char*() const { return mValue.c_str(); }
			operator EA::String&() { return mValue; }
			operator const EA::String&() const { return mValue; }
			
		private:
		
			EA::String mValue;
		};
		
		class IEncoder;

		struct NativeDecoderParams;
		class NativeEncoder;

		/*! @class Function datatypes.h	"EABaseTypes/datatypes.h"
		*	The Function class can be extended to essentially wrap some Function call in an arbitrary language.
		*	Doing this allows these functions to be passed around as BaseType values
		*	@sa	Types::BaseType
		*/
		class Function : public BaseType
		{
		public:

			explicit Function(Factory* factory);
			virtual ~Function();

			/*!
			*	Create a deep copy of this Function
			*	@return	BaseTypeReturn	A deep copy of this Function
			*/
			virtual BaseTypeReturn Clone() = 0;

			/*!
			*	Call the function dynamically
			*	@param[in] ArrayIn	Array of BaseTypes containing the paramters to be passed to the function
			*	@return BaseTypeReturn	A BaseType, or NULL
			*/
			virtual BaseTypeReturn Call(ArrayIn pParams);

			/*!
			*	Call the function
			*	@param	id				The id for the caller
			*	@param	decoderParams	The argument decoder params for this caller
			*	@param	encoder			The result encoder for this caller
			*	@param	defaultDecode	The default argument decode function to use if none is available (expects an IEncoder as the first parameter)
			*	@param	defaultEncoder	The default result encoder to use if not result decode function is available
			*/
			virtual void Call(unsigned int id, 
							  void* decoderParams,
							  void* encoder,
							  DecodeFunction defaultDecode,
							  IEncoder* defaultEncoder);

			/*!
			*	Template for a zero-parameter call
			*	@tparam	R	return type
			*/
			template<typename R>
			inline R Call();

			/*!
			*	Template for a 1-parameter call
			*	@tparam	R	return type
			*	@tparam P1  parameter 1 type
			*	@param	p1	parameter 1
			*/
			template<typename R, typename P1>
			inline R Call(P1 p1);

			/*!
			*	Template for a 2-parameter call
			*	@tparam	R	return type
			*	@tparam P1  parameter 1 type
			*	@param	p1	parameter 1
			*	@tparam P2  parameter 2 type
			*	@param	p2	parameter 2
			*/
			template<typename R, typename P1, typename P2>
			inline R Call(P1 p1, P2 p2);

			/*!
			*	Template for a 3-parameter call
			*	@tparam	R	return type
			*	@tparam P1  parameter 1 type
			*	@param	p1	parameter 1
			*	@tparam P2  parameter 2 type
			*	@param	p2	parameter 2
			*	@tparam P3  parameter 3 type
			*	@param	p3	parameter 3
			*/
			template<typename R, typename P1, typename P2, typename P3>
			inline R Call(P1 p1, P2 p2, P3 p3);

			/*!
			*	Template for a 4-parameter call
			*	@tparam	R	return type
			*	@tparam P1  parameter 1 type
			*	@param	p1	parameter 1
			*	@tparam P2  parameter 2 type
			*	@param	p2	parameter 2
			*	@tparam P3  parameter 3 type
			*	@param	p3	parameter 3
			*	@tparam P4  parameter 4 type
			*	@param	p4	parameter 4
			*/
			template<typename R, typename P1, typename P2, typename P3, typename P4>
			inline R Call(P1 p1, P2 p2, P3 p3, P4 p4);

			/*!
			*	Template for a 5-parameter call
			*	@tparam	R	return type
			*	@tparam P1  parameter 1 type
			*	@param	p1	parameter 1
			*	@tparam P2  parameter 2 type
			*	@param	p2	parameter 2
			*	@tparam P3  parameter 3 type
			*	@param	p3	parameter 3
			*	@tparam P4  parameter 4 type
			*	@param	p4	parameter 4
			*	@tparam P5  parameter 5 type
			*	@param	p5	parameter 5
			*/
			template<typename R, typename P1, typename P2, typename P3, typename P4, typename P5>
			inline R Call(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5);

			/*!
			*	Template for a 6-parameter call
			*	@tparam	R	return type
			*	@tparam P1  parameter 1 type
			*	@param	p1	parameter 1
			*	@tparam P2  parameter 2 type
			*	@param	p2	parameter 2
			*	@tparam P3  parameter 3 type
			*	@param	p3	parameter 3
			*	@tparam P4  parameter 4 type
			*	@param	p4	parameter 4
			*	@tparam P6  parameter 6 type
			*	@param	p6	parameter 6
			*/
			template<typename R, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6>
			inline R Call(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6);
            
            BaseTypeReturn operator[](size_t index);
            BaseTypeReturn operator[](const EA::String& key);
            BaseTypeReturn operator[](const char* key);
            
			/*!
			*	Compare two functions
			*	@param[in] FunctionIn	Function to compare to
			*	@return bool true if the functions are equal, false otherwise
			*/
			virtual bool Equals(FunctionIn pCompare) = 0;

			/*!
			*	Get the type of the function
			*	@return EA::Type::TypeID The id for this type of Function class
			*/
			virtual EA::Type::TypeID GetFunctionType() = 0;

			/*!
			*	Set the paramater definition for this function 
			*	@param[in] ArrayIn	containing the defintion for each paramter
			*/
			virtual void SetDataDef(ArrayIn pDataDef);

			/*!
			*	Check that the paramters match the parameter definition.
			*	@param[in] ArrayIn	containing the paramters to check
			*	@return bool True if the paramters match the registered definition or a definition is not registered.
			*/
#if !defined(EA_FINAL)
			virtual bool CheckData(ArrayIn pParams) const;
#else
			inline bool CheckData(ArrayIn pParams) { return true; }
#endif

			/*!
			*	Check that the paramters match the parameter definition.
			*	@param	decoderParams	The decoder params
			*	@param	defaultCaller	The default caller function
			*	@return bool True if the paramters match the registered definition or a definition is not registered.
			*/
#if !defined(EA_FINAL)
			virtual bool CheckData(void *decoderParams, DecodeFunction defaultDecode);
#else
			inline bool CheckData(void *decoderParams, DecodeFunction defaultDecode) { return true; }
#endif

			inline BaseTypeReturn GetDebugInfo()
			{
#if !defined(EA_FINAL)
				return mDebugInfo;
#else
				return NULL;
#endif
			}

        protected:

#if !defined(EA_FINAL)
			inline void SetDebugInfo(BaseTypeIn debugInfo) { mDebugInfo = debugInfo; }
#endif

			inline void Call(NativeDecoderParams* decoderParams, NativeEncoder* encoder);
		
#if !defined(EA_FINAL)
			ArrayRef	mDataDef;
			BaseTypeRef	mDebugInfo;
#endif
		};

		class IEncoder;

		/*! @class UserData datatypes.h	"EABaseTypes/datatypes.h"
		*	UserData is designed to be subclassed by user code so that arbitrary data can be passed as a BaseType
		*	@sa Types::BaseType
		*/
		class UserData : public BaseType
		{
		public:

			explicit UserData(Factory* factory);
			virtual ~UserData();

			/*!
			*	Create a deep copy of this Function
			*	@return	BaseTypeReturn	A deep copy of this Function
			*/
			virtual BaseTypeReturn Clone() = 0;

			/*!
			*	Compare two userdatas
			*	@param[in] UserDataIn	UserData to compare to
			*	@return bool true if the functions are equal, false otherwise
			*/
			virtual bool Equals(UserDataIn pCompare) = 0;

			/*!
			*	Get the type of the userdata
			*	@return EA::Type::TypeID The id for this type of UserData class
			*/
			virtual EA::Type::TypeID GetUserDataType() = 0;
		};
		
		typedef EASTLICA::Vector<BaseTypeRef>				BaseTypeVector;
		
		/*! @class Array datatypes.h	"EABaseTypes/datatypes.h"
		*	Data providers can use the Array type to publish a game defined Array of script objects.
		*	Although it is legal in Actionscript to create arrays that contain different types, it is not recommended.
		*	@sa Types::BaseType
		*/
		class Array : public BaseType
		{
		public:

			/*!
			*	Default C'tor
			*/
			explicit Array(Factory* factory);


			/*!
			*	Creates an array and reserves the passed in number of entries, does not actually allocate any entries 
			*	just the space required in in the internal container
			*	@param[in] reserveSize	Number of entries to reserve
			*/
			Array(Factory* factory, size_t reserveSize);

			virtual ~Array();

			/*!
			*	Create a deep copy of this object
			*	@return	BaseTypeReturn	A deep copy of this object
			*/
			virtual BaseTypeReturn Clone();
			
			typedef BaseTypeVector::iterator		iterator;
			typedef BaseTypeVector::const_iterator	const_iterator;
			
			iterator begin();
			const_iterator begin() const;
			
			iterator end();
			const_iterator end() const;
			
			bool empty() const;
			size_t size() const;
			
			BaseTypeRef& operator[](size_t index) { return at(index); }
			const BaseTypeRef& operator[](size_t index) const { return at(index); }
			
			BaseTypeRef& at(size_t index);
			const BaseTypeRef& at(size_t index) const;
			
			BaseTypeRef& push_back();
			
			template<typename T>
			void push_back(T value) { push_back() = BaseTypeTraits1<T>::BaseType(mFactory, value); }

			template<typename T1, typename T2>
			void push_back(T1 value1, T2 value2) { push_back() = BaseTypeTraits2<T1, T2>::BaseType(mFactory, value1, value2); }
			
			ArrayReturn push_backArray();
			ArrayReturn push_backArray(size_t reserveSize);
			ObjectReturn push_backObject();

			iterator erase(iterator it);
			
			void clear();

			void reserve(size_t reserveSize);

		private:
		
			BaseTypeVector mValue;
		};
		
		typedef EASTLICA::HashMap<EA::String, BaseTypeRef>	BaseTypeMap;

		/*! @class Object datatypes.h	"EABaseTypes/datatypes.h"
		*	Data providers can use the Object Type to publish a game defined set of key, value pairs. 
		*	Where value can be any type the extends BaseType
		*	@sa	Types::BaseType
		*/
		class Object : public BaseType
		{
		public:
			explicit Object(Factory* factory);
			
			virtual ~Object();

			/*!
			*	Create a deep copy of this object
			*	@return	BaseTypeReturn	A deep copy of this object
			*/
			virtual BaseTypeReturn Clone();
			
			typedef BaseTypeMap::iterator			iterator;
			typedef BaseTypeMap::const_iterator		const_iterator;
			typedef BaseTypeMap::insert_return_type	insert_return_type;
			
			iterator begin();
			const_iterator begin() const;
			
			iterator end();
			const_iterator end() const;
			
			iterator find(const EA::String& key);
			iterator find(const char* key);
			
			const_iterator find(const EA::String& key) const;
			const_iterator find(const char* key) const;
			
			bool empty() const;
			size_t size() const;
			
			BaseTypeRef& operator[](const EA::String& key) { return get(key); }
			BaseTypeRef& operator[](const char* key) { return get(key); }
			
			const BaseTypeRef& operator[](const EA::String& key) const { return get(key); }
			const BaseTypeRef& operator[](const char* key) const { return get(key); }

			BaseTypeRef& get(const EA::String& key);
			BaseTypeRef& get(const char* key);

			const BaseTypeRef& get(const EA::String& key) const;
			const BaseTypeRef& get(const char* key) const;
			
			insert_return_type insert(const EA::String& key);
			insert_return_type insert(const char* key);
			
			template<typename T>
			void insert(const EA::String& key, T value) { insert(key).first->second = BaseTypeTraits1<T>::BaseType(mFactory, value); }

			template<typename T>
			void insert(const char* key, T value) { insert(key).first->second = BaseTypeTraits1<T>::BaseType(mFactory, value); }
			
			template<typename T1, typename T2>
			void insert(const EA::String& key, T1 value1, T2 value2) { insert(key).first->second = BaseTypeTraits2<T1, T2>::BaseType(mFactory, value1, value2); }

			template<typename T1, typename T2>
			void insert(const char* key, T1 value1, T2 value2) { insert(key).first->second = BaseTypeTraits2<T1, T2>::BaseType(mFactory, value1, value2); }
			
			ArrayReturn insertArray(const EA::String& key);
			ArrayReturn insertArray(const char* key);

			ArrayReturn insertArray(const EA::String& key, size_t reserveSize);
			ArrayReturn insertArray(const char* key, size_t reserveSize);
			
			ObjectReturn insertObject(const EA::String& key);
			ObjectReturn insertObject(const char* key);
			
			bool contains(const EA::String& key) const;
			bool contains(const char* key) const;

			void erase(const EA::String& key);
			void erase(const char* key);
			
		private:
		
			BaseTypeMap mValue;
		};

		template<bool Condition, typename T>
		struct EnableIfImpl;

		template<typename Condition, typename T = void>
		struct EnableIf : EnableIfImpl<Condition::value, T> {};

		template<typename T>
		struct EnableIfImpl<true, T> { typedef T type; };

		template<typename T>
		struct EnableIfImpl<false, T> {};

		template<typename Condition, typename T = void>
		struct DisableIf : EnableIfImpl<!Condition::value, T> {};

		template<typename Base, typename Derived>
		struct IsBaseOf
		{
			struct Yes { char mPad[1]; };
			struct No { char mPad[2]; };

			static Yes Check(Base*);
			static No Check(...);

			static const bool value = sizeof(Check(static_cast<Derived*>(NULL))) == sizeof(Yes);
		};

		template<>
		struct BaseTypeTraits1<bool>
		{
			static BaseTypeReturn BaseType(Factory* factory, bool value) { return factory->Boolean(value); }

			static bool As(BaseTypeIn baseType) { return baseType->AsBool(); }
		};

		template<>
		struct BaseTypeTraits1<int>
		{
			static BaseTypeReturn BaseType(Factory* factory, int value) { return factory->Number(value); }

			static int As(BaseTypeIn baseType) { return baseType->AsInt(); }
		};

		template<>
		struct BaseTypeTraits1<unsigned int>
		{
			static BaseTypeReturn BaseType(Factory* factory, unsigned int value) { return factory->Number(value); }

			static unsigned int As(BaseTypeIn baseType) { return baseType->AsUnsignedInt(); }
		};

		template<>
		struct BaseTypeTraits1<float>
		{
			static BaseTypeReturn BaseType(Factory* factory, float value) { return factory->Number(value); }

			static float As(BaseTypeIn baseType) { return baseType->AsFloat(); }
		};

		template<>
		struct BaseTypeTraits1<BaseTypeFloat>
		{
			static BaseTypeReturn BaseType(Factory* factory, BaseTypeFloat value) { return factory->Number(value); }

			static double As(BaseTypeIn baseType) { return baseType->AsBaseTypeFloat(); }
		};

		template<>
		struct BaseTypeTraits1<const char*>
		{
			static BaseTypeReturn BaseType(Factory* factory, const char* value) { return factory->String(value); }

			static const char* As(BaseTypeIn baseType) { return baseType->AsCStr(); }
		};

		template<>
		struct BaseTypeTraits2<const char*, size_t>
		{
			static BaseTypeReturn BaseType(Factory* factory, const char* value, size_t length) { return factory->String(value, length); }
		};

		template<>
		struct BaseTypeTraits1<char*> : BaseTypeTraits1<const char*> {};

		template<>
		struct BaseTypeTraits1<const EA::String&>
		{
			static BaseTypeReturn BaseType(Factory* factory, const EA::String& value) { return factory->String(value); }

			static const EA::String& As(BaseTypeIn baseType) { return baseType->AsEAString(); }
		};

		template<>
		struct BaseTypeTraits1<EA::String> : BaseTypeTraits1<const EA::String&> {};

		template<typename T>
		struct BaseTypeTraits1<const T&, typename EnableIf<IsBaseOf<EA::String, T> >::type> : BaseTypeTraits1<const EA::String&> {};

		template<typename T>
		struct BaseTypeTraits1<T, typename EnableIf<IsBaseOf<EA::String, T> >::type> : BaseTypeTraits1<const EA::String&> {};

		template<>
		struct BaseTypeTraits1<const EA::RawString&>
		{
			static BaseTypeReturn BaseType(Factory* factory, const EA::RawString& value) { return factory->String(value); }
		};

		template<>
		struct BaseTypeTraits1<EA::RawString> : BaseTypeTraits1<const EA::RawString&> {};

		template<typename T>
		struct BaseTypeTraits1<const T&, typename EnableIf<IsBaseOf<EA::RawString, T> >::type> : BaseTypeTraits1<const EA::RawString&> {};

		template<typename T>
		struct BaseTypeTraits1<T, typename EnableIf<IsBaseOf<EA::RawString, T> >::type> : BaseTypeTraits1<const EA::RawString&> {};

		template<>
		struct BaseTypeTraits1<const char**>
		{
			static BaseTypeReturn BaseType(Factory* factory, const char** value)
			{
				const char** strArray = static_cast<const char**>(value);

				EA::Types::ArrayRef result;

				if(strArray != NULL)
				{
					result = factory->Array();

					for(size_t i = 0; strArray[i] != NULL; ++i)
					{
						result->push_back(strArray[i]);
					}
				}

				return result;
			}
		};

		template<typename T>
		struct BaseTypeTraits1<T*, typename EnableIf<IsBaseOf<BaseType, T> >::type>
		{
			static BaseTypeReturn BaseType(Factory* factory, T* value)
			{
				return value;
			}
		};

		template<typename T>
		struct AutoRefBaseTypeTraits
		{
			static BaseTypeReturn BaseType(Factory* factory, AutoRefIn<T> value)
			{
				return value;
			}
		};

		template<typename T>
		struct BaseTypeTraits1<AutoRef<T>, typename EnableIf<IsBaseOf<BaseType, T> >::type> : AutoRefBaseTypeTraits<T> {};

		template<typename T>
		struct BaseTypeTraits1<AutoRefIn<T>, typename EnableIf<IsBaseOf<BaseType, T> >::type> : AutoRefBaseTypeTraits<T> {};


#if !defined(EA_FINAL)
		/*!
		*	Print the contents of a BaseType to TTY
		*	@param[in]	pVal a pointer to the BaseType instance to print
		*	@attention	The implementation is dependent on EA_LOG_ENABLED being defined and uses the EA_LOGD macro
		*	with "EABaseTypes" as the trace group
		*/
		void DumpBaseType(EA::RawString& dst, ConstBaseTypeIn pVal);

		/*!
		*	Print the contents of an Object to TTY
		*	@param[in]	pObj a pointer to the Object instance to print
		*	@param[in]	pTabs used for formatting nested elements
		*	@attention	The implementation is dependent on EA_LOG_ENABLED being defined and uses the EA_LOGD macro
		*	with "EABaseTypes" as the trace group
		*/
		void DumpObject(EA::RawString& dst, ConstObjectIn pObj, const char* pTabs);

		/*!
		*	Print the contents of an Array to TTY
		*	@param[in]	pArray a pointer to the Array instance to print
		*	@param[in]	pTabs used for formatting nested elements
		*	@attention	The implementation is dependent on EA_LOG_ENABLED being defined and uses the EA_LOGD macro
		*	with "EABaseTypes" as the trace group
		*/
		void DumpArray(EA::RawString& dst, ConstArrayIn pArray, const char* pTabs);
#endif /* !defined(EA_FINAL) */
	}
}

#define EABASETYPES_NEW_OPERATORS(EABASETYPES_GET_FACTORY)\
	void* operator new(size_t size)\
	{\
		return EA::Types::BaseType::Alloc(size, EABASETYPES_GET_FACTORY, "EA::Types::BaseType", EA::Allocator::MEM_TEMP);\
	}\
	\
	void* operator new(size_t size, const char* name, EA::Allocator::AllocFlags eFlags) \
	{\
		return EA::Types::BaseType::Alloc(size, EABASETYPES_GET_FACTORY, name, eFlags);\
	}

#define EABASETYPES_BASETYPES(EABASETYPES_GET_FACTORY)\
	class Number : public EA::Types::Number\
	{\
	public:\
		EABASETYPES_NEW_OPERATORS(EABASETYPES_GET_FACTORY)\
		Number():EA::Types::Number(EABASETYPES_GET_FACTORY) {}\
		explicit Number(int val):EA::Types::Number(EABASETYPES_GET_FACTORY, val) {}\
		explicit Number(unsigned int val):EA::Types::Number(EABASETYPES_GET_FACTORY, val) {}\
		explicit Number(EA::BaseTypeFloat val):EA::Types::Number(EABASETYPES_GET_FACTORY, val) {}\
	};\
	class String : public EA::Types::String\
	{\
	public:\
		EABASETYPES_NEW_OPERATORS(EABASETYPES_GET_FACTORY)\
		String():EA::Types::String(EABASETYPES_GET_FACTORY) {}\
		explicit String(const char* val):EA::Types::String(EABASETYPES_GET_FACTORY, val) {}\
		explicit String(const EA::String& val):EA::Types::String(EABASETYPES_GET_FACTORY, val) {}\
		explicit String(const EA::RawString& val):EA::Types::String(EABASETYPES_GET_FACTORY, val) {}\
		String(const char* val, size_t length):EA::Types::String(EABASETYPES_GET_FACTORY, val, length) {}\
	};\
	\
	class Boolean : public EA::Types::Boolean\
	{\
	public:\
		EABASETYPES_NEW_OPERATORS(EABASETYPES_GET_FACTORY)\
		Boolean():EA::Types::Boolean(EABASETYPES_GET_FACTORY) {}\
		explicit Boolean(bool val):EA::Types::Boolean(EABASETYPES_GET_FACTORY, val) {}\
	};\
	\
	class Function : public EA::Types::Function\
	{\
	public:\
		EABASETYPES_NEW_OPERATORS(EABASETYPES_GET_FACTORY)\
		Function():EA::Types::Function(EABASETYPES_GET_FACTORY) {}\
	};\
	\
	class UserData : public EA::Types::UserData\
	{\
	public:\
		EABASETYPES_NEW_OPERATORS(EABASETYPES_GET_FACTORY)\
		UserData():EA::Types::UserData(EABASETYPES_GET_FACTORY) {}\
	};\
	\
	class Array : public EA::Types::Array\
	{\
	public:\
		EABASETYPES_NEW_OPERATORS(EABASETYPES_GET_FACTORY)\
		Array():EA::Types::Array(EABASETYPES_GET_FACTORY) {}\
		explicit Array(unsigned int reserveSize):EA::Types::Array(EABASETYPES_GET_FACTORY, reserveSize) {}\
	};\
	\
	class Object : public EA::Types::Object\
	{\
	public:\
		EABASETYPES_NEW_OPERATORS(EABASETYPES_GET_FACTORY)\
		Object():EA::Types::Object(EABASETYPES_GET_FACTORY) {}\
	};

#endif // EABASETYPES_DATATYPES_H_
