/** @file PODUserData.h
*	Userdata type for POD types
*	@author JP Flouret (jpflouret@ea.com)
*
*	EABaseTypes
*	(c) 2013 Electronic Arts Inc.
*/

#ifndef EABASETYPES_PODUSERDATA_H
#define EABASETYPES_PODUSERDATA_H

#include "EAAssert/eaassert.h"
#include "eabasetypes/datatypes.h"
#include "EAStdC/EAMemory.h"

namespace EA
{
	namespace Types
	{
		template<typename T> class PODUserData : public EA::Types::UserData
		{
		public:

			virtual BaseTypeReturn Clone() { return Create(mFactory, mT); }

            virtual bool Equals(UserDataIn pCompare)
			{
				return EA::Type::TypeOf(*this) == pCompare->GetUserDataType() && 0 == memcmp(&mT, &static_cast<PODUserData<T>*>(pCompare.GetUnsafePointer())->mT, sizeof(T));
			}

			virtual EA::Type::TypeID GetUserDataType() { return EA::Type::TypeOf(*this); }

            static UserDataReturn Create(Factory* factory) { return new (factory) PODUserData<T>(factory); }
			static UserDataReturn Create(Factory* factory, const T& t) { return new(factory) PODUserData<T>(factory, t); }

			static const T& AsPOD(BaseTypeIn baseType)
			{
				if(baseType != NULL && baseType->GetType() == EA::Types::USERDATA_TYPE && baseType->AsUserData()->GetUserDataType() == EA::Type::TypeOf<PODUserData<T> >())
				{
					return static_cast<PODUserData<T>*>(baseType.GetUnsafePointer())->mT;
				}
				else
				{
					static T t;
					return t;
				}
			}

		private:

            PODUserData(Factory* factory):UserData(factory), mT() {}
			PODUserData(Factory* factory, const T& t):UserData(factory), mT(t) {}

			T	mT;
		};
        
        template <class T>
        UserDataReturn PODUserDataCreate(EA::Types::Factory* f)
        {
            return PODUserData<T>::Create(f);
        }
        
        template <class T>
        UserDataReturn PODUserDataCreate(EA::Types::Factory* f, const T& p)
        {
            return PODUserData<T>::Create(f, p);
        }

		template<typename T, typename Enable>
		struct BaseTypeTraits1
		{
			static EA::Types::BaseTypeReturn BaseType(Factory* factory) { return UserData(factory); }

			static EA::Types::BaseTypeReturn BaseType(Factory* factory, const T& value) { return UserData(factory, value); }

			static EA::Types::UserDataReturn UserData(Factory* factory) { return PODUserData<T>::Create(factory); }

			static EA::Types::UserDataReturn UserData(Factory* factory, const T& value) { return PODUserData<T>::Create(factory, value); }

			static const T& As(EA::Types::BaseTypeIn baseType) { return PODUserData<T>::AsPOD(baseType); }
		};
	}
}

#endif // EABASETYPES_PODUSERDATA_H
