/** @file factory.h
*	Factory data needed for creating BaseTypes
*	@author Chris Burns (cburns@ea.com)
*
*	EABaseTypes
*	(c) 2012 Electronic Arts Inc.
*/

#ifndef EABASETYPES_FACTORY_H_
#define EABASETYPES_FACTORY_H_

// for size_t
#include "EABase/eabase.h"

#include "EABaseTypes/basetypefloat.h"
#include "EABaseTypes/autoref.h"

namespace EA
{
	namespace Allocator
	{
		class ICoreAllocator;
	}

	class StringTable;
	class String;
	class RawString;

	namespace Types
	{
		class CallerMap;
		class MetaTypes;

		template<typename T, typename Enable = void>
		struct BaseTypeTraits1;

		template<typename T1, typename T2, typename Enable = void>
		struct BaseTypeTraits2;
		
		EABASETYPES_FORWARD_DECLARATION(class, BaseType)
		EABASETYPES_FORWARD_DECLARATION(class, Boolean)
		EABASETYPES_FORWARD_DECLARATION(class, Number)
		EABASETYPES_FORWARD_DECLARATION(class, String)
		EABASETYPES_FORWARD_DECLARATION(class, Function)
		EABASETYPES_FORWARD_DECLARATION(class, Array)
		EABASETYPES_FORWARD_DECLARATION(class, Object)
		EABASETYPES_FORWARD_DECLARATION(class, UserData)

		/*! @class Factory factory.h	"EABaseTypes/factory.h"
		*	@brief Contains all the data needed for propagating BaseTypes
		*/
		class Factory
		{
		public:
			Factory(EA::Allocator::ICoreAllocator* allocator,
					EA::StringTable* stringTable,
					CallerMap* callerMap,
					MetaTypes* metaTypes);
                    
            virtual ~Factory();

			inline EA::Allocator::ICoreAllocator* GetAllocator() { return mAllocator; }
			inline EA::StringTable* GetStringTable() { return mStringTable; }
			inline CallerMap* GetCallerMap() { return mCallerMap; }
			inline MetaTypes* GetMetaTypes() { return mMetaTypes; }

			BooleanReturn Boolean();
			BooleanReturn Boolean(bool val);
			
			NumberReturn Number();
			NumberReturn Number(int val);
			NumberReturn Number(unsigned int val);
			NumberReturn Number(BaseTypeFloat val);
			
			StringReturn String();
			StringReturn String(const char* val);
			StringReturn String(const EA::String& val);
			StringReturn String(const EA::RawString& val);
			StringReturn String(const char* val, size_t length);
			
			ArrayReturn Array();
			ArrayReturn Array(size_t reserveSize);
			
			ObjectReturn Object();

			template<typename T>
			BaseTypeReturn BaseType() { return BaseTypeTraits1<T>::BaseType(this); }

			template<typename T>
			BaseTypeReturn BaseType(T value) { return BaseTypeTraits1<T>::BaseType(this, value); }

			template<typename T>
			UserDataReturn UserData() { return BaseTypeTraits1<T>::UserData(this); }

			template<typename T>
			UserDataReturn UserData(T value) { return BaseTypeTraits1<T>::UserData(this, value); }

			template<typename T>
			FunctionReturn Function(T value) { return BaseTypeTraits1<T>::Function(this, value); }

			template<typename T1, typename T2>
			FunctionReturn Function(T1 value1, T2 value2) { return BaseTypeTraits2<T1, T2>::Function(this, value1, value2); }

		protected:

			EA::Allocator::ICoreAllocator*	mAllocator;
			EA::StringTable*				mStringTable;
			CallerMap*						mCallerMap;
			MetaTypes*						mMetaTypes;
		};
        
        /*!
        *   Create a default factory using an allocator
        *	@param allocator    The allocator to use
        *   @return	Factory*
		*/
        Factory* CreateDefaultFactory(EA::Allocator::ICoreAllocator* allocator);
	}
}

#endif // EABASETYPES_FACTORY_H_
