/*
	ZWeakPointer.hpp
	Author: James Russell <jcrussell@762studios.com>
	Created: 08/12/2011

	Purpose: 
	
	TODO

	Don't pass these things around by pointer or reference unless you really know what you
	are doing.  You won't like the results.

	License: 

	TODO
*/

#pragma once

#ifndef _ZWEAKPOINTER_H
#define _ZWEAKPOINTER_H

#include <ZUtil/ZSmartPointer.hpp>

/*
DeallocLock macro, used to lock a weak pointer when in use to prevent 
deallocation.  Using this ensures that the ZReferenceCounter  functions 
SignalInUse / SignalUnused are respected.

	Usage:
	ZWeakPointer<Object> ptr;

	DeallocLock(ptr) {
	  ... code to execute using ptr ...
	}
*/
#define DeallocLock(weakPointer) if (ZWeakPointerDeallocLock dealloc_lock##__LINE__ = weakPointer())

/*
Struct used to ensure (via RAII and scoped construction and destruction) that while weak pointers 
are in use, the object will not be deallocated by the owning smart pointer.
*/
struct ZWeakPointerDeallocLock {
	
	//Indicates whether or not we successfully obtained the lock on our reference counter
	bool bLockObtained;

	//The reference counter we attempt to lock
	ZReferenceCounter* Ref;

	/*
	Default constructor.  Calls the SignalInUse function on _counter and stores the 
	result of the call.

	@param _counter - the reference counter struct to signal
	*/
	ZWeakPointerDeallocLock(ZReferenceCounter* _counter)
		: bLockObtained(_counter != NULL && _counter->SignalInUse()), Ref(_counter) 
	{ }

	/*
	Destructor.  If the lock was successfully obtained, will signal the object no longer
	in use.
	*/
	~ZWeakPointerDeallocLock() 
	{ 
		if (bLockObtained && Ref != NULL) 
			Ref->SignalUnused(); 
	}

	/*
	operator bool override.  Returns whether or not the lock was successful.

	@return (bool) - true if the lock succeeded, false otherwise
	*/
	operator bool () 
	{
		return bLockObtained;
	}
};

/*
Weak pointer class, used to maintain a weak reference to an object that has a reference
whose lifetime is maintained by instances of ZSmartPointer.

@param T - the type of object referenced by the weak pointer

@param R - the reference counter allocator type to use
*/
template <typename T, typename R = ZReferenceCounterAllocator >
class ZWeakPointer
{
private:
	//Managed Pointer
	T* Object;

	//Reference Counter Allocator, used to deallocate the ref counter
	R RefAllocator;

	//Reference Counter for the pointer
	ZReferenceCounter* Ref;

	//Checks to see if the object has lost all strong references and is deleted
	inline void CheckReferences()
	{
		if (Ref != NULL && Ref->GetStrongRefCount() == 0)
		{
			//There is an edge case here wherein the strong count is zero, the deallocation flag
			//on the reference counter has been set, but the object is in use (by us)
			if (Ref->State != ZREFCOUNTER_DEALLOC_BIT)
				return;

			ReferenceLost();

			Object = NULL;
			Ref = NULL;
		}
	}

	//Checks to see if the counter is NULL because the pointer is NULL and increments the count
	inline void ReferenceGained()
	{
		if (Ref != NULL)
			Ref->GainWeakRef();
	}

	//Checks to see if we can delete the reference and lowers the count
	inline void ReferenceLost()
	{
		//This can be NULL in the case of a default constructed (NULL) pointer
		if (Ref == NULL)
			return;

		ZASSERT_UTIL(Ref->GetWeakRefCount() > 0 && Object != NULL, "ZSmartPointer: Reference lost but object is already deleted!");

		uint32_t combinedCount = Ref->LoseWeakRef();

		if(combinedCount == 0) //If we by losing the weak reference we've reached zero on both weak/strong, deallocate the counter
		{
			//Deallocate the counter
			RefAllocator.DeallocateCounter(Ref);
		}

		//We lost our reference, so we don't need these
		Object = NULL;
		Ref = NULL;
	}

public:
	/*
	Default constructor.  Sets the reference to NULL.
	*/
	ZWeakPointer()
		: Object(NULL), Ref(NULL)
	{ }

	/*
	Copy constructor.

	@param _other - the other weak pointer
	*/
	ZWeakPointer(const ZWeakPointer<T, R>& _other)
		: Object(_other.Pointer()), Ref(_other.Counter())
	{
		ZASSERT_UTIL(!(Object != NULL && Ref == NULL), "ZWeakPointer: Copy constructor called from weak pointer with invalid reference counter!");

		ReferenceGained();
	}

	/*
	Conversion constructor.  Used to auto up-cast derived classes, or a 
	class/object convertible to T.

	@param D - the type contained by the other weak pointer
	@param S - the reference counter allocator type used by the other weak pointer
	@param _other - the other weak pointer
	*/
	template <typename D, typename S>
	ZWeakPointer(const ZWeakPointer<D, S>& _other)
		: Object(static_cast<T*>(_other.Pointer())), Ref(_other.Counter())
	{
		ZASSERT_UTIL(!(Object != NULL && Ref == NULL), "ZWeakPointer: Copy constructor called from weak pointer with invalid reference counter!");

		ReferenceGained();
	}

	/*
	Constructor.  Takes a ZSmartPointer instance to create a weak pointer.

	@param DF - the deallocation functor type used by the smart pointer
	@param _host - the host smart pointer used to initialize this weak pointer
	*/
	template <typename DF>
	ZWeakPointer(const ZSmartPointer<T, DF, R>& _host)
		: Object(_host.Pointer()), Ref(_host.Counter())
	{
		ZASSERT_UTIL(!(Object != NULL && Ref == NULL), "ZWeakPointer: Copy constructor called from smart pointer with invalid reference counter!");

		ReferenceGained();
	}

	/*
	Conversion constructor.  Used to construct from a ZSmartPointer of a derived class, 
	or a class/object convertible to T.

	@param D - the type contained by the other weak pointer
	@param DF - the deallocation functor type used by the smart pointer
	@param S - the reference counter allocator type used by the other weak pointer
	@param _host - the host smart pointer used to initialize this weak pointer
	*/
	template <typename D, typename DF, typename S>
	ZWeakPointer(const ZSmartPointer<D, DF, S>& _host)
		: Object(static_cast<T*>(_host.Pointer())), Ref(_host.Counter())
	{
		ZASSERT_UTIL(!(Object != NULL && Ref == NULL), "ZWeakPointer: Copy constructor called from smart pointer with invalid reference counter!");

		ReferenceGained();
	}

	/*
	Destructor.  Causes a weak reference to be lost.
	*/
	~ZWeakPointer()
	{
		ReferenceLost();
	}

	/*
	= operator overload.  This version is used only to assign to NULL and nullify
	the reference.

	@param _null - the NULL value
	@return (ZWeakPointer<T, R>&) - this weak pointer
	@assert - if _null is not the value NULL
	*/
	ZWeakPointer<T, R>& operator = (int _null)
	{
		ZASSERT_RUNTIME(_null == 0, "ZWeakPointer: Assignment operator to int can only be used to assign to NULL!");

		ReferenceLost();		//Lose a weak reference
		Object = NULL;			//Nullify our object pointer
		Ref = NULL;				//Nullify our reference counter

		return *this;
	}

	/*
	= operator overload.  Constructs this weak pointer from another weak pointer, 
	incrementing the weak reference count on the object.

	@param _other - the other weak pointer
	@return (ZWeakPointer<T, R>&)- this weak pointer
	*/
	ZWeakPointer<T, R>& operator = (const ZWeakPointer<T, R>& _other)
	{
		if (*this == _other || Ref == _other.Counter())
			return *this;

		ReferenceLost();				//Lose a reference to our current object
		Ref = _other.Counter();			//Get our new reference counter
		ReferenceGained();				//Increment the reference

		Object = _other.Pointer();		//Reference It

		return *this;
	}

	/*
	= operator overload.  Used to assign to derived classes or classes that 
	can be converted.

	@param D - the type contained by the other weak pointer
	@param S - the reference counter allocator type used by the other weak pointer
	@param _other - the other smart pointer
	@return (ZWeakPointer<T, R>&) - this weak pointer
	*/
	template <typename D, typename S>
	ZWeakPointer<T, R>& operator = (const ZWeakPointer<D, S>& _other)
	{
		T* testCast = static_cast<T*>(_other.Pointer()); ((void)testCast);	//This will fail to compile if T* cannot static cast to D*

		return *this = static_cast< ZWeakPointer<T, R> >(_other);
	}

	/*
	= operator overload.  Used to set the weak pointer from a host smart pointer.

	@param DF - the deallocation functor type used by the smart pointer
	@param _host - the host smart pointer used to initialize this weak pointer
	@return (ZWeakPointer<T, R>&) - this weak pointer
	*/
	template <typename DF>
	ZWeakPointer<T, R>& operator = (const ZSmartPointer<T, DF, R>& _host)
	{
		if (*this == _host || Ref == _host.Counter())
			return *this;

		ReferenceLost();				//Lose a reference to our current object

		Object = _host.Pointer();		//Reference It
		Ref = _host.Counter();			//Get our new reference counter

		ReferenceGained();				//Increment the reference


		return *this;
	}

	/*
	= operator overload.  Used to set the weak pointer from a host smart pointer of
	a derived type or a type that can be converted.

	@param D - the type contained by the other weak pointer
	@param DF - the deallocation functor type used by the smart pointer
	@param S - the reference counter allocator type used by the other weak pointer
	@param _host - the host smart pointer used to initialize this weak pointer
	@return (ZWeakPointer<T, R>&) - this weak pointer
	*/
	template <typename D, typename DF, typename S>
	ZWeakPointer<T, R>& operator = (const ZSmartPointer<D, DF, S>& _host)
	{
		T* testCast = static_cast<T*>(_host.Pointer()); ((void)testCast);	//This will fail to compile if T* cannot static cast to D*

		return *this = static_cast< ZSmartPointer<T, DF, R> >(_host);
	}

	/*
	== operator overload.  Checks to see if this weak pointer references the provided
	raw pointer.

	@param _ptr - the pointer to check
	@return (bool) - true if the pointer is referenced by the weak pointer, false otherwise
	*/
	bool operator == (const T* _ptr)
	{
		CheckReferences();

		return Object == _ptr;
	}

	/*
	== operator overload.  Checks to see if these pointers reference the same object.

	@param _other - the other weak pointer
	@return (bool) - true if they reference the same object, false otherwise
	*/
	bool operator == (const ZWeakPointer<T, R>& _other)
	{
		CheckReferences();

		return Object == _other.Pointer();
	}

	/*
	== operator overload.  Used to compare with weak pointers containing objects of a 
	derived type or a type that can be converted to T.

	@param D - the type contained by the other weak pointer
	@param S - the reference counter allocator type used by the other weak pointer
	@param _other - the other smart pointer
	@return (bool) - true if equal, false otherwise
	*/
	template <typename D, typename S>
	bool operator == (const ZWeakPointer<D, S>& _other)
	{
		CheckReferences();

		return Object == static_cast<T*>(_other.Pointer());
	}

	/*
	== operator overload.  Used to determine if this weak pointer and a smart pointer 
	reference the same object.

	@param DF - the deallocator functor used by the smart pointer
	@param _other - the other smart pointer
	@return (bool) - true if they reference the same object, false otherwise.
	*/
	template <typename DF>
	bool operator == (const ZSmartPointer<T, DF, R>& _other)
	{
		CheckReferences();

		return Object == _other.Pointer();
	}

	/*
	== operator overload.  Used to compare to determine if this weak pointer and a smart 
	pointer with different template types reference the same object.

	@param D - the type contained by the smart pointer
	@param DF - the deallocator functor used by the smart pointer
	@param S - the reference counter allocator type used by the other smart pointer
	@param _other - the other smart pointer
	@return -this weak pointer
	*/
	template <typename D, typename DF, typename S>
	bool operator == (const ZSmartPointer<D, DF, S>& _other)
	{
		return Object == static_cast<T*>(_other.Pointer());
	}

	/*
	!= operator overload.  Checks to see if this weak pointer does not 
	reference the provided raw pointer.

	@param _ptr - the pointer to check
	@return (bool) - false if equal, true otherwise
	*/
	bool operator != (const T* _ptr)
	{
		return !(*this == _ptr);
	}

	/*
	!= operator overload.  Checks to see if these pointers reference different 
	objects.

	@param _other - the other smart pointer
	@return (bool) - false if equal, true otherwise
	*/
	bool operator != (const ZWeakPointer<T, R>& _other)
	{
		return !(*this == _other);
	}

	/*
	!= operator overload.  Checks to see if these pointers reference different 
	objects.

	@param D - the type contained by the other weak pointer
	@param S - the reference counter allocator type for the other weak pointeR
	@param _other - the other smart pointer
	@return (bool) - false if equal, true otherwise
	*/
	template <typename D, typename S>
	bool operator != (const ZWeakPointer<D, S>& _other)
	{
		return !(*this == _other);
	}

	/*
	!= operator overload.  Used to determine if this weak pointer and the given smart
	pointer reference the same object.

	@param DF - the deallocator functor type for the smart pointer
	@param _other - the other smart pointer
	@return (bool) - false if equal, true otherwise
	*/
	template <typename DF>
	bool operator != (const ZSmartPointer<T, DF, R>& _other)
	{
		return !(*this == _other);
	}

	/*
	!= operator overload.  Used to determine if this weak pointer and the given smart
	pointer with different template arguments reference the same object.

	@param D - the type referenced by the other smart pointer
	@param DF - the deallocator functor type for the smart pointer
	@param S - the reference counter deallocator type for the smart pointer
	@param _other - the other smart pointer
	@return (bool) - false if equal, true otherwise
	*/
	template <typename D, typename DF, typename S>
	bool operator != (const ZSmartPointer<D, DF, S>& _other)
	{
		return !(*this == _other);
	}

	/*
	-> operator overload.  Allows this to be dereferenced as a T* would be.  ZWeakPointer instances
	should only be accessed (via -> and *) from within the scope of a DeallocLock macro.

	@return - the managed pointer
	@assert - if the pointer is NULL
	*/
	T* operator -> ()
	{
		CheckReferences();

		ZASSERT_RUNTIME(Object != NULL, "ZSmartPointer: Null Pointer Dereferenced!");

		return Object;
	}

	/*
	'*' operator overload.  Allows this to be dereferenced as a T* would be.  ZWeakPointer instances
	should only be accessed (via -> and *) from within the scope of a DeallocLock macro.

	@return - reference to the managed object
	@assert - if the object is NULL
	*/
	T& operator * ()
	{
		CheckReferences();

		ZASSERT_RUNTIME(Object != NULL, "ZSmartPointer: Null Pointer Dereferenced!");

		return *Object;
	}

	/*
	Operator override which enables use of the DeallocLock macro.  ZWeakPointer instances
	should only be accessed (via -> and *) from within the scope of a DeallocLock macro.

	@return (ZWeakPointerDeallocLock) - dealloc lock
	*/
	ZWeakPointerDeallocLock operator () ()
	{
		CheckReferences();

		return ZWeakPointerDeallocLock(Ref);
	}

	/*
	public ZWeakPointer<C, R>::Cast

	Used to cast this weak pointer into another type.  This will construct an
	additional weak pointer that also references the object.  The referenced 
	object must be convertible to type C* via static_cast.


	@param C - the type we should cast this weak pointer to 
	@return (ZWeakPointer<C, R>) - the casted weak pointer
	*/
	template <typename C>
	ZWeakPointer<C, R> Cast()
	{
		CheckReferences();

		return static_cast< ZWeakPointer<C, R> >(*this);
	}

	/*
	public ZWeakPointer<T, A>::Counter

	Gets the reference counter used by this weak pointer.

	@return (ZSmartPointerRefCounter*) - reference counter instance
	*/
	ZReferenceCounter* Counter() const 
	{ 
		return Ref; 
	}

	/*
	public ZWeakPointer<T, A>::Pointer

	Gets the weak pointer as a raw pointer.  Buyer beware.

	@return (T*) - raw pointer that this smart pointer manages
	*/
	T* Pointer() const 
	{ 
		return Object; 
	}
};

////////////////////////////////////////
/* ZArray Containment Specializations */
////////////////////////////////////////

//Helper function used to nullify references in a range
template <typename T,  typename R>
void ZWeakPointerArrayNullify(ZWeakPointer<T, R>* _array, size_t _start, size_t _end)
{
	for (size_t i = _start; i < _end; i++)
		_array[i] = NULL;
}

//Specialization for ZArray_ClearImpl containing ZWeakPointer
template <typename T, typename A,  typename R>
struct ZArray_ClearImpl< ZWeakPointer<T, R>, A> {

	inline static void Call(ZArray<ZWeakPointer<T, R>, A>& _self) 
	{
		//Nullify references
		ZWeakPointerArrayNullify(_self.Array, 0, _self.ArraySize);

		//Reset size and check integrity
		_self.ArraySize = 0;
		_self.CheckIntegrity();
	}

	inline static void Call(ZArray<ZWeakPointer<T, R>, A>& _self, size_t _newCapacity) 
	{
		//Nullify references
		ZWeakPointerArrayNullify(_self.Array, 0, _self.ArraySize);

		#if !ZSTL_DISABLE_RUNTIME_CHECKS
		ZSTL_ASSERT(_newCapacity > 0, "ZArray: Cannot set capacity to zero!");
		#endif

		//Reallocate if needed, drop our size to zero, and check integrity
		if (_newCapacity > _self.ArrayCapacity)
		{
			_self.Deallocate(_self.Array, _self.ArrayCapacity);
			_self.ArrayCapacity = _newCapacity;
			_self.Allocate(_self.ArrayCapacity);
		}

		_self.ArraySize = 0;
		_self.CheckIntegrity();
	}

};

//Specialization for ZArray_EraseImpl containing ZWeakPointer
template <typename T, typename A,  typename R>
struct ZArray_EraseImpl< ZWeakPointer<T, R>, A> {

	inline static ZWeakPointer<T, R> Call(ZArray<ZWeakPointer<T, R>, A>& _self, size_t _index) 
	{
		size_t index = _self.BoundsCheck(_index, _self.ArraySize);

		//Grab the currently held element, shift the array down, reduce size, and check integrity
		ZWeakPointer<T, R> element = _self.Array[index];

		for (size_t i = index; i + 1 < _self.ArraySize; i++)
			_self.Array[i] = _self.Array[i + 1];

		_self.ArraySize--;
		_self.CheckIntegrity();

		//Nullify reference
		ZWeakPointerArrayNullify(_self.Array, _self.ArraySize, _self.ArraySize + 1);

		return element;
	}

	inline static void Call(ZArray<ZWeakPointer<T, R>, A>& _self, const size_t _start, const size_t _end) 
	{
		size_t start = _self.BoundsCheck(_start, _self.ArraySize);
		size_t end = _self.BoundsCheck(_end, _self.ArraySize + 1);

		#if !ZSTL_DISABLE_RUNTIME_CHECKS
		ZSTL_ASSERT(start <= end, "ZArray: cannot erase with start < end!");
		#endif

		//Copy the elements down, compute new size, and check integrity
		for (size_t idx = start; idx + (end - start) < _self.ArraySize; idx++)
			_self.Array[idx] = _self.Array[idx + (end - start)];

		_self.ArraySize = _self.ArraySize - (end - start);
		_self.CheckIntegrity();

		//Nullify references (where we moved from)
		ZWeakPointerArrayNullify(_self.Array, _self.ArraySize, _self.ArraySize + (end - start));
	}
};

//Specialization for ZArray_PopBackImpl containing ZWeakPointer
template <typename T, typename A,  typename R>
struct ZArray_PopBackImpl< ZWeakPointer<T, R>, A> {

	inline static ZWeakPointer<T, R> Call(ZArray<ZWeakPointer<T, R>, A>& _self) 
	{
		#if !ZSTL_DISABLE_RUNTIME_CHECKS
		ZSTL_ASSERT(_self.ArraySize > 0, "ZArray: Cannot pop from array with no elements!");
		#endif

		ZWeakPointer<T, R> ptr = _self.Array[--(_self.ArraySize)];

		//Nullify reference
		ZWeakPointerArrayNullify(_self.Array, _self.ArraySize, _self.ArraySize + 1);

		//Grab the last element in the array and decrease our array size
		return ptr;
	}

};

//Specialization for ZArray_PopFrontImpl containing ZWeakPointer
template <typename T, typename A,  typename R>
struct ZArray_PopFrontImpl< ZWeakPointer<T, R>, A> {

	inline static ZWeakPointer<T, R> Call(ZArray<ZWeakPointer<T, R>, A>& _self) 
	{
		#if !ZSTL_DISABLE_RUNTIME_CHECKS
		ZSTL_ASSERT(_self.ArraySize > 0, "ZArray: Cannot pop from array with no elements!");
		#endif

		//This will nullify the reference
		return _self.Erase(0);
	}

};

//Specialization for ZArray_ResizeImpl containing ZWeakPointer
template <typename T, typename A,  typename R>
struct ZArray_ResizeImpl< ZWeakPointer<T, R>, A> {

	inline static void Call(ZArray<ZWeakPointer<T, R>, A>& _self, const size_t _size) 
	{
		//Nullify references if needed
		if (_size < _self.ArraySize)
			ZWeakPointerArrayNullify(_self.Array, _size, _self.ArraySize);

		//Check to see if we need more space, change our size, and check integrity
		if (_size > _self.ArrayCapacity)
			_self.Reserve(_size);

		_self.ArraySize = _size;
		_self.CheckIntegrity();
	}

	inline static void Call(ZArray<ZWeakPointer<T, R>, A>& _self, const size_t _size, const ZWeakPointer<T, R>& _value) 
	{
		//Nullify references if needed
		if (_size < _self.ArraySize)
			ZWeakPointerArrayNullify(_self.Array, _size, _self.ArraySize);

		//See if we need more space, copy in the new value, change our size, and check integrity
		if (_size > _self.ArrayCapacity)
			_self.Reserve(_size);

		for (size_t i = _self.ArraySize; i < _size; i++)
			_self.Array[i] = _value;

		_self.ArraySize = _size;
		_self.CheckIntegrity();
	}

};

///////////////////////////////////////
/* ZList Containment Specializations */
///////////////////////////////////////

//Specialization for ZList_ClearImpl containing ZWeakPointer
template <typename T, typename A,  typename R>
struct ZList_ClearImpl < ZWeakPointer<T, R>, A> {

	inline static void Call(ZList<ZWeakPointer<T, R>, A>& _self, ZListIterator< ZWeakPointer<T, R> >& _itr) {

		ZListNode<ZWeakPointer<T, R> >* next;
		ZListNode<ZWeakPointer<T, R> >* current = _itr.GetNode();

		_self.CheckIntegrity();

		//Early out
		if (_self.Empty())
			return;

		//If we are the starting node, be sure to reset the EmptyNode.Next pointer
		if (current == _self.EmptyNode.Next)
			_self.EmptyNode.Next = &_self.EmptyNode;

		//This is always true
		_self.EmptyNode.Previous = current->Previous;
		current->Previous->Next = &_self.EmptyNode;

		//Iterate and deallocate the nodes
		while (current != &_self.EmptyNode)
		{
			next = current->Next;
			current->Element = NULL;		//This is the specialization
			_self.DeallocateNode(current);
			current = next;
		}

		//Set the node on the iterator equal to the end node
		_itr.SetNode(&_self.EmptyNode);

		_self.CheckIntegrity();
	}

};

//Specialization for ZList_EraseImpl containing ZWeakPointer
template <typename T, typename A,  typename R>
struct ZList_EraseImpl < ZWeakPointer<T, R>, A> {

	inline static ZWeakPointer<T, R> Call(ZList<ZWeakPointer<T, R>, A>& _self, ZListIterator< ZWeakPointer<T, R> >& _itr)
	{
		ZWeakPointer<T, R> elem;
		ZListNode< ZWeakPointer<T, R> > *node = _itr.GetNode();

		#if !ZSTL_DISABLE_RUNTIME_CHECKS
		ZSTL_ASSERT(node != NULL, "ZList: Iterator is invalid!");
		ZSTL_ASSERT(node != &_self.EmptyNode, "ZList: Cannot erase end node!");
		#endif

		//Increment the iterator to the next list node to keep the iterator valid
		++_itr;
		
		//Rearrange the pointers
		node->Previous->Next = node->Next;
		node->Next->Previous = node->Previous;

		elem = node->Element;
		node->Element = NULL;			//This is the specialization

		_self.DeallocateNode(node);

		_self.CheckIntegrity();

		return elem;
	}

	inline static void Call(ZList<ZWeakPointer<T, R>, A>& _self, ZListIterator< ZWeakPointer<T, R> >& _start, const ZListIterator< ZWeakPointer<T, R> >& _end)
	{

		ZListNode< ZWeakPointer<T, R> > *nodeStart = _start.GetNode();
		ZListNode< ZWeakPointer<T, R> > *nodeEnd = _end.GetNode();

		ZListNode< ZWeakPointer<T, R> > *curNode;
		ZListNode< ZWeakPointer<T, R> > *prevNode;

		#if !ZSTL_DISABLE_RUNTIME_CHECKS
		ZSTL_ASSERT(nodeStart != NULL && nodeEnd != NULL, "ZList: Cannot erase with invalid iterator!");
		ZSTL_ASSERT(nodeStart != &_self.EmptyNode, "ZList: Cannot erase end node!");
		#endif

		//Rearrange the pointers
		nodeStart->Previous->Next = nodeEnd;
		nodeEnd->Previous = nodeStart->Previous;

		//Erase each element between from and to
		curNode = nodeStart;
		prevNode = NULL;

		while (curNode != nodeEnd)
		{
			#if !ZSTL_DISABLE_RUNTIME_CHECKS
			ZSTL_ASSERT(curNode != &_self.EmptyNode, "ZList: Cannot erase end node!");
			#endif

			prevNode = curNode;
			curNode = curNode->Next;

			prevNode->Element = NULL;			//This is the specialization
			_self.DeallocateNode(prevNode);
		}

		_start = _end;
	}

};

//Specialization for ZList_PopBackImpl containing ZWeakPointer
template <typename T, typename A,  typename R>
struct ZList_PopBackImpl  < ZWeakPointer<T, R>, A> {
	inline static ZWeakPointer<T, R> Call(ZList<ZWeakPointer<T, R>, A>& _self) {

		ZWeakPointer<T, R> elem;
		ZListNode< ZWeakPointer<T, R> > *node;

		#if !ZSTL_DISABLE_RUNTIME_CHECKS
		ZSTL_ASSERT(!_self.Empty(), "ZList: Cannot pop from back of empty list!");
		#endif

		//Grab the element at the back of the list
		node = _self.EmptyNode.Previous;
		
		//Remove the node from the list
		node->Previous->Next = &_self.EmptyNode;	
		_self.EmptyNode.Previous = node->Previous;

		//Get the element value and lose our reference
		elem = node->Element;
		node->Element = NULL;

		//Deallocate and then return
		_self.DeallocateNode(node);

		_self.CheckIntegrity();

		return elem;
	}
};

//Specialization for ZList_PopFrontImpl containing ZWeakPointer
template <typename T, typename A,  typename R>
struct ZList_PopFrontImpl < ZWeakPointer<T, R>, A> {
	inline static ZWeakPointer<T, R> Call(ZList<ZWeakPointer<T, R>, A>& _self) {

		ZWeakPointer<T, R> elem;
		ZListNode< ZWeakPointer<T, R> > *node;

		#if !ZSTL_DISABLE_RUNTIME_CHECKS
		ZSTL_ASSERT(!_self.Empty(), "ZList: Cannot pop from front of empty list!");
		#endif

		//Grab the element at the front of the list
		node = _self.EmptyNode.Next;

		//Remove the node from the list
		node->Next->Previous = node->Previous;
		node->Previous->Next = node->Next;

		//Get the element value and lose our reference
		elem = node->Element;
		node->Element = NULL;

		//Deallocate and then return
		_self.DeallocateNode(node);

		_self.CheckIntegrity();

		return elem;
	}
};

/////////////////////////////////////////////
/* ZRingBuffer Containment Specializations */
/////////////////////////////////////////////

//Specialization for ZRingBuffer_ClearImpl containing ZWeakPointer
template <typename T, typename P, typename A, typename R>
struct ZRingBuffer_ClearImpl  < ZWeakPointer<T, R>, P, A> {
	inline static void Call( ZRingBuffer< ZWeakPointer<T, R>, P, A>& _self )
	{
		// set to null to remove references
		for (size_t i = 0; i < _self.BufferSize; i++)
			_self.At(i) = ZWeakPointer<T, R>(NULL);

		_self.BufferSize = 0;
		_self.FrontIndex = 0;
		_self.BackIndex = 0;
	}
	inline static void Call( ZRingBuffer< ZWeakPointer<T, R>, P, A>& _self, size_t _newCapacity )
	{
		// set to null to remove references
		for (size_t i = 0; i < _self.BufferSize; i++)
			_self.At(i) = ZWeakPointer<T, R>(NULL);

		_self.Buffer.Resize(_newCapacity);

		_self.BufferSize = 0;
		_self.FrontIndex = 0;
		_self.BackIndex = 0;
	}
};

//Specialization for ZRingBuffer_EraseImpl containing ZWeakPointer
template <typename T, typename P, typename A, typename R>
struct ZRingBuffer_EraseImpl < ZWeakPointer<T, R>, P, A> {
	inline static T Call( ZRingBuffer< ZWeakPointer<T, R>, P, A>& _self, size_t _index)
	{
		//We are going to do this in a very naive fashion, as this container is not intended for these
		//kinds of operations anyhow.  Anyone who wishes to optimize this at a later date is welcome.

		_self.AlignBuffer();

		_self.BufferSize--;
		_self.BackIndex--;

		// set to null to remove references
		ZWeakPointer<T, R> ret = _self.Buffer.At(_index);
		_self.Buffer.At(_index) = ZWeakPointer<T, R>(NULL);
		return ret;

	}
	inline static void Call( ZRingBuffer< ZWeakPointer<T, R>, P, A>& _self, size_t _i, size_t _j )
	{
		//We are going to do this in a very naive fashion, as this container is not intended for these
		//kinds of operations anyhow.  Anyone who wishes to optimize this at a later date is welcome.

		size_t count;

		_self.AlignBuffer();

		count = (size_t)(_j - _i);

		_self.BufferSize = _self.BufferSize - count;
		_self.BackIndex = _self.BackIndex - count;

		// set to null to remove references
		for( size_t i = _i; i < _j; i++)
			_self.Buffer.At(i) = ZWeakPointer<T, R>(NULL);

		_self.Buffer.Erase(_i, _j);
	}
};

//Specialization for ZRingBuffer_PopBackImpl containing ZWeakPointer
template <typename T, typename P, typename A, typename R>
struct ZRingBuffer_PopBackImpl < ZWeakPointer<T, R>, P, A> {
	inline static T Call( ZRingBuffer< ZWeakPointer<T, R>, P, A>& _self )
	{
		#if !ZSTL_DISABLE_RUNTIME_CHECKS
		ZSTL_ASSERT( _self.BufferSize > 0, "ZRingBuffer::PopBack() caused underflow!");
		#endif

		size_t index = _self.BackIndex;

		_self.DecrementBack();

		_self.CheckIntegrity();

		// set to NULL to fix ref count issues
		ZWeakPointer<T, R> ret = _self.Buffer.At(index);
		_self.Buffer.At(index) = ZWeakPointer<T, R>(NULL);
		return ret;
	}
};

//Specialization for ZRingBuffer_PopFrontImpl containing ZWeakPointer
template <typename T, typename P, typename A, typename R>
struct ZRingBuffer_PopFrontImpl < ZWeakPointer<T, R>, P, A> {
	inline static T Call( ZRingBuffer< ZWeakPointer<T, R>, P, A>& _self )
	{
		#if !ZSTL_DISABLE_RUNTIME_CHECKS
		ZSTL_ASSERT( _self.BufferSize > 0, "ZRingBuffer::PopFront() caused underflow!");
		#endif

		size_t index = _self.FrontIndex;

		_self.IncrementFront();

		_self.CheckIntegrity();

		// set to NULL to fix ref count issues
		ZWeakPointer<T, R> ret = _self.Buffer.At(index);
		_self.Buffer.At(index) = ZWeakPointer<T, R>(NULL);
		return ret;
	}
};


#endif
