#pragma once

#include "CoreMinimal.h"

template <class UObjectType>
class TRootedObject
{
public:
	using SelfType = TRootedObject<UObjectType>;

	static_assert(TIsDerivedFrom<UObjectType, UObject>::Value, "This class only works with UObjects");

	TRootedObject() = default;

	explicit TRootedObject(UObjectType* Object)
		: OwnedObject(Object)
	{
		OwnedObject->AddToRoot();
	}

	TRootedObject(const SelfType& Other) = delete;
	SelfType& operator=(const SelfType& Other) = delete;


	TRootedObject(SelfType&& Other)
	{
		*this = Other;
	}

	SelfType& operator=(SelfType&& Other)
	{
		Swap(OwnedObject, Other.OwnedObject);
		return *this;
	}

	~TRootedObject()
	{
		if (::IsValid(OwnedObject))
		{
			OwnedObject->RemoveFromRoot();
		}
	}

	operator UObjectType*()
	{
		return RetrieveObject();
	}

	UObjectType* RetrieveObject()
	{
		UObjectType* Temp = OwnedObject;
		OwnedObject = nullptr;
		Temp->RemoveFromRoot();
		return Temp;
	}

	bool IsValid() const
	{
		return ::IsValid(OwnedObject);
	}

private:
	UObjectType* OwnedObject = nullptr;
};
