/****************************************************************************************************

		MCSmartPtr.h
		Copyright: (c) 2001 Eovia Corp. All rights reserved.

		Author:	Charles
		Date:	12/10/2001

****************************************************************************************************/

#ifndef __MCSmartPtr__
#define __MCSmartPtr__

#if CP_PRAGMA_ONCE
#pragma once
#endif

#include "MCBasicDefines.h"
#include "MCPtr.h"

/// \addtogroup MCCore
/// \{

/// Like TMCPtr, TMCSmartPtr is a transparent wrapper around a regular pointer
/// But TMCSmartPtr owns the pointed data, and will delete it in its destructor.
/// It is very useful when you need to create a temporary object as you don't need to worry about destruction (and exceptions).
/// Example: 
/// \code
/// TMCSmartPtr<TMCOffscreen> offscreen;
/// offscreen= TMCOffscreen::Create(width, height, bitDepth);
/// \endcode
///
/// \note When you need a temporary buffer, it is better to use a TMCArray instead of TMCSmartPtr and new[] as the array will assert if you go too far.
///
template <class T> class TMCSmartPtr : public TMCPtr<T>
{
private: //Forbidden methods
	TMCSmartPtr(const TMCSmartPtr& ptr)						{ MCNotify("This should never be called"); }
	TMCSmartPtr& operator= (const TMCSmartPtr& fromSmart)	{ MCNotify("This should never be called"); }

public:
	TMCSmartPtr(T* ptr=NULL)
	{
		this->fObject=ptr; //gcc fix
	}
	~TMCSmartPtr()
	{
		Assign(&(this->fObject), NULL);
	}
	T* operator=(T* ptr)
	{
		return Assign(&(this->fObject),ptr);
	}
	
	void Allocate()
	{
		Assign(&(this->fObject),new T);
	}

	// ****************************************************************************
	//								CopyObjectFrom
	// 
	/// Creates a copy of the object pointed to by fromSmart and points to it.
	/// The previous object pointed by this will be deleted.
	/// 
	/// \param fromSmart  a pointer to the object that will be copied
	/// 
	inline void CopyObjectFrom(const TMCSmartPtr& fromSmart)
	{
		if (fromSmart.fObject)
		{
			Assign(&(this->fObject), new T(*fromSmart.fObject));
		}
		else
		{
			Assign(&(this->fObject), NULL);
		}
	}

	// ****************************************************************************
	//								TransferObjectFrom
	// 
	/// Transfers the pointed object from fromSmart to this and sets fromSmart to null
	/// 
	/// \param fromSmart  the pointer to acquire
	/// 
	template<class U>
	inline void TransferObjectFrom(TMCSmartPtr<U>& fromSmart)
	{		
		Assign(&(this->fObject), fromSmart.fObject);
		fromSmart.fObject= NULL;
	}
	
	// ****************************************************************************
	//								SetToNullWithoutDeleting
	// 
	/// Sets the internal pointer to NULL without deleting the pointed object.
	/// Use this to transfer ownership of the pointed object to a TMCPtrArray
	/// But don't forget to call DeleteAndRemoveAll on the array !
	/// 
	inline void	SetToNullWithoutDeleting()		{ this->fObject= NULL; }


	// ****************************************************************************
	//								AssignWithoutDeleting
	// 
	/// Assign a new value to the pointer without deleting the object previously
	/// pointed by it.
	/// 
	/// \param lp  The new value of the pointer.
	/// 
	inline void AssignWithoutDeleting(T* lp)
	{
		this->fObject = lp;
	}
	
	inline TMCSmartPtr* This()	{ return this; }	///< because & has been overriden differently :-(

protected:
	static T* Assign(T** pp, T* lp)
	{
		MCAssertPointerCheck(pp);
		MCAssert(!MCCheckDeceased(*pp));
		MCAssert((lp == NULL) || !MCCheckDeceased(lp));
		MCAssert((lp == NULL) || !MCCheckDeceased(*(void**)lp));
		if (lp == *pp) return lp;

		if (*pp)
		{
			delete (*pp);
		}
		*pp = lp;
		return lp;
	}

	template<class U> friend class TMCSmartPtr;
};


/// \}





#endif
