/*
 * Generic linked-list implementation
 */

#ifndef LIST_H
#define LIST_H

#include <stdlib.h>

template<class Cls>
class ListElem;

template<class Cls>
class List
{
protected:
	ListElem<Cls> *first, *last;
	friend class ListElem<Cls>;

public:
	List (void) { first = last = NULL; }
	inline ~List (void); 
	inline ListElem<Cls> *Append (Cls *c);
	ListElem<Cls> *Append (Cls c) { return Append (&c); }
	inline ListElem<Cls> *Prepend (Cls *c);
	ListElem<Cls> *Prepend (Cls c) { return Prepend (&c); }
	inline void RemoveFirst (Cls *c);
	void RemoveFirst (Cls c) { RemoveFirst (&c); }
	inline void RemoveAll (Cls *c);
	void RemoveAll (Cls c) { RemoveFirst (&c); }
	inline ListElem<Cls> *findFirst (Cls *c);
	
	ListElem<Cls> *getFirst (void) { return first; }
};

template<class Cls>
class ListElem
{
protected:
	friend class List<Cls>;
	
	List<Cls> *parent;
	ListElem<Cls> *next, *prev;
	Cls data;

public:
	ListElem<Cls> (Cls *c) { data = *c; next = prev = NULL; parent = NULL; }
	inline ~ListElem<Cls> (void);
	inline void Create (List<Cls> *p);
	inline void AddAfter (ListElem<Cls> *e);
	inline void AddBefore (ListElem<Cls> *e);
	inline void Remove (void);
	inline ListElem<Cls> *findNext (Cls *c);
	
	ListElem<Cls> *getNext (void) { return next; }
	Cls *v (void) { return &data; }
	Cls operator* () const { return data; }
};

template<class Cls>
inline List<Cls>::~List (void)
{
	while (first)
		delete first;
}

template<class Cls>
inline ListElem<Cls> *List<Cls>::Append (Cls *c)
{
	ListElem<Cls> *e;
	
	e = new ListElem<Cls> (c);
	if (last)
		last->AddAfter (e);
	else
		e->Create (this);
	return e;
}

template<class Cls>
inline ListElem<Cls> *List<Cls>::Prepend (Cls *c)
{
	ListElem<Cls> *e;
	
	e = new ListElem<Cls> (c);
	if (first)
		first->AddBefore (e);
	else
		e->Create (this);
	return e;
}

template<class Cls>
inline void List<Cls>::RemoveFirst (Cls *c)
{
	ListElem<Cls> *e;
	
	e = findFirst (c);
	if (e)
		e->Remove ();
}

template<class Cls>
inline void List<Cls>::RemoveAll (Cls *c)
{
	ListElem<Cls> *e, *f;
	
	e = findFirst (c);
	do
	{
		f = e->next;
		e->Remove ();
		if (f)
			e = f->findNext (c);
	} while (e && f);
}

template<class Cls>
inline ListElem<Cls> *List<Cls>::findFirst (Cls *c)
{
	if (first)
		return first->findNext (c);
	return NULL;
}

template<class Cls>
inline ListElem<Cls>::~ListElem (void)
{
	Remove ();
}

template<class Cls>
inline void ListElem<Cls>::Create (List<Cls> *p)
{
	parent = p;
	next = prev = NULL;
	p->first = p->last = this;
}

template<class Cls>
inline void ListElem<Cls>::AddAfter (ListElem<Cls> *e)
{
	e->next = next;
	e->prev = this;
	e->parent = parent;
	if (next)
		next->prev = e;
	next = e;
	if (parent->last == this)
		parent->last = e;
}

template<class Cls>
inline void ListElem<Cls>::AddBefore (ListElem<Cls> *e)
{
	e->prev = prev;
	e->next = this;
	e->parent = parent;
	if (prev)
		prev->next = e;
	prev = e;
	if (parent->first == this)
		parent->first = e;
}

template<class Cls>
inline void ListElem<Cls>::Remove (void)
{
	if (prev)
		prev->next = next;
	if (next)
		next->prev = prev;
	if (parent->first == this)
		parent->first = next;
	if (parent->last == this)
		parent->last = prev;
}

template<class Cls>
inline ListElem<Cls> *ListElem<Cls>::findNext (Cls *c)
{
	ListElem<Cls> *e;
	
	for (e = this; e != NULL; e = e->next)
		if (e->data == *c)
			return e;
	return NULL;
}

#endif /* LIST_H */

/* End of file. */
