/*
....[@@@..[@@@..............[@.................. MUD++ is a written from
....[@..[@..[@..[@..[@..[@@@@@....[@......[@.... scratch multi-user swords and
....[@..[@..[@..[@..[@..[@..[@..[@@@@@..[@@@@@.. sorcery game written in C++.
....[@......[@..[@..[@..[@..[@....[@......[@.... This server is an ongoing
....[@......[@..[@@@@@..[@@@@@.................. development project.  All 
................................................ contributions are welcome. 
....Copyright(C).1995.Melvin.Smith.............. Enjoy. 
------------------------------------------------------------------------------
Melvin Smith (aka Fusion)         msmith@falcon.mercer.peachnet.edu 
MUD++ development mailing list    mudpp-list@spice.com
------------------------------------------------------------------------------
llist.h
*/

#ifndef LLIST_H
#define LLIST_H
 

template < class T >
class Node
{
	public:
		Node< T > *next;
		T *obj;

		Node()
		:	next(0), obj(0)
		{
		}

		Node( T * x )
		:	next(0), obj(x)
		{
		}

		~Node()
		{
		}
};

#define RDONLY 1

template < class T >
class LList
{
	private:
		Node< T > *head;
		Node< T > *current;
		unsigned char flags;

	public:
		LList() 
		:	head(0), current(0), flags(0)
		{
		}

		// Does node by node copy. This is so constructed objects
		// that have list data will copy correctly.
		LList( const LList & x );
 
		~LList() { destroyList(); }

		void destroyList();

		// For creating a temp list to iterate with.
		const LList & operator = ( const LList & );

		// true copy, not read-only like assign operator
		void copy( const LList & );

		// Of course these members change the state of the object but
		// for practical purposes they don't and we need const because
		// iterating through a list is common thing to do for a const
		// object. For example writing an object and its inventory to a
		// file doesn't change object but you must iterate through
		// inventory. This would not be required if I implemented LList
		// iterators instead of my method off read-only copying of lists.
		void next() const;
		void reset() const { const_cast< LList * >(this)->current = head; }

		void add( T * );
		void addTop( T * );
		void addAfterCurrent( T * );
		void remove( T * );
		T *remove();
		T *peek() const;
		T *peekNext() const;
};

// Does node by node copy. This is so constructed objects
// that have list data will copy correctly. Note that the
// actual object pointers still point to same address.
template < class T >
LList< T >::LList( const LList & x )
:	head(0), current(0), flags(0)
{
	Node< T > *node = x.head;

	while( node )
	{
		add( node->obj );
		node = node->next;
	}
}
 

// Do read-only copy of a list. Items can't be added or removed
// from this list. It is only for iterating, etc. and is written
// specifically for this with the least overhead.

template < class T >
const LList< T > & LList< T >::operator = ( const LList & x )
{
	if( &x != this )
	{
		destroyList();
		head = x.head;
		current = x.head;
		flags |= RDONLY;
	}

	return *this;
}


template < class T >
void LList< T >::copy( const LList & x )
{
	Node< T > *node = x.head;

	if( &x != this )
	{
		destroyList();
		while( node )
		{
			add( node->obj );
			node = node->next;
		}
	}
}


template < class T >
inline void LList< T >::next() const
{
	if( current )
	{
		const_cast< LList< T > * >(this)->current = current->next;
	}
}


template < class T >
void LList< T >::destroyList()
{
	// Make sure its not a copied list that was used for iterating
	// which is just going out of scope.
	if( !( flags & RDONLY ) )
	{
		if( head )
		{
			if( !current )
				current = head;

			for( ; head; head = current )
			{
				current = current->next;
				delete head; 
			}
		}
	}
	else
	{
		flags &= ~RDONLY;     // clear read only bit
		head = current = 0;
	}
}


template < class T >
void LList< T >::addTop( T * obj )
{
	if( !obj )
		return;
	else if( flags & RDONLY )
		return; // need to bug this later

	Node< T > *add = new Node< T >( obj );

	add->next = head;
	head = add;

	if( ! current )
		current = add;
}


template < class T >
void LList< T >::add( T * obj )
{
	if( !obj )
		return;
	else if( flags & RDONLY )
		return; // need to bug this later

	Node< T > *add = new Node< T >( obj );
	if( !head )
	{ 
		head = current = add; 
		return;
	} 

	add->next = current;

	if( head == current )
	{
		head = add;
		current = add;
		return;
	}

	Node< T > *tlast;

	for( tlast = head; tlast->next; tlast = tlast->next )
	{
		if( tlast->next == current )
		{
			tlast->next = add;
			break;
		}
	}

	if( !tlast->next )
		tlast->next = add;

	current = add;
}


// Add a node after current node, used for sequential building
// of a list mostly.

template < class T >
void LList< T >::addAfterCurrent( T * obj )
{
	if( !obj )
		return;
	else if( flags & RDONLY )
		return; // need to bug this later

	Node< T > *add = new Node< T >( obj );
	if( !head )
	{ 
		head = current = add; 
		return;
	} 
	else if( !current )
		current = head;

	add->next = current->next;
	current->next = add;
}


template < class T >
void LList< T >::remove( T * obj ) 
{
	if( !head )
		return;
	else if( flags & RDONLY )
		return; // need to bug this later

	Node< T > *rem;
	Node< T > *tlast = 0;

	if( head->obj == obj )
	{
		if( current == head )
		 	current = head->next;
		rem = head;
		head = head->next;
		delete rem;
		return;
	}

	for( rem = head; rem; rem = rem->next )
	{
		if( rem->obj == obj )
		{
			if( rem == current )
			{
				current = current->next;
			}

			if( tlast )
				tlast->next = rem->next;

			delete rem;
			return;
		}

		tlast = rem;
	}
}


template < class T >
T *LList< T >::remove() 
{
	if( !head )
		return 0;
	else if( flags & RDONLY )
		return 0; // need to bug this later

	Node< T > *tlast;
	Node< T > *rem = current;

	if( !rem )
		return 0;
	else if( rem == head )
	{
		head = head->next;
		current = current->next;
	}
	else
	{
		for( tlast = head; tlast->next; tlast = tlast->next )
		{
			if( tlast->next == rem )
			{
				tlast->next = rem->next;
				break;
			}
		}
	}

	T *obj = rem->obj;
	delete rem;
	rem = tlast->next;
	return obj;
}


template < class T >
T *LList< T >::peek() const
{
	if( !current )
		return 0;

	return current->obj;
}


template < class T >
T *LList< T >::peekNext() const
{
	if( !current || !current->next )
		return 0;

	return current->next->obj;
}

/* I decided to make LList a container-only class and remove
 * code that deleted actual objects that it held as it could
 * become buggy. (already caused some) - Fusion

template < class T >
void LList< T >::destroy()
{
	if( !current )
		return;

	Node< T > *tlast;
	Node< T > *rem = current;

	for( tlast = head; tlast->next; tlast = tlast->next )
	{
		if( tlast->next == current )
		{
			tlast->next = current->next;
			break;
		}
	}

	delete rem->obj;
	delete rem;
}


template < class T >
void LList< T >::destroy( T * obj )
{
	if( !head )
		return;

	Node< T > *rem;
	Node< T > *tlast = 0;

	if( head->obj == obj )
	{
		if( current == head )
		 	current = head->next;
		rem = head;
		head = head->next;
		delete rem->obj;
		delete rem;
		return;
	}

	for( rem = head; rem; rem = rem->next )
	{
		if( rem->obj == obj )
		{
			if( rem == current )
				current = current->next;

			if( tlast )
				tlast->next = rem->next;

			delete rem->obj;
			delete rem;
			return;
		}

		tlast = rem;
	}
}
*/

#endif