///////////////////////////////////////////////////////////////////////////////
// MQ4CPP - Message queuing for C++
// Copyright (C) 2004-2007  Riccardo Pompeo (Italy)
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//

#define SILENT
#include "Trace.h"
#include "LinkedList.h"

#ifdef WIN32
#define ASSIGN_LONG(dest,val) InterlockedExchange(&dest,val)
#define ASSIGN_PTR(dest,val)  InterlockedExchangePointer((volatile PVOID*)&dest,val)
#define INCREMENT_LONG(dest)  InterlockedIncrement(&dest)
#define DECREMENT_LONG(dest)  InterlockedDecrement(&dest)
#else
#define ASSIGN_LONG(dest,val) dest=val
#define ASSIGN_PTR(dest,val)  dest=val
#define INCREMENT_LONG(dest)  dest++
#define DECREMENT_LONG(dest)  dest--
#endif

LinkedElement::LinkedElement(void* theObject)
			 : itsObject(theObject)

{
	ASSIGN_PTR(itsPreviousElement,this);
	ASSIGN_PTR(itsNextElement,this);
}

LinkedElement::~LinkedElement()
{
}

void* LinkedElement::getObject()
{
	return itsObject;
}

LinkedElement* LinkedElement::getNext()
{
	return itsNextElement;
}

LinkedElement* LinkedElement::getPrevious()
{
	return itsPreviousElement;
}

void LinkedElement::setPrevious(LinkedElement* theElement)
{
	ASSIGN_PTR(itsPreviousElement,theElement);
}

void LinkedElement::setNext(LinkedElement* theElement)
{
	ASSIGN_PTR(itsNextElement,theElement);
}

void LinkedElement::insert(LinkedElement* thePreviousElement,LinkedElement* theNextElement)
{
	ASSIGN_PTR(itsPreviousElement,thePreviousElement);
	ASSIGN_PTR(itsNextElement,theNextElement);
	thePreviousElement->setNext(this);
	theNextElement->setPrevious(this);
}

void LinkedElement::insertBefore(LinkedElement* theElement)
{
	theElement->insert(itsPreviousElement,this);
}

void LinkedElement::insertAfter(LinkedElement* theElement)
{
	theElement->insert(this,itsNextElement);
}

void LinkedElement::append(LinkedElement* theElement)
{
	ASSIGN_PTR(itsNextElement,theElement);
	theElement->setPrevious(this);
}

void LinkedElement::remove()
{
	itsPreviousElement->setNext(itsNextElement);
	itsNextElement->setPrevious(itsPreviousElement);
	ASSIGN_PTR(itsPreviousElement,this);
	ASSIGN_PTR(itsNextElement,this);
}

LinkedList::LinkedList() : LinkedElement(0)
{
	TRACE("LinkedList constructor")
	ASSIGN_LONG(itsElementCount,0);
}

LinkedList::~LinkedList()
{
	TRACE("LinkedList destructor")
}

void LinkedList::push(void* theObject)
{
	TRACE("LinkedList::push - start")
	LinkedElement* anElement=new LinkedElement(theObject);
	if(itsElementCount==0)
	{
		anElement->append(this);
		append(anElement);
		TRACE("Create circular link between LinkedList and LinkedElement")		
	}
	else
	{
		anElement->insert(this,getNext());
		TRACE("LinkedElement inserted in the circular list")	
	}

	INCREMENT_LONG(itsElementCount);
	TRACE("LinkedList::push - end")
}

bool LinkedList::isEmpty()
{
	if(itsElementCount==0)
		return true;
	
	return false;	
}

void* LinkedList::pop()
{
	TRACE("LinkedList::pop - start")
	void* anObject=0;
	
	if(itsElementCount>=1)
	{
		LinkedElement* anElement=getPrevious();
		anObject=anElement->getObject();
		anElement->remove();
		delete anElement;
		DECREMENT_LONG(itsElementCount);
	}

	TRACE("LinkedList::pop - end")
	return anObject;
}

void LinkedList::free()
{
	TRACE("LinkedList::free - start")
	while(itsElementCount>0)
	{
		LinkedElement* anElement=getNext();
		void* anObject=anElement->getObject();
		anElement->remove();		
		delete anElement;
		deleteObject(anObject);
		DECREMENT_LONG(itsElementCount);
	}
	TRACE("LinkedList::free - end")
}

void LinkedList::forEach(bool theFromLastFlag)
{
	TRACE("LinkedList::forEach - start")
	if(itsElementCount==0)
		return;

	LinkedElement* anElement;

	if(theFromLastFlag==true)
		anElement=getNext();
	else
		anElement=getPrevious();
	
	int max=itsElementCount;
	for(int cnt=0;cnt < max; cnt++)
	{
		LinkedElement* aNextElement;
		
		if(theFromLastFlag==true)
			aNextElement=anElement->getNext();
		else
			aNextElement=anElement->getPrevious();

		if(onIteration(anElement)==false)
			break;
			
		anElement=aNextElement;
	}
	TRACE("LinkedList::forEach - end")
}

bool LinkedList::onIteration(LinkedElement* theElement)
{
	return false;	
}

