////////////////////////////////////////////////////////////////////////////////
///  @file   : auto_cleanup.h
///
///  Purpose : Declaration of templated class auto_cleanup
///
///  Created by : makom
///
///  Date:22.08.2007
////////////////////////////////////////////////////////////////////////////////

#ifndef __AUTO_CLEANUP_H__
#define __AUTO_CLEANUP_H__

//////////////////////////////////////////////////////////////////////////
/// @brief 		Abstract base class for defining how a functor has to be used.
///			99,9% of all the "cleanup" functions take no arguments and return void!
///			For the rest a special Functor has to be defined.
class MCleanupFunctor
{
    virtual void operator()() = 0;  
    virtual void Call() = 0;
    
}; // class MCleanupFunctor

//////////////////////////////////////////////////////////////////////////
/// @brief 		Derived template class for defining the functor 
///			which is used to call the "cleanup" function on the TClass instance.
template<class TClass>
class TCleanupFunctor : public MCleanupFunctor
{
public:
	
	/// Constructor
	/// @param anObject 	[in] : pointer to an object
	/// @param anFpt 		[in] : pointer to a member function
	TCleanupFunctor(TClass* anObject, void(TClass::*anFpt)())
	{
		iObject = anObject;
		iFpt = anFpt;
	};
	
	/// From MCleanupFunctor
	virtual void operator()()
	{
		(*iObject.*iFpt)();
	};
	
	/// From MCleanupFunctor
	virtual void Call()
	{
		(*iObject.*iFpt)();
	};
	
private:
	
	void (TClass::*iFpt)();   			// uses a pointer to a member function
	TClass* iObject;                  	// uses a pointer to an object
	
};	// class TCleanupFunctor

//////////////////////////////////////////////////////////////////////////
/// @brief 			Templated class for implementing the auto_cleanup. 
/// 				This template can be used for Symbians typical R classes.
///				Keep in mind: "." and "->" are used for different reasons!
///
///	@usage		This template can only be used for classes which have a cleanup function which looks
///				like "void CleanupFunction();"
///
/// 	RMy handle;									// creation (clean up via Close())
///	auto_cleanup<RMy> acHandle(&handle, &RMy::Close);			// takes ownership
///    User::Leave(KErrCancel);							// RMy instance is cleaned up correctly (RMy::Close() is called)
///	RMy& refHandle(*acHandle);							// get a reference (no ownership transfer!)
///	refHandle.SetSomeL(_L8("TestTestTest")); 				// call RMy::SetSomeL()
///	TPtrC8 some(acHandle->GetSome());						// dereferenced member operator
///	acHandle.Release();								// auto_cleanup releases the ownership
///	CleanupClosePushL(handle);							// has to be pushed for correct cleanup in case handle goes out of scope
///	/* ... */
/// 	CleanupStack::PopAndDestroy(&handle);
template<class TClass>
class auto_cleanup
{
public:

	/// Constructor
	/// Initializes the functor instance with a pointer to the instance and
	/// a pointer to the "cleanup" function.
	/// Puts the auto_cleanup instance on the cleanupstack and specifies a function
	/// which should be called in case of an exception.
	auto_cleanup(TClass* aPtr, void(TClass::*anFpt)()) : iPtr(aPtr),
														 iCleanup(aPtr, anFpt)
 	{
		CleanupStack::PushL(TCleanupItem(Close, static_cast<TAny*>(this)));
	};

	/// Destructor
	/// Is called when the auto_cleanup instance goes "out of scope" by returning from a function.
	~auto_cleanup()
	{ 
		// Check if auto_cleanup instance has ownership.
		// If not auto_cleanup::Release() was called before.
		if (iPtr)
		{
			CleanupStack::Pop();
			
			// call the functors cleanup function
			iCleanup.Call();
		}
 	};

	/// Dereference operator
	TClass& operator *() const
	{ 
		if (iPtr) return *iPtr;
	};
	
	/// Dereferenced member operator for getting a pointer to the
	/// instance which is wrapped by the auto_cleanup template class
	TClass* operator ->() const
	{
		return iPtr;
	};
	
	/// Getter function for getting a pointer to the
	/// instance which is wrapped by the auto_cleanup template class
	TClass* Get() const
	{
		return iPtr;
	};

	/// Release function for getting a pointer to the
	/// instance which is wrapped by the auto_cleanup template class
	/// This function releases ownership of the wrapped instance.
	/// The caller is now responsible for correct cleanup of the TClass instance.
	TClass* Release()
	{ 
		CleanupStack::Pop();
		TClass* pTemp = iPtr;
		iPtr = NULL;
		return pTemp;
	};
	
private:
	
	/// Cleanup function which is called when the CleanupStack cleans up
	/// the auto_close instance in case of an exception
	static void Close(TAny* aPtr)
	{ 
		// get a pointer to the auto_cleanup instance
		auto_cleanup<TClass>* obj = static_cast<auto_cleanup<TClass>*>(aPtr);
		
		obj->iCleanup.Call();
		obj->iPtr = NULL;
	};
	
	TClass*					iPtr;		///< has a TClass instance
	TCleanupFunctor<TClass>	iCleanup;	///< has a TCleanupFunctor<TClass> instance
	
};	// class auto_cleanup

#endif  // __AUTO_CLEANUP_H__


