#ifndef SAFELIST__
#define SAFELIST__
#include <iostream.h>
#include "LinkList.h"

#define autoRegister

template <class data> class SafeList;
template <class data> class SafeContext;
template <class data> class SafeListNode;

//**************************  SafeLIST  **************************
template <class data>
class SafeList:public LinkList<data> 
{	public:
		SafeList(const data& dummy)
		:	LinkList<data>(dummy),
		 	_contexts(NULL)
		{
		}
	
		SafeList(SafeList<data>& L)
		:LinkList<data>(L),
		 _contexts(NULL)
		{
		}
	
		~SafeList()
		{	if(_contexts)delete _contexts;
			_contexts = NULL;
		}
	
		void insertFirst(const data& val, direction d = forward)
		{	LinkListNode<data> *second = ExclOr(_head[1-d], ((SafeListNode<data>*)_head[d])->access());
			LinkListNode<data> *n = newNode(val, _head[d], second);
			_length++;
			((SafeListNode<data>*)_head[d])
				->access(ExclOr(_head[1-d],n));
			((SafeListNode<data>*)second)
				->access(ExclOr(n, ExclOr(_head[d],((SafeListNode<data>*)second)->access())));
			if(d)    //forward
				notifyOthers(NULL, _head[1], second, n); //ALL Notified
			else
				notifyOthers(NULL, second, _head[0], n);
		}
	
	long testLevels(ostream &os, long start = 0)
	{	os << ' '<<_length<<' ';
		if(!_contexts) return start;
		else return _contexts->testLevels(os, start+1);
	}
	
	protected:
		LinkList< SafeContext<data> *> *_contexts;
	
		LinkListNode<data> *newNode(const data& val, LinkListNode<data> *left, LinkListNode<data> *right)
		{	SafeListNode<data> *result = new SafeListNode<data>(val,left,right);
			if(!result)userERROR("Heap exhausted.");
			return result;
		}

/*
		void notifyAll
		(	LinkListNode<data> *N,
			LinkListNode<data> *M = NULL,
			LinkListNode<data> *ptr = NULL
		)
		{	if(_contexts)
			{	Context< SafeContext<data>* > *nextContext
					= new Context< SafeContext<data>* >(*_contexts);
				SafeContext<data> *v;
				while(nextContext->iterate(v))
					v->notify(N,M,ptr);
				delete nextContext;
			}
		}
*/
		void notifyOthers  //Notify all except skip (may be NULL)
		(	SafeContext<data>* skip, LinkListNode<data> *N,
			LinkListNode<data> *M = NULL,
			LinkListNode<data> *ptr = NULL
		)
		{	if(_contexts)
			{	Context< SafeContext<data>* > *nextContext
					= new Context< SafeContext<data>* >(*_contexts);
				SafeContext<data> *v;
				while(nextContext->iterate(v))
					if (v!= skip)
						v->notify(N,M,ptr);
				delete nextContext;
			}
		}
	
		void deregister(SafeContext<data> *C)
		{	if(_contexts)_contexts->removeAll(C);
		}
	
		friend class SafeContext<data>;
};

//**************************  SafeContext  **************************
template <class data>
class SafeContext:public Context<data> 
{	public:
		SafeContext(SafeList<data> & L)
		:	Context<data>(L)
	#ifndef autoRegister
			,
			_registered(FALSE)
	#endif
		{
	#ifdef autoRegister
			if(!L._contexts)
				 L._contexts = new LinkList<SafeContext<data> *>(this);
			L._contexts->insertFirst(this);
	#endif
		}
	
		SafeContext(const SafeContext<data>& C)
		:	Context<data>(C)
	#ifndef autoRegister
			,
			_registered(FALSE)
	#endif
		{
	#ifdef debugLists
	gc++;
	#endif
	
	#ifdef autoRegister
			SafeList<data> &temp = dynamic_cast<SafeList<data>& >(_owner);
			if(!temp._contexts)
				temp._contexts = new LinkList<SafeContext<data> *>(NULL);
			temp._contexts->insertFirst(this);
	#endif
		}
	
		~SafeContext()
		{	((SafeList<data> &)_owner).deregister(this);
	//	#ifdef debugLists
	// gc--;
	// #endif
		}
	
	#ifndef autoRegister
		void doRegister()
		{	if(!((SafeList<data> &)_owner)._contexts)
				((SafeList<data> &)_owner)._contexts
					= new LinkList<SafeContext<data> *>(this);
			((SafeList<data> &)_owner)._contexts->insertFirst(this);
			_registered = TRUE;
		}
	
		Boolean isRegistered(){ return _registered;}
	#endif
	
	void insert(const data& val, direction d = forward)
			// Creates a new location at this position.
			// Leaves the location with the new value to the left.
		{	LinkListNode<data>* oldLeft = _nbr[0];
			LinkListNode<data>* oldRight = _nbr[1];
			Context<data>::insert(val);
			LinkListNode<data>* aNode = _nbr[0];
//			((SafeList<data> &)_owner).notifyAll(oldLeft, oldRight, aNode);
			((SafeList<data> &)_owner).notifyOthers(this,oldLeft, oldRight, aNode);
		}
	
	data removeNext(direction d = forward)
			// Returns the data removed from the list.
			// Returns dummy if nothing can be removed.
		{	data result = _nbr[d]->at();
			if(! atEnd(d))
			{	LinkListNode<data> *temp = _nbr[d];
				((SafeList<data> &)_owner).notifyOthers(this,temp);
				Context<data>::removeNext(d);
			}
			return result;
		}
	
	private:
	
		Boolean _registered;
	
		void notify
		(	LinkListNode<data> *N,
			LinkListNode<data> *M,
			LinkListNode<data> *ptr
		)
		{	if(!M) // Removing N
			{	if(_nbr[0] == N) 
					_nbr[0] = ExclOr(_nbr[1], ((SafeListNode<data>*)N)->access());
				else if (_nbr[1] == N) 
					_nbr[1] = ExclOr(_nbr[0], ((SafeListNode<data>*)N)->access());
			}
			else  // Inserting between N and M
				if(_nbr[0] == N && _nbr[1] == M)
				{	_nbr[0] = ptr;     // NOT Symmetric, always Left.
				}
		}
	
		SafeContext(LinkList<data>& L, Boolean )  // Un_registered context
	   	:	Context<data>(L)
	#ifndef autoRegister
			,_registered(FALSE)
	#endif
		{
	#ifdef debugLists
	gc++;
	#endif
		}
	friend class SafeList<data>;
};

//**************************  SafeListNode  **************************
template <class data>
class SafeListNode:public LinkListNode<data> 
{	protected:
		SafeListNode(const data& val, LinkListNode<data> *left, LinkListNode<data> *right)
		:	LinkListNode<data>(val,left,right)
		{
		}
			
		SafeListNode(const LinkListNode<data> & N)
		:	LinkListNode<data>(N)
		{
		}
			
		~SafeListNode(){}
	
		LinkListNode<data> *access(){return _access;}
		
		void access(LinkListNode<data> * a){_access = a;}
		
	friend class SafeList<data>;
	friend class SafeContext<data>;
};

#endif
