#ifndef _PTR_H_
#define _PTR_H_

#include "exceptions/exceptionnullptr.h"
#include "tobject.h"


/**
 * \brief Smart pointer template
 *
 * Manages reference couting for TObject and its subclasses.
 * Example of usage:
 * \code
 * {
 *    Ptr<MyClass> myClass=new MyClass();
 * }
 * \endcode 
 *
 * myClass will be disposed when reference is lost, in our example at the
 * end of the block.
 *
 * \note Avoid circular references, reference circle will not be disposed
 *       until end of the program.
 *
 * \see TObject
 *
 * \date 01-13-2006
 *
 * \author Ondrej Svejdar
 *
 * \todo 
 *
 * \bug 
 *
 */
template<class T>
class Ptr 
{
    TObject* data;
public:
	/**
	 * \brief Construct empty object. Analogy to "null".
	 */
	Ptr():data(0)
	{
	}

	/**
	 * \brief Start managing reference counting to TObject data
	 *
	 * If data is not NULL, increase data reference's counter by one.
	 * \param data pointer to TObject
	 */
	Ptr(TObject* data):data(data) 
	{ 
		if (data!=0) data->upcount(); 
	}

	/**
	 * \brief Copy constructor
	 *
	 * Set inner pointer to point to the same TObject as in ptr and increase
	 * reference's counter by one.
	 * \param ptr reference to Ptr class
	 */
	Ptr(const Ptr& ptr)
	{
        data=ptr.data;
		if (data!=0) data->upcount();
	}
    
	/**
	 * \brief Destructor
	 *
	 * Decrease reference counter of managed TObject by one.
	 * \return 
	 */
	~Ptr() 
	{
		if (data!=0) data->downcount(); 
		data=0;
	}
    
	/**
	 * \brief Retype instance to template class
	 * \return pointer to managed object
	 */
	operator T*(void)
	{ 
		return (T*)data; 
	}

	/**
	 * \brief Return managed object
	 * \return managed object
	 */
	TObject* asObject()
	{
		return data;
	}

	/**
	 * \brief Test if managed object is NULL
	 * \return true if instance is NULL
	 */
	bool isNull() const
	{
        return data==0;
	}

	/**
	 * \brief Use for smart acces to methods of managed object.
	 *
	 * Example:
	 * \code
	 * Ptr<MyClass> myClass=new MyClass();
	 * myClass->foo();
	 * \endcode
	 * \return pointer to managed object
	 */
	T* operator->(void) 
	{ 
		if (data==0) throw new ExceptionNullPtr();
		return (T*)data; 
	}

	/**
	 * \brief Use for smart acces to methods of managed object.
	 *
	 * Example:
	 * \code
	 * Ptr<MyClass> myClass=new MyClass();
	 * myClass->foo();
	 * \endcode
	 * \return  pointer to managed object
	 */
	const T* operator->(void) const
	{
		if (data==0) throw new ExceptionNullPtr();
		return (T*)data; 
	}

	/**
	 * \brief Comparator
	 *
	 * For enable usage of generic Ptr classes in the STL container classes.
	 * \param ptr reference to Ptr
	 * \return true if this instance is "less than" ptr
	 */
	bool operator<(const Ptr& ptr) const
	{
        if (data==0) return true;
		return data->compareTo(ptr.data);
	}

	/**
	 * \brief Assign operator
	 *
	 * Decrease reference counter of currently managed object, set managed object
	 * to managed object referenced by ptr, and increase it's reference counter.
	 * \param ptr reference to Ptr
	 * \return reference to this
	 */
	Ptr& operator=(const Ptr& ptr)
	{
		return operator=(ptr.data);
	}

	/**
	 * \brief Assign operator
	 *
	 * Decrease reference counter of currently managed object, set managed object
	 * to managed object referenced by ptr, and increase it's reference counter.
	 * \param ptr reference to Ptr
	 * \return reference to this
	 */
	Ptr& operator=(TObject* ptr) 
	{
        if (data!=0) data->downcount(); 
		data=ptr;
		if (data!=0) data->upcount();
		return *this;
    }
};


#endif/*_PTR_H_*/
