/*
** lists.h
** Essentially, Amiga Exec lists and nodes
**
**---------------------------------------------------------------------------
** Copyright 1998-2006 Randy Heit
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
**    notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
**    notice, this list of conditions and the following disclaimer in the
**    documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
**    derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/

#ifndef __LISTS_H__
#define __LISTS_H__

struct Node
{
	Node *Succ, *Pred;

	void Insert (Node *putAfter)
	{
		Succ = putAfter->Succ;
		Pred = putAfter;
		putAfter->Succ = this;
		Succ->Pred = this;
	}

	void InsertBefore (Node *putBefore)
	{
		Succ = putBefore;
		Pred = putBefore->Pred;
		putBefore->Pred = this;
		Pred->Succ = this;
	}

	void Remove ()
	{
		Pred->Succ = Succ;
		Succ->Pred = Pred;
	}
};

struct List
{
	Node *Head;
	const Node *const Tail;
	Node *TailPred;

	List () : Head ((Node *)&Tail), Tail (NULL), TailPred ((Node *)&Head)
	{
	}

	bool IsEmpty () const
	{
		return TailPred == (Node *)this;
	}

	void MakeEmpty ()
	{
		Head = (Node *)&Tail;
		TailPred = (Node *)&Head;
	}

	void AddHead (Node *node)
	{
		node->Succ = Head;
		node->Pred = (Node *)&Head;
		Head->Pred = node;
		Head = node;
	}

	void AddTail (Node *node)
	{
		node->Pred = TailPred;
		node->Succ = (Node *)&Tail;
		TailPred->Succ = node;
		TailPred = node;
	}
	
	Node *RemHead ()
	{
		Node *node = Head;
		if (node->Succ == NULL)
		{
			return NULL;
		}
		Head = node->Succ;
		Head->Pred = (Node *)&Head;
		return node;
	}

	Node *RemHeadQ ()	// Only use if list is definitely not empty
	{
		Node *node = Head;
		Head = node->Succ;
		Head->Pred = (Node *)&Head;
		return node;
	}

	Node *RemTail ()
	{
		Node *node = TailPred;
		if (node->Pred == NULL)
		{
			return NULL;
		}
		TailPred = node->Pred;
		TailPred->Succ = (Node *)&Tail;
		return node;
	}

	Node *RemTailQ ()	// Only use if list is definitely not empty
	{
		Node *node = TailPred;
		TailPred = node->Pred;
		TailPred->Succ = (Node *)&Tail;
		return node;
	}

private:
	List &operator= (const List&) { return *this; }
};

#endif //__LISTS_H__