// Author: Juan Carlos De Abreu (jcabreur@gmail.com)
//

#ifndef BASE_MEMORY_SMART_POINTER_H__
#define BASE_MEMORY_SMART_POINTER_H__

#include "../../global.h"
#include "../../Includes/Basic.h"

BEGIN_TEG_NAMESPACE();

template<class T>
class SmartPointer {
 public:
  // SmartPointer constructors and destructor.
  SmartPointer(T* _pObj = NULL);
  SmartPointer(const SmartPointer<T>& p);
  ~SmartPointer();

  // Operators for assigning a plain pointer and anoteher smart pointer.
  inline void operator = (T* _pObj);
  inline void operator = (const SmartPointer<T>& sp);

  // Operators to access as a reference and as a pointer.
  inline T& operator *() const;
  inline T* operator ->() const;

  // Operator that allow the smart pointer to be automatically converted to
  // type T*
  inline operator T*() const;							

  // Operators to compare a smart pointer with other smart pointer and with a
  // plain pointer.
  inline bool operator !();
  inline bool operator == (const SmartPointer<T>& sp) const;
  inline bool operator == (const T* _pObj) const;

  // Method to check if is a valid pointer.
  inline bool isValid() const;

 protected:
  // SmartPointer attributes.
  T* pObj;
};

// Constructing with a pointer
template<class T>
SmartPointer<T>::SmartPointer(T* _pObj) : pObj(NULL) {
  *this = _pObj;
}

// Constructing with another smart pointer (copy constructor)
template<class T>
SmartPointer<T>::SmartPointer(const SmartPointer<T>& sp) : pObj(NULL) {
  *this = sp;
}

// Destructor
template<class T>
SmartPointer<T>::~SmartPointer() {
  if (pObj) pObj->Release();
}

// Assignement operators - assigning a plain pointer
template<class T>
inline void SmartPointer<T>::operator = (T* _pObj) {
  if (pObj) pObj->Release();
  pObj = _pObj;
  if (pObj) pObj->AddRef();
}

// Assigning another smart pointer
template<class T>
inline void SmartPointer<T>::operator = (const SmartPointer<T>& sp) {
  if (pObj) pObj->Release();
  pObj = sp.pObj;
  if (pObj) pObj->AddRef();
}

// Access as a reference
template<class T>
inline T& SmartPointer<T>::operator *() const {
  assert(pObj != 0 && "Tried to * on a NULL smart pointer");
  return *pObj;
}

// Access as a pointer
template<class T>
inline T* SmartPointer<T>::operator ->() const {
  assert(pObj != 0 && "Tried to -> on a NULL smart pointer");
  return pObj;
}

// Conversion - allow the smart pointer to be automatically converted to type T*
template<class T>
inline SmartPointer<T>::operator T*() const {
  return pObj;
}

// 
template<class T>
inline bool SmartPointer<T>::isValid() const {
  return (pObj != 0);
}

// 
template<class T>
inline bool SmartPointer<T>::operator !() {
  return !(pObj);
}

// 
template<class T>
inline bool SmartPointer<T>::operator == (const SmartPointer<T>& sp) const {
  return (pObj == sp.pObj);
}

// 
template<class T>
inline bool SmartPointer<T>::operator == (const T* _pObj) const {
  return (pObj == _pObj);
}

END_TEG_NAMESPACE();

#endif  // BASE_MEMORY_SMART_POINTER_H__
