/** @file safecomuserdata.h
*	Userdata type for SafeCom::AutoRef
*	@author Chris Burns (cburns@ea.com)
*
*	EABaseTypes
*	(c) 2012 Electronic Arts Inc.
*/

#ifndef EABASETYPES_SAFECOMUSERDATA_H
#define EABASETYPES_SAFECOMUSERDATA_H

#include "EAAssert/eaassert.h"
#include "EABaseTypes/datatypes.h"
#include "SafeCom/AutoRef.h"

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

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

			virtual bool Equals(UserDataIn pCompare)
			{
				return EA::Type::TypeOf(*this) == pCompare->GetUserDataType() && mRef == static_cast<SafeComUserData<T>*>(pCompare.GetUnsafePointer())->mRef;
			}

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

			static UserDataReturn Create(EA::Types::Factory* factory, const EA::SafeCom::AutoRef<T>& ref)
			{
				return new(factory) SafeComUserData<T>(factory, ref);
			}

			static const EA::SafeCom::AutoRef<T>& AsRef(EA::Types::BaseTypeIn baseType)
			{
				if(baseType != NULL && baseType->GetType() == EA::Types::USERDATA_TYPE && baseType->AsUserData()->GetUserDataType() == EA::Type::TypeOf<SafeComUserData<T> >())
				{
					return static_cast<SafeComUserData<T>*>(baseType.GetUnsafePointer())->mRef;
				}
				else
				{
					static EA::SafeCom::AutoRef<T> ref;
					return ref;
				}
			}

		private:

			SafeComUserData(EA::Types::Factory* factory, const EA::SafeCom::AutoRef<T>& ref):UserData(factory), mRef(ref) {}

			EA::SafeCom::AutoRef<T> mRef;
		};
        
        template<typename T>
        UserDataReturn SafeComUserDataCreate(EA::Types::Factory* f, const EA::SafeCom::AutoRef<T>& ref)
        {
            return SafeComUserData<T>::Create(f, ref);
        }

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

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

			static const EA::SafeCom::AutoRef<T>& As(EA::Types::BaseTypeIn baseType) { return SafeComUserData<T>::AsRef(baseType); }
		};

		template<typename T>
		struct BaseTypeTraits1<EA::SafeCom::AutoRefReturn<T> > : BaseTypeTraits1<EA::SafeCom::AutoRef<T> > {};
	}
}

#endif // EABASETYPES_SAFECOMUSERDATA_H
