// Author : Chris Tolley
// Date   : 8/2/2004
// SmartPointer.h contains the class declaration for a class of smart pointers
// that will delete the dynamic memory stored inside them and know when an object
// that they point to has been deleted

#include "SmartPointer.h"
#include "logger.h"

unsigned int SmartPointer::m_uiIdGenerator = 0;

// Constructor
SmartPointer::SmartPointer() 
: m_Target( NULL ), m_iRefCount( NULL ), m_bValid( NULL )
, m_uiId( m_uiIdGenerator++ ), m_bThisValid( false )
{
//	logger::event( "SP::Constructor", "Setting all to NULL", m_uiId );
}


// Constructor,  newObject must be declared with new
SmartPointer::SmartPointer( Object* newObject ) : m_iRefCount( new int( 1 ) ), 
						m_bValid( new bool( true ) ), m_Target( newObject )
						, m_uiId( m_uiIdGenerator++ ), m_bThisValid( true )
{
//	logger::event( "SP::Object Constructor", "Setting all", m_uiId );
}// End SmartPointer::Constructor


// Copy Constructor
SmartPointer::SmartPointer( const SmartPointer& rhs ) 
: m_bValid( rhs.m_bValid ), m_iRefCount( rhs.m_iRefCount ),
  m_Target( rhs.m_Target ) ,m_uiId( m_uiIdGenerator++ ), m_bThisValid( true )
{
	// Point all of this's private data to rhs's private data
//	m_bValid	= rhs.m_bValid;
//	m_iRefCount = rhs.m_iRefCount;
//	m_Target	= rhs.m_Target;

	// Increment the reference count
//	++( *m_iRefCount );
	
//	logger::event( "SP::Copy Constructor", "Setting all to rhs", m_uiId );

	// If the reference count is not NULL
	if( m_iRefCount != NULL )
	{
//		logger::event( "SP::Copy Constructor", "RefCount not NULL", m_uiId );
		++( *m_iRefCount );
	}// End if
}// End SmartPointer::Copy Constructor


// Destructor
SmartPointer::~SmartPointer()
{
//	logger::event( "SP::Destructor", "At start", m_uiId );
	// Deincrement the reference count if there is one
	if( m_iRefCount != NULL )
	{
//		logger::event( "SP::Destructor", "Deincrementing RefCount", m_uiId );
		--(*m_iRefCount);

		// If the reference count is zero,
		if( *m_iRefCount == 0 )
		{
//			logger::event( "SP::Destructor", "RefCount 0", m_uiId );
			// Then we can delete target if it hasn't already been deleted
			if( *m_bValid )
			{
				delete m_Target;
			}// End if

			// Delete the reference count and memory status flat
			delete m_bValid;
			delete m_iRefCount;
		}// End if
	}// End if
}// End SmartPointer::Destructor


// Operator equals
SmartPointer& SmartPointer::operator = ( const SmartPointer& rhs )
{
//	logger::event( "SP::operator =", "At start", m_uiId );
	// Deincrement this's reference count if we have one
	if( m_iRefCount != NULL )
	{
//		logger::event( "SP::operator =", "RefCount not NULL", m_uiId );
		--( *m_iRefCount );

		// Check to see if we need to delete this's data now
		if( *m_iRefCount == 0 )
		{
//			logger::event( "SP::operator =", "Ref Count 0", m_uiId );
			// Delete the reference count
			delete m_iRefCount;

			// If the target has not already been deleted
			if( *m_bValid )
			{
				// Delete it
				delete m_Target;
			}// End if
	
			// Delete the valid flat
			delete m_bValid;
		}// End if
	}// End if

//	logger::event( "SP::operator =", "Assigning new data", m_uiId );
	// Now set this's data to rhs's data
	m_bValid	= rhs.m_bValid;
	m_iRefCount = rhs.m_iRefCount;
	m_Target	= rhs.m_Target;
	m_bThisValid = true;

//	logger::event( "SP::operator =", "++RefCount", m_uiId );
	// Increment the reference count
	if( m_iRefCount != NULL )
		++( *m_iRefCount );

	// Return this
	return *this;
}// End SmartPointer::operator =


void SmartPointer::Delete()
{
//	logger::event( "SP::Delete", "Deleting target", m_uiId );
	delete m_Target; *m_bValid = false;
}// End SmartPointer::Delete