/** 
 * @file doublelinkedlist.h
 * @brief Provides a standard doubly linked list for fun and profit.
 *
 * $LicenseInfo:firstyear=2001&license=viewergpl$
 * 
 * Copyright (c) 2001-2008, Linden Research, Inc.
 * 
 * Second Life Viewer Source Code
 * The source code in this file ("Source Code") is provided by Linden Lab
 * to you under the terms of the GNU General Public License, version 2.0
 * ("GPL"), unless you have obtained a separate licensing agreement
 * ("Other License"), formally executed by you and Linden Lab.  Terms of
 * the GPL can be found in doc/GPL-license.txt in this distribution, or
 * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
 * 
 * There are special exceptions to the terms and conditions of the GPL as
 * it is applied to this Source Code. View the full text of the exception
 * in the file doc/FLOSS-exception.txt in this software distribution, or
 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception
 * 
 * By copying, modifying or distributing this software, you acknowledge
 * that you have read and understood your obligations described above,
 * and agree to abide by those obligations.
 * 
 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
 * COMPLETENESS OR PERFORMANCE.
 * $/LicenseInfo$
 */

#ifndef LL_DOUBLELINKEDLIST_H
#define LL_DOUBLELINKEDLIST_H

#include "llerror.h"
#include "llrand.h"

// node that actually contains the data
template <class DATA_TYPE> class LLDoubleLinkedNode
{
public:
	DATA_TYPE			*mDatap;
	LLDoubleLinkedNode	*mNextp;
	LLDoubleLinkedNode	*mPrevp;


public:
	// assign the mDatap pointer
	LLDoubleLinkedNode(DATA_TYPE *data);

	// destructor does not, by default, destroy associated data
	// however, the mDatap must be NULL to ensure that we aren't causing memory leaks
	~LLDoubleLinkedNode();

	// delete associated data and NULL out pointer
	void deleteData();

	// remove associated data and NULL out pointer
	void removeData();
};


const U32 LLDOUBLE_LINKED_LIST_STATE_STACK_DEPTH = 4;

template <class DATA_TYPE> class LLDoubleLinkedList
{
private:
	LLDoubleLinkedNode<DATA_TYPE> mHead;		// head node
	LLDoubleLinkedNode<DATA_TYPE> mTail;		// tail node
	LLDoubleLinkedNode<DATA_TYPE> *mQueuep;		// The node in the batter's box
	LLDoubleLinkedNode<DATA_TYPE> *mCurrentp;	// The node we're talking about

	// The state stack allows nested exploration of the LLDoubleLinkedList
	// but should be used with great care
	LLDoubleLinkedNode<DATA_TYPE> *mQueuepStack[LLDOUBLE_LINKED_LIST_STATE_STACK_DEPTH];
	LLDoubleLinkedNode<DATA_TYPE> *mCurrentpStack[LLDOUBLE_LINKED_LIST_STATE_STACK_DEPTH];
	U32 mStateStackDepth;
	U32	mCount;

	// mInsertBefore is a pointer to a user-set function that returns 
	// TRUE if "first" should be located before "second"
	// NOTE: mInsertBefore() should never return TRUE when ("first" == "second")
	// or never-ending loops can occur
	BOOL				(*mInsertBefore)(DATA_TYPE *first, DATA_TYPE *second);	
																				
public:
	LLDoubleLinkedList();

	// destructor destroys list and nodes, but not data in nodes
	~LLDoubleLinkedList();

	// put data into a node and stick it at the front of the list
	// set mCurrentp to mQueuep
	void addData(DATA_TYPE *data);

	// put data into a node and stick it at the end of the list
	// set mCurrentp to mQueuep
	void addDataAtEnd(DATA_TYPE *data);

	S32 getLength() const;
	// search the list starting at mHead.mNextp and remove the link with mDatap == data
	// set mCurrentp to mQueuep
	// return TRUE if found, FALSE if not found
	BOOL removeData(const DATA_TYPE *data);

	// search the list starting at mHead.mNextp and delete the link with mDatap == data
	// set mCurrentp to mQueuep
	// return TRUE if found, FALSE if not found
	BOOL deleteData(DATA_TYPE *data);

	// remove all nodes from the list and delete the associated data
	void deleteAllData();

	// remove all nodes from the list but do not delete data
	void removeAllNodes();

	BOOL isEmpty();

	// check to see if data is in list
	// set mCurrentp and mQueuep to the target of search if found, otherwise set mCurrentp to mQueuep
	// return TRUE if found, FALSE if not found
	BOOL	checkData(const DATA_TYPE *data);

	// NOTE: This next two funtions are only included here 
	// for those too familiar with the LLLinkedList template class.
	// They are depreciated.  resetList() is unecessary while 
	// getCurrentData() is identical to getNextData() and has
	// a misleading name.
	//
	// The recommended way to loop through a list is as follows:
	//
	// datap = list.getFirstData();
	// while (datap)
	// {
	//     /* do stuff */
	//     datap = list.getNextData();
	// }

		// place mQueuep on mHead node
		void resetList();
	
		// return the data currently pointed to, 
		// set mCurrentp to that node and bump mQueuep down the list
		// NOTE: this function is identical to getNextData()
		DATA_TYPE *getCurrentData();


	// reset the list and return the data currently pointed to, 
	// set mCurrentp to that node and bump mQueuep down the list
	DATA_TYPE *getFirstData();


	// reset the list and return the data at position n, set mCurentp 
	// to that node and bump mQueuep down the list
	// Note: n=0 will behave like getFirstData()
	DATA_TYPE *getNthData(U32 n);

	// reset the list and return the last data in it, 
	// set mCurrentp to that node and bump mQueuep up the list
	DATA_TYPE *getLastData();

	// return data in mQueuep,
	// set mCurrentp mQueuep and bump mQueuep down the list
	DATA_TYPE *getNextData();

	// return the data in mQueuep, 
	// set mCurrentp to mQueuep and bump mQueuep up the list
	DATA_TYPE *getPreviousData();

	// remove the Node at mCurrentp
	// set mCurrentp to mQueuep
	void removeCurrentData();

	// delete the Node at mCurrentp
	// set mCurrentp to mQueuep
	void deleteCurrentData();

	// remove the Node at mCurrentp and insert it into newlist
	// set mCurrentp to mQueuep
	void moveCurrentData(LLDoubleLinkedList<DATA_TYPE> *newlist);

	// insert the node in front of mCurrentp
	// set mCurrentp to mQueuep
	void insertNode(LLDoubleLinkedNode<DATA_TYPE> *node);

	// insert the data in front of mCurrentp
	// set mCurrentp to mQueuep
	void insertData(DATA_TYPE *data);

	// if mCurrentp has a previous node then :
	//   * swaps mCurrentp with its previous
	//   * set mCurrentp to mQueuep
	//     (convenient for forward bubble-sort)
	// otherwise does nothing
	void swapCurrentWithPrevious();

	// if mCurrentp has a next node then :
	//   * swaps mCurrentp with its next
	//   * set mCurrentp to mQueuep
	//     (convenient for backwards bubble-sort)
	// otherwise does nothing
	void swapCurrentWithNext();

	// move mCurrentp to the front of the list
	// set mCurrentp to mQueuep
	void moveCurrentToFront();
	
	// move mCurrentp to the end of the list
	// set mCurrentp to mQueuep
	void moveCurrentToEnd();

	// set mInsertBefore
	void setInsertBefore(BOOL (*insert_before)(DATA_TYPE *first, DATA_TYPE *second));

	// add data in front of first node for which mInsertBefore(datap, node->mDatap) returns TRUE
	// set mCurrentp to mQueuep
	BOOL addDataSorted(DATA_TYPE *datap);

	// sort the list using bubble-sort
	// Yes, this is a different name than the same function in LLLinkedList.
	// When it comes time for a name consolidation hopefully this one will win.
	BOOL bubbleSort();

	// does a single bubble sort pass on the list
	BOOL lazyBubbleSort();

	// returns TRUE if state successfully pushed (state stack not full)
	BOOL pushState();

	// returns TRUE if state successfully popped (state stack not empty)
	BOOL popState();

	// empties the state stack
	void clearStateStack();

	// randomly move the the links in the list for debug or (Discordian) purposes
	// sets mCurrentp and mQueuep to top of list
	void scramble();

private:
	// add node to beginning of list
	// set mCurrentp to mQueuep
	void addNode(LLDoubleLinkedNode<DATA_TYPE> *node);

	// add node to end of list
	// set mCurrentp to mQueuep
	void addNodeAtEnd(LLDoubleLinkedNode<DATA_TYPE> *node);
};

//#endif

////////////////////////////////////////////////////////////////////////////////////////////

// doublelinkedlist.cpp
// LLDoubleLinkedList template class implementation file.
// Provides a standard doubly linked list for fun and profit.
// 
// Copyright 2001, Linden Research, Inc.

//#include "llerror.h"
//#include "doublelinkedlist.h"

//////////////////////////////////////////////////////////////////////////////////////////
// LLDoubleLinkedNode
//////////////////////////////////////////////////////////////////////////////////////////


// assign the mDatap pointer
template <class DATA_TYPE>
LLDoubleLinkedNode<DATA_TYPE>::LLDoubleLinkedNode(DATA_TYPE *data) : 
	mDatap(data), mNextp(NULL), mPrevp(NULL)
{
}


// destructor does not, by default, destroy associated data
// however, the mDatap must be NULL to ensure that we aren't causing memory leaks
template <class DATA_TYPE>
LLDoubleLinkedNode<DATA_TYPE>::~LLDoubleLinkedNode()
{
	if (mDatap)
	{
		llerror("Attempting to call LLDoubleLinkedNode destructor with a non-null mDatap!", 1);
	}
}


// delete associated data and NULL out pointer
template <class DATA_TYPE>
void LLDoubleLinkedNode<DATA_TYPE>::deleteData()
{
	delete mDatap;
	mDatap = NULL;
}


template <class DATA_TYPE>
void LLDoubleLinkedNode<DATA_TYPE>::removeData()
{
	mDatap = NULL;
}


//////////////////////////////////////////////////////////////////////////////////////
// LLDoubleLinkedList
//////////////////////////////////////////////////////////////////////////////////////

//                                   <------- up -------
//
//                                               mCurrentp
//                                   mQueuep         |
//                                      |            |
//                                      |            | 
//                      .------.     .------.     .------.      .------.
//                      |      |---->|      |---->|      |----->|      |-----> NULL
//           NULL <-----|      |<----|      |<----|      |<-----|      |
//                     _'------'     '------'     '------'      '------:_
//             .------. /|               |             |               |\ .------.
//  NULL <-----|mHead |/                 |         mQueuep               \|mTail |-----> NULL
//             |      |               mCurrentp                           |      |
//             '------'                                                   '------'
//                               -------- down --------->

template <class DATA_TYPE>
LLDoubleLinkedList<DATA_TYPE>::LLDoubleLinkedList()
: mHead(NULL), mTail(NULL), mQueuep(NULL)
{
	mCurrentp = mHead.mNextp;
	mQueuep = mHead.mNextp;
	mStateStackDepth = 0;
	mCount = 0;
	mInsertBefore = NULL;
}


// destructor destroys list and nodes, but not data in nodes
template <class DATA_TYPE>
LLDoubleLinkedList<DATA_TYPE>::~LLDoubleLinkedList()
{
	removeAllNodes();
}


// put data into a node and stick it at the front of the list
// doesn't change mCurrentp nor mQueuep
template <class DATA_TYPE>
void LLDoubleLinkedList<DATA_TYPE>::addData(DATA_TYPE *data)
{
	// don't allow NULL to be passed to addData
	if (!data)
	{
		llerror("NULL pointer passed to LLDoubleLinkedList::addData()", 0);
	}

	// make the new node
	LLDoubleLinkedNode<DATA_TYPE> *temp = new LLDoubleLinkedNode<DATA_TYPE> (data);

	// add the node to the front of the list
	temp->mPrevp = NULL; 
	temp->mNextp = mHead.mNextp;
	mHead.mNextp = temp;

	// if there's something in the list, fix its back pointer
	if (temp->mNextp)
	{
		temp->mNextp->mPrevp = temp;
	}
	// otherwise, fix the tail of the list
	else 
	{
		mTail.mPrevp = temp;
	}

	mCount++;
}


// put data into a node and stick it at the end of the list
template <class DATA_TYPE>
void LLDoubleLinkedList<DATA_TYPE>::addDataAtEnd(DATA_TYPE *data)
{
	// don't allow NULL to be passed to addData
	if (!data)
	{
		llerror("NULL pointer passed to LLDoubleLinkedList::addData()", 0);
	}

	// make the new node
	LLDoubleLinkedNode<DATA_TYPE> *nodep = new LLDoubleLinkedNode<DATA_TYPE>(data);

	addNodeAtEnd(nodep);
	mCount++;
}


// search the list starting at mHead.mNextp and remove the link with mDatap == data
// set mCurrentp to mQueuep, or NULL if mQueuep points to node with mDatap == data
// return TRUE if found, FALSE if not found
template <class DATA_TYPE>
BOOL LLDoubleLinkedList<DATA_TYPE>::removeData(const DATA_TYPE *data)
{
	BOOL b_found = FALSE;
	// don't allow NULL to be passed to addData
	if (!data)
	{
		llerror("NULL pointer passed to LLDoubleLinkedList::removeData()", 0);
	}

	mCurrentp = mHead.mNextp;

	while (mCurrentp)
	{
		if (mCurrentp->mDatap == data)
		{
			b_found = TRUE;

			// if there is a next one, fix it
			if (mCurrentp->mNextp)
			{
				mCurrentp->mNextp->mPrevp = mCurrentp->mPrevp;
			}
			else // we are at end of list
			{
				mTail.mPrevp = mCurrentp->mPrevp;
			}

			// if there is a previous one, fix it
			if (mCurrentp->mPrevp)
			{
				mCurrentp->mPrevp->mNextp = mCurrentp->mNextp;
			}
			else // we are at beginning of list
			{
				mHead.mNextp = mCurrentp->mNextp;
			}

			// remove the node
			mCurrentp->removeData();
			delete mCurrentp;
			mCount--;
			break;
		}
		mCurrentp = mCurrentp->mNextp; 
	}

	// reset the list back to where it was
	if (mCurrentp == mQueuep)
	{
		mCurrentp = mQueuep = NULL;
	}
	else
	{
		mCurrentp = mQueuep;
	}

	return b_found;
}


// search the list starting at mHead.mNextp and delete the link with mDatap == data
// set mCurrentp to mQueuep, or NULL if mQueuep points to node with mDatap == data
// return TRUE if found, FALSE if not found
template <class DATA_TYPE>
BOOL LLDoubleLinkedList<DATA_TYPE>::deleteData(DATA_TYPE *data)
{
	BOOL b_found = FALSE;
	// don't allow NULL to be passed to addData
	if (!data)
	{
		llerror("NULL pointer passed to LLDoubleLinkedList::deleteData()", 0);
	}

	mCurrentp = mHead.mNextp;

	while (mCurrentp)
	{
		if (mCurrentp->mDatap == data)
		{
			b_found = TRUE;

			// if there is a next one, fix it
			if (mCurrentp->mNextp)
			{
				mCurrentp->mNextp->mPrevp = mCurrentp->mPrevp;
			}
			else // we are at end of list
			{
				mTail.mPrevp = mCurrentp->mPrevp;
			}

			// if there is a previous one, fix it
			if (mCurrentp->mPrevp)
			{
				mCurrentp->mPrevp->mNextp = mCurrentp->mNextp;
			}
			else // we are at beginning of list
			{
				mHead.mNextp = mCurrentp->mNextp;
			}

			// remove the node
			mCurrentp->deleteData();
			delete mCurrentp;
			mCount--;
			break;
		}
		mCurrentp = mCurrentp->mNextp;
	}

	// reset the list back to where it was
	if (mCurrentp == mQueuep)
	{
		mCurrentp = mQueuep = NULL;
	}
	else
	{
		mCurrentp = mQueuep;
	}

	return b_found;
}


// remove all nodes from the list and delete the associated data
template <class DATA_TYPE>
void LLDoubleLinkedList<DATA_TYPE>::deleteAllData()
{
	mCurrentp = mHead.mNextp;

	while (mCurrentp)
	{
		mQueuep = mCurrentp->mNextp;
		mCurrentp->deleteData();
		delete mCurrentp;
		mCurrentp = mQueuep;
	}

	// reset mHead and mQueuep
	mHead.mNextp = NULL;
	mTail.mPrevp = NULL;
	mCurrentp = mHead.mNextp;
	mQueuep = mHead.mNextp;
	mStateStackDepth = 0;
	mCount = 0;
}


// remove all nodes from the list but do not delete associated data
template <class DATA_TYPE>
void LLDoubleLinkedList<DATA_TYPE>::removeAllNodes()
{
	mCurrentp = mHead.mNextp;

	while (mCurrentp)
	{
		mQueuep = mCurrentp->mNextp;
		mCurrentp->removeData();
		delete mCurrentp;
		mCurrentp = mQueuep;
	}

	// reset mHead and mCurrentp
	mHead.mNextp = NULL;
	mTail.mPrevp = NULL;
	mCurrentp = mHead.mNextp;
	mQueuep = mHead.mNextp;
	mStateStackDepth = 0;
	mCount = 0;
}

template <class DATA_TYPE>
S32 LLDoubleLinkedList<DATA_TYPE>::getLength() const
{
//	U32	length = 0;
//	for (LLDoubleLinkedNode<DATA_TYPE>* temp = mHead.mNextp; temp != NULL; temp = temp->mNextp)
//	{
//		length++;
//	}
	return mCount;
}

// check to see if data is in list
// set mCurrentp and mQueuep to the target of search if found, otherwise set mCurrentp to mQueuep
// return TRUE if found, FALSE if not found
template <class DATA_TYPE>
BOOL LLDoubleLinkedList<DATA_TYPE>::checkData(const DATA_TYPE *data)
{
	mCurrentp = mHead.mNextp;

	while (mCurrentp)
	{
		if (mCurrentp->mDatap == data)
		{
			mQueuep = mCurrentp;
			return TRUE;
		}
		mCurrentp = mCurrentp->mNextp;
	}

	mCurrentp = mQueuep;
	return FALSE;
}

// NOTE: This next two funtions are only included here 
// for those too familiar with the LLLinkedList template class.
// They are depreciated.  resetList() is unecessary while 
// getCurrentData() is identical to getNextData() and has
// a misleading name.
//
// The recommended way to loop through a list is as follows:
//
// datap = list.getFirstData();
// while (datap)
// {
//     /* do stuff */
//     datap = list.getNextData();
// }

	// place mCurrentp and mQueuep on first node
	template <class DATA_TYPE>
	void LLDoubleLinkedList<DATA_TYPE>::resetList()
	{
		mCurrentp = mHead.mNextp;
		mQueuep = mHead.mNextp;
		mStateStackDepth = 0;
	}
	
	
	// return the data currently pointed to, 
	// set mCurrentp to that node and bump mQueuep down the list
	template <class DATA_TYPE>
	DATA_TYPE* LLDoubleLinkedList<DATA_TYPE>::getCurrentData()
	{
		if (mQueuep)
		{
			mCurrentp = mQueuep;
			mQueuep = mQueuep->mNextp;
			return mCurrentp->mDatap;
		}
		else
		{
			return NULL;
		}
	}


// reset the list and return the data currently pointed to, 
// set mCurrentp to that node and bump mQueuep down the list
template <class DATA_TYPE>
DATA_TYPE* LLDoubleLinkedList<DATA_TYPE>::getFirstData()
{
	mQueuep = mHead.mNextp;
	mCurrentp = mQueuep;
	if (mQueuep)
	{
		mQueuep = mQueuep->mNextp;
		return mCurrentp->mDatap;
	}
	else
	{
		return NULL;
	}
}


// reset the list and return the data at position n, set mCurentp 
// to that node and bump mQueuep down the list
// Note: n=0 will behave like getFirstData()
template <class DATA_TYPE>
DATA_TYPE* LLDoubleLinkedList<DATA_TYPE>::getNthData(U32 n)
{
	mCurrentp = mHead.mNextp;

	if (mCurrentp)
	{
		for (U32 i=0; i<n; i++)
		{
			mCurrentp = mCurrentp->mNextp;
			if (!mCurrentp)
			{
				break;
			}		
		}
	}

	if (mCurrentp)
	{
		// bump mQueuep down the list
		mQueuep = mCurrentp->mNextp;
		return mCurrentp->mDatap;
	}
	else
	{
		mQueuep = NULL;
		return NULL;
	}
}


// reset the list and return the last data in it, 
// set mCurrentp to that node and bump mQueuep up the list
template <class DATA_TYPE>
DATA_TYPE* LLDoubleLinkedList<DATA_TYPE>::getLastData()
{
	mQueuep = mTail.mPrevp;
	mCurrentp = mQueuep;
	if (mQueuep)
	{
		mQueuep = mQueuep->mPrevp;
		return mCurrentp->mDatap;
	}
	else
	{
		return NULL;
	}
}


// return the data in mQueuep, 
// set mCurrentp to mQueuep and bump mQueuep down the list
template <class DATA_TYPE>
DATA_TYPE* LLDoubleLinkedList<DATA_TYPE>::getNextData()
{
	if (mQueuep)
	{
		mCurrentp = mQueuep;
		mQueuep = mQueuep->mNextp;
		return mCurrentp->mDatap;
	}
	else
	{
		return NULL;
	}
}


// return the data in mQueuep, 
// set mCurrentp to mQueuep and bump mQueuep up the list
template <class DATA_TYPE>
DATA_TYPE* LLDoubleLinkedList<DATA_TYPE>::getPreviousData()
{
	if (mQueuep)
	{
		mCurrentp = mQueuep;
		mQueuep = mQueuep->mPrevp;
		return mCurrentp->mDatap;
	}
	else
	{
		return NULL;
	}
}


// remove the Node at mCurrentp
// set mCurrentp to mQueuep, or NULL if (mCurrentp == mQueuep)
template <class DATA_TYPE>
void LLDoubleLinkedList<DATA_TYPE>::removeCurrentData()
{
	if (mCurrentp)
	{
		// if there is a next one, fix it
		if (mCurrentp->mNextp)
		{
			mCurrentp->mNextp->mPrevp = mCurrentp->mPrevp;
		}
		else	// otherwise we are at end of list
		{
			mTail.mPrevp = mCurrentp->mPrevp;
		}

		// if there is a previous one, fix it
		if (mCurrentp->mPrevp)
		{
			mCurrentp->mPrevp->mNextp = mCurrentp->mNextp;
		}
		else	// otherwise we are at beginning of list
		{
			mHead.mNextp = mCurrentp->mNextp;
		}

		// remove the node
		mCurrentp->removeData();
		delete mCurrentp;
		mCount--;

		// check for redundant pointing
		if (mCurrentp == mQueuep)
		{
			mCurrentp = mQueuep = NULL;
		}
		else
		{
			mCurrentp = mQueuep;
		}
	}
}


// delete the Node at mCurrentp
// set mCurrentp to mQueuep, or NULL if (mCurrentp == mQueuep) 
template <class DATA_TYPE>
void LLDoubleLinkedList<DATA_TYPE>::deleteCurrentData()
{
	if (mCurrentp)
	{
		// remove the node
		// if there is a next one, fix it
		if (mCurrentp->mNextp)
		{
			mCurrentp->mNextp->mPrevp = mCurrentp->mPrevp;
		}
		else	// otherwise we are at end of list
		{
			mTail.mPrevp = mCurrentp->mPrevp;
		}

		// if there is a previous one, fix it
		if (mCurrentp->mPrevp)
		{
			mCurrentp->mPrevp->mNextp = mCurrentp->mNextp;
		}
		else	// otherwise we are at beginning of list
		{
			mHead.mNextp = mCurrentp->mNextp;
		}

		// remove the LLDoubleLinkedNode
		mCurrentp->deleteData();
		delete mCurrentp;
		mCount--;

		// check for redundant pointing
		if (mCurrentp == mQueuep)
		{
			mCurrentp = mQueuep = NULL;
		}
		else
		{
			mCurrentp = mQueuep;
		}
	}
}


// remove the Node at mCurrentp and insert it into newlist
// set mCurrentp to mQueuep, or NULL if (mCurrentp == mQueuep)
template <class DATA_TYPE>
void LLDoubleLinkedList<DATA_TYPE>::moveCurrentData(LLDoubleLinkedList<DATA_TYPE> *newlist)
{
	if (mCurrentp)
	{
		// remove the node
		// if there is a next one, fix it
		if (mCurrentp->mNextp)
		{
			mCurrentp->mNextp->mPrevp = mCurrentp->mPrevp;
		}
		else	// otherwise we are at end of list
		{
			mTail.mPrevp = mCurrentp->mPrevp;
		}

		// if there is a previous one, fix it
		if (mCurrentp->mPrevp)
		{
			mCurrentp->mPrevp->mNextp = mCurrentp->mNextp;
		}
		else	// otherwise we are at beginning of list
		{
			mHead.mNextp = mCurrentp->mNextp;
		}

		// move the node to the new list
		newlist->addNode(mCurrentp);

		// check for redundant pointing
		if (mCurrentp == mQueuep)
		{
			mCurrentp = mQueuep = NULL;
		}
		else
		{
			mCurrentp = mQueuep;
		}
	}
}


// Inserts the node previous to mCurrentp
// set mCurrentp to mQueuep
template <class DATA_TYPE>
void LLDoubleLinkedList<DATA_TYPE>::insertNode(LLDoubleLinkedNode<DATA_TYPE> *nodep)
{
	// don't allow pointer to NULL to be passed
	if (!nodep)
	{
		llerror("NULL pointer passed to LLDoubleLinkedList::insertNode()", 0);
	}
	if (!nodep->mDatap)
	{
		llerror("NULL data pointer passed to LLDoubleLinkedList::insertNode()", 0);
	}

	if (mCurrentp)
	{
		if (mCurrentp->mPrevp)
		{
			nodep->mPrevp = mCurrentp->mPrevp;
			nodep->mNextp = mCurrentp;
			mCurrentp->mPrevp->mNextp = nodep;
			mCurrentp->mPrevp = nodep;
		}
		else	// at beginning of list
		{
			nodep->mPrevp = NULL;
			nodep->mNextp = mCurrentp;
			mHead.mNextp = nodep;
			mCurrentp->mPrevp = nodep;
		}
		mCurrentp = mQueuep;
	}
	else	// add to front of list
	{
		addNode(nodep);
	}
}


// insert the data in front of mCurrentp
// set mCurrentp to mQueuep
template <class DATA_TYPE>
void LLDoubleLinkedList<DATA_TYPE>::insertData(DATA_TYPE *data)
{
	if (!data)
	{
		llerror("NULL data pointer passed to LLDoubleLinkedList::insertNode()", 0);
	}
	LLDoubleLinkedNode<DATA_TYPE> *node = new LLDoubleLinkedNode<DATA_TYPE>(data);
	insertNode(node);
	mCount++;
}


// if mCurrentp has a previous node then :
//   * swaps mCurrentp with its previous
//   * set mCurrentp to mQueuep
// otherwise does nothing
template <class DATA_TYPE>
void LLDoubleLinkedList<DATA_TYPE>::swapCurrentWithPrevious()
{
	if (mCurrentp)
	{
		if (mCurrentp->mPrevp)
		{
			// Pull mCurrentp out of list
			mCurrentp->mPrevp->mNextp = mCurrentp->mNextp;
			if (mCurrentp->mNextp)
			{
				mCurrentp->mNextp->mPrevp = mCurrentp->mPrevp;
			}
			else 	// mCurrentp was at end of list
			{
				mTail.mPrevp = mCurrentp->mPrevp;
			}

			// Fix mCurrentp's pointers
			mCurrentp->mNextp = mCurrentp->mPrevp;
			mCurrentp->mPrevp = mCurrentp->mNextp->mPrevp;
			mCurrentp->mNextp->mPrevp = mCurrentp;

			if (mCurrentp->mPrevp)
			{
				// Fix the backward pointer of mCurrentp's new previous
				mCurrentp->mPrevp->mNextp = mCurrentp;
			}
			else	// mCurrentp is now at beginning of list
			{
				mHead.mNextp = mCurrentp;
			}

			// Set the list back to the way it was
			mCurrentp = mQueuep;
		}
	}
}


// if mCurrentp has a next node then :
//   * swaps mCurrentp with its next
//   * set mCurrentp to mQueuep
// otherwise does nothing
template <class DATA_TYPE>
void LLDoubleLinkedList<DATA_TYPE>::swapCurrentWithNext()
{
	if (mCurrentp)
	{
		if (mCurrentp->mNextp)
		{
			// Pull mCurrentp out of list
			mCurrentp->mNextp->mPrevp = mCurrentp->mPrevp;
			if (mCurrentp->mPrevp)
			{
				mCurrentp->mPrevp->mNextp = mCurrentp->mNextp;
			}
			else 	// mCurrentp was at beginning of list
			{
				mHead.mNextp = mCurrentp->mNextp;
			}

			// Fix mCurrentp's pointers
			mCurrentp->mPrevp = mCurrentp->mNextp;
			mCurrentp->mNextp = mCurrentp->mPrevp->mNextp;
			mCurrentp->mPrevp->mNextp = mCurrentp;

			if (mCurrentp->mNextp)
			{
				// Fix the back pointer of mCurrentp's new next
				mCurrentp->mNextp->mPrevp = mCurrentp;
			}
			else 	// mCurrentp is now at end of list
			{
				mTail.mPrevp = mCurrentp;
			}
			
			// Set the list back to the way it was
			mCurrentp = mQueuep;
		}
	}
}

// move mCurrentp to the front of the list
// set mCurrentp to mQueuep
template <class DATA_TYPE>
void LLDoubleLinkedList<DATA_TYPE>::moveCurrentToFront()
{
	if (mCurrentp)
	{
		// if there is a previous one, fix it
		if (mCurrentp->mPrevp)
		{
			mCurrentp->mPrevp->mNextp = mCurrentp->mNextp;
		}
		else	// otherwise we are at beginning of list
		{
			// check for redundant pointing
			if (mCurrentp == mQueuep)
			{
				mCurrentp = mQueuep = NULL;
			}
			else
			{
				mCurrentp = mQueuep;
			}
			return;
		}

		// if there is a next one, fix it
		if (mCurrentp->mNextp)
		{
			mCurrentp->mNextp->mPrevp = mCurrentp->mPrevp;
		}
		else	// otherwise we are at end of list
		{
			mTail.mPrevp = mCurrentp->mPrevp;
		}

		// add mCurrentp to beginning of list
		mCurrentp->mNextp = mHead.mNextp;
		mHead.mNextp->mPrevp = mCurrentp;	// mHead.mNextp MUST be valid, 
											// or the list had only one node
											// and we would have returned already
		mCurrentp->mPrevp = NULL;
		mHead.mNextp = mCurrentp;

		// check for redundant pointing
		if (mCurrentp == mQueuep)
		{
			mCurrentp = mQueuep = NULL;
		}
		else
		{
			mCurrentp = mQueuep;
		}
	}

}

// move mCurrentp to the end of the list
// set mCurrentp to mQueuep
template <class DATA_TYPE>
void LLDoubleLinkedList<DATA_TYPE>::moveCurrentToEnd()
{
	if (mCurrentp)
	{
		// if there is a next one, fix it
		if (mCurrentp->mNextp)
		{
			mCurrentp->mNextp->mPrevp = mCurrentp->mPrevp;
		}
		else	// otherwise we are at end of list and we're done
		{
			// check for redundant pointing
			if (mCurrentp == mQueuep)
			{
				mCurrentp = mQueuep = NULL;
			}
			else
			{
				mCurrentp = mQueuep;
			}
			return;
		}

		// if there is a previous one, fix it
		if (mCurrentp->mPrevp)
		{
			mCurrentp->mPrevp->mNextp = mCurrentp->mNextp;
		}
		else	// otherwise we are at beginning of list
		{
			mHead.mNextp = mCurrentp->mNextp;
		}

		// add mCurrentp to end of list
		mCurrentp->mPrevp = mTail.mPrevp;
		mTail.mPrevp->mNextp = mCurrentp;	// mTail.mPrevp MUST be valid, 
											// or the list had only one node
											// and we would have returned already
		mCurrentp->mNextp = NULL;
		mTail.mPrevp = mCurrentp;

		// check for redundant pointing
		if (mCurrentp == mQueuep)
		{
			mCurrentp = mQueuep = NULL;
		}
		else
		{
			mCurrentp = mQueuep;
		}
	}
}


template <class DATA_TYPE>
void LLDoubleLinkedList<DATA_TYPE>::setInsertBefore(BOOL (*insert_before)(DATA_TYPE *first, DATA_TYPE *second) )
{
	mInsertBefore = insert_before;
}


// add data in front of the first node for which mInsertBefore(datap, node->mDatap) returns TRUE
// set mCurrentp to mQueuep
template <class DATA_TYPE>
BOOL LLDoubleLinkedList<DATA_TYPE>::addDataSorted(DATA_TYPE *datap)
{
	// don't allow NULL to be passed to addData()
	if (!datap)
	{
		llerror("NULL pointer passed to LLDoubleLinkedList::addDataSorted()", 0);
	}

	// has mInsertBefore not been set?
	if (!mInsertBefore)
	{
		addData(datap);
		return FALSE;
	}

	// is the list empty?
	if (!mHead.mNextp)
	{
		addData(datap);
		return TRUE;
	}

	// Note: this step has been added so that the behavior of LLDoubleLinkedList
	// is as rigorous as the LLLinkedList class about adding duplicate nodes.
	// Duplicate nodes can cause a problem when sorting if mInsertBefore(foo, foo) 
	// returns TRUE.  However, if mInsertBefore(foo, foo) returns FALSE, then there 
	// shouldn't be any reason to exclude duplicate nodes (as we do here).
	if (checkData(datap))
	{
		return FALSE;
	}
	
	mCurrentp = mHead.mNextp;
	while (mCurrentp)
	{
		// check to see if datap is already in the list
		if (datap == mCurrentp->mDatap)
		{
			return FALSE;
		}
		else if (mInsertBefore(datap, mCurrentp->mDatap))
		{
			insertData(datap);
			return TRUE;
		}
		mCurrentp = mCurrentp->mNextp;
	}
	
	addDataAtEnd(datap);
	return TRUE;
}


// bubble-sort until sorted and return TRUE if anything was sorted
// leaves mQueuep pointing at last node that was swapped with its mNextp
//
// NOTE: if you find this function looping for really long times, then you
// probably need to check your implementation of mInsertBefore(a,b) and make 
// sure it does not return TRUE when (a == b)!
template <class DATA_TYPE>
BOOL LLDoubleLinkedList<DATA_TYPE>::bubbleSort()
{
	BOOL b_swapped = FALSE;
	U32 count = 0;
	while (lazyBubbleSort()) 
	{
		b_swapped = TRUE;
		if (count++ > 0x7FFFFFFF)
		{
			llwarning("LLDoubleLinkedList::bubbleSort() : too many passes...", 1);
			llwarning("    make sure the mInsertBefore(a, b) does not return TRUE for a == b", 1);
			break;
		}
	}
	return b_swapped;
}


// do a single bubble-sort pass and return TRUE if anything was sorted
// leaves mQueuep pointing at last node that was swapped with its mNextp
template <class DATA_TYPE>
BOOL LLDoubleLinkedList<DATA_TYPE>::lazyBubbleSort()
{
	// has mInsertBefore been set?
	if (!mInsertBefore)
	{
		return FALSE;
	}

	// is list empty?
	mCurrentp = mHead.mNextp;
	if (!mCurrentp)
	{
		return FALSE;
	}

	BOOL b_swapped = FALSE;

	// the sort will exit after 0x7FFFFFFF nodes or the end of the list, whichever is first
	S32  length = 0x7FFFFFFF;
	S32  count = 0;

	while (mCurrentp  &&  mCurrentp->mNextp  &&  count<length)
	{
		if (mInsertBefore(mCurrentp->mNextp->mDatap, mCurrentp->mDatap))
		{
			b_swapped = TRUE;
			mQueuep = mCurrentp;
			swapCurrentWithNext();	// sets mCurrentp to mQueuep
		}
		count++;
		mCurrentp = mCurrentp->mNextp;
	}
	
	return b_swapped;
}


template <class DATA_TYPE>
BOOL LLDoubleLinkedList<DATA_TYPE>::pushState()
{
	if (mStateStackDepth < LLDOUBLE_LINKED_LIST_STATE_STACK_DEPTH)
	{
		*(mQueuepStack + mStateStackDepth) = mQueuep;
		*(mCurrentpStack + mStateStackDepth) = mCurrentp;
		mStateStackDepth++;
		return TRUE;
	}
	return FALSE;
}


template <class DATA_TYPE>
BOOL LLDoubleLinkedList<DATA_TYPE>::popState()
{
	if (mStateStackDepth > 0)
	{
		mStateStackDepth--;
		mQueuep = *(mQueuepStack + mStateStackDepth);
		mCurrentp = *(mCurrentpStack + mStateStackDepth);
		return TRUE;
	}
	return FALSE;
}


template <class DATA_TYPE>
void LLDoubleLinkedList<DATA_TYPE>::clearStateStack()
{
	mStateStackDepth = 0;
}

//////////////////////////////////////////////////////////////////////////////////////////
// private members
//////////////////////////////////////////////////////////////////////////////////////////

// add node to beginning of list
// set mCurrentp to mQueuep
template <class DATA_TYPE>
void LLDoubleLinkedList<DATA_TYPE>::addNode(LLDoubleLinkedNode<DATA_TYPE> *nodep)
{
	// add the node to the front of the list
	nodep->mPrevp = NULL;
	nodep->mNextp = mHead.mNextp;
	mHead.mNextp = nodep;

	// if there's something in the list, fix its back pointer
	if (nodep->mNextp)
	{
		nodep->mNextp->mPrevp = nodep;
	}
	else	// otherwise fix the tail node
	{
		mTail.mPrevp = nodep;
	}

	mCurrentp = mQueuep;
}


// add node to end of list
// set mCurrentp to mQueuep
template <class DATA_TYPE>
void LLDoubleLinkedList<DATA_TYPE>::addNodeAtEnd(LLDoubleLinkedNode<DATA_TYPE> *node)
{
	// add the node to the end of the list
	node->mNextp = NULL;
	node->mPrevp = mTail.mPrevp;
	mTail.mPrevp = node;

	// if there's something in the list, fix its back pointer
	if (node->mPrevp)
	{
		node->mPrevp->mNextp = node;
	}
	else	// otherwise fix the head node
	{
		mHead.mNextp = node;
	}

	mCurrentp = mQueuep;
}


// randomly move nodes in the list for DEBUG (or Discordian) purposes
// sets mCurrentp and mQueuep to top of list
template <class DATA_TYPE>
void LLDoubleLinkedList<DATA_TYPE>::scramble()
{
	S32 random_number;
	DATA_TYPE *datap = getFirstData();
	while(datap)
	{
		random_number = ll_rand(5);

		if (0 == random_number)
		{
			removeCurrentData();
			addData(datap);
		}
		else if (1 == random_number)
		{
			removeCurrentData();
			addDataAtEnd(datap);
		}
		else if (2 == random_number)
		{
			swapCurrentWithPrevious();
		}
		else if (3 == random_number)
		{
			swapCurrentWithNext();
		}
		datap = getNextData();
	}
	mQueuep = mHead.mNextp;
	mCurrentp = mQueuep;
}

template <class DATA_TYPE>
BOOL LLDoubleLinkedList<DATA_TYPE>::isEmpty()
{
	return (mCount == 0);
}


#endif
