#ifndef __MULTIQUEUE_H_
#define __MULTIQUEUE_H_ 1

#include <stdlib.h>
#include <string.h>

class MultiQueueBase 
{
private:
	int nodeCount;

public:
	MultiQueueBase        ( void )    { nodeCount = 0; }

	virtual void setTail  ( void *tail ) = 0;
	virtual int  getCount ( void )    { return nodeCount; }
	virtual int  setCount ( int cnt ) { return (nodeCount = (cnt>=0?cnt:0)); }
	virtual int  incCount ( void )    { return (++nodeCount); }
	virtual int  decCount ( void )    { return (nodeCount=(nodeCount>0?nodeCount-1:0)); }
};


template <unsigned queueCount> class MultiQueueNode
{
private:
	char *               binary;
	unsigned             binaryLen;
	
public:
	class MultiQueueBase             *queue[queueCount];
	class MultiQueueNode<queueCount> *prev [queueCount];
	class MultiQueueNode<queueCount> *next [queueCount];

	MultiQueueNode(char * Binary=NULL, size_t BinaryLen=0) 
		: binary(Binary), binaryLen(BinaryLen)
		{
		memset(queue, 0, sizeof(class MultiQueueBase *)*queueCount);
		memset(prev,  0, sizeof(class MultiQueueNode<queueCount> *)*queueCount);
		memset(next,  0, sizeof(class MultiQueueNode<queueCount> *)*queueCount);
		}

	virtual ~MultiQueueNode(void)
		{
		binary    = NULL;
		binaryLen = 0;
		clear();
		}

	virtual void set ( char * Binary, size_t BinaryLen )
		{
		binary    = Binary;
		binaryLen = BinaryLen;
		}
		
	virtual void get ( char ** Binary, size_t * BinaryLen )
		{
		*Binary = binary;
		*BinaryLen = binaryLen;
		}
	
	virtual void clear ( void )
		{
		for(int i=0; i<queueCount; i++)
			{
			if(prev[i])       prev [i]->next[i] = next[i];
			if(next[i])       next [i]->prev[i] = prev[i];
			else if(queue[i]) queue[i]->setTail(prev[i]);

			if(queue[i])      queue[i]->decCount();
			
			queue[i]=NULL;
			prev[i] =NULL;
			next[i] =NULL;
			}		
		}
};

	

template <unsigned queueIndex, unsigned queueCount> class MultiQueue 
	: public MultiQueueBase
{
private:
	MultiQueueNode<queueCount>   head;	
	MultiQueueNode<queueCount> * tail;
		
public:
	MultiQueue   ( void ) 
		{ 
		tail      = NULL; 
		}

	virtual ~MultiQueue  ( void ) 
		{ 
		MultiQueueNode<queueCount> * node; 
		while((node=dequeue())!=NULL) delete node; 
		}			
	
	virtual void setTail ( void * Tail )
		{
		tail = (MultiQueueNode<queueCount> *)Tail;
		}
		
	virtual int  empty   ( void ) { return (head.next[queueIndex]==NULL?1:0); }

	virtual void enqueue ( MultiQueueNode<queueCount> * node )
		{
		if(node!=NULL)
			{
			if(head.next[queueIndex]==NULL) 
				{
				head.next[queueIndex]  = node;
				node->prev[queueIndex] = &head;
				}
			else 
				{
				tail->next[queueIndex] = node;
				node->prev[queueIndex] = tail;
				}
			tail = node;
			node->queue[queueIndex] = this;
			node->queue[queueIndex]->incCount();
			}
		}


	virtual MultiQueueNode<queueCount> * peek ( void )
		{
		return head.next[queueIndex];
		}
		
	virtual MultiQueueNode<queueCount> * dequeue ( void )
		{
		MultiQueueNode<queueCount> * node = head.next[queueIndex];
		if(node!=NULL) node->clear();
		return node;
		} 

	virtual int peek ( char ** binary, size_t * binaryLen )
		{
		int result = -1;
		MultiQueueNode<queueCount> * node;
		
		if((node = peek())!=NULL)
			{
			node->get(binary, binaryLen);
			if(*binary!=NULL && *binaryLen!=0) result = 0;
			}
		return result;
		}

	virtual int dequeue ( char ** binary, size_t * binaryLen )
		{
		int result = -1;
		MultiQueueNode<queueCount> * node;

		*binary    = NULL;
		*binaryLen = 0;

		if((node = dequeue())!=NULL)
			{
			node->get(binary, binaryLen);
			if(*binary!=NULL && *binaryLen!=0) result = 0;
			delete node;
			}
		return result;
		}

	virtual MultiQueueNode<queueCount> * localDequeue ( void )
		{
		MultiQueueNode<queueCount> * node = head.next[queueIndex];
		if(node!=NULL)
			{
			if(node->prev[queueIndex]!=NULL) 
				node->prev[queueIndex]->next[queueIndex] = node->next[queueIndex];
			if(node->next[queueIndex]!=NULL)
				node->next[queueIndex]->prev[queueIndex] = node->prev[queueIndex];
			else if(node->queue[queueIndex]!=NULL)
				{
				node->queue[queueIndex]->setTail(node->prev);
				node->queue[queueIndex]->decCount();
				}
			node->queue[queueIndex]=NULL;
			node->next [queueIndex]=NULL;
			node->prev [queueIndex]=NULL;
			}
		return node;
		}
};

#endif	/* __MULTIQUEUE_H_ */

