/*-----------------------------------------------------------------------------
 * Copyright (c) 1991,1992 Southeastern Universities Research Association,
 *                         Continuous Electron Beam Accelerator Facility
 *
 * This software was developed under a United States Government license
 * described in the NOTICE file included as part of this distribution.
 *
 *-----------------------------------------------------------------------------
 *
 * Description:
 *
 * Author:  Walt Akers
 *
 * Revision History:
 *   fifo.h,v
 * Revision 1.4  1997/12/22  15:15:45  akers
 * Ongoing development with new cdevReactor
 *
 * Revision 1.3  1996/09/13  18:47:18  akers
 * Installed free list for node objects
 *
 * Revision 1.2  1996/07/16  15:48:55  akers
 * Ongoing Modifications
 *
 *-----------------------------------------------------------------------------
 */

#ifndef __FIFO_H_
#define __FIFO_H_ 1

#include <cdevPlatforms.h>

class GENERIC_SERVER_API QueueBase
{
public:
	class node
	{
	friend class QueueBase;
	private:
		node  ( void ) : binary(NULL), binaryLen(0), next(NULL) { }
		~node ( void ) { }
	public:
		void       * binary;
		size_t       binaryLen;
		class node * next;
	};

protected:
	node * head;
	node * tail;

private:
	enum { NEWCNT = 32 };
	static node * freeList_;

public:
	QueueBase ( void ) 
		: head(NULL), tail(NULL) 
		{
		}
		
	virtual ~QueueBase ( void ) 
		{
		}	

	static node * newNode ( void )
		{
		node * result;
		if(freeList_==NULL)
			{
			freeList_ = new node[NEWCNT];
			for(int i=0; i<NEWCNT; i++)
				{
				freeList_[i].binary     = NULL;
				freeList_[i].binaryLen  = 0;
				freeList_[i].next       = (i<(NEWCNT-1))?&freeList_[i+1]:(node *)NULL;
				}
			}
		result    = &freeList_[0];
		freeList_ = result->next;
		result->binary    = NULL;
		result->binaryLen = 0;
		result->next      = NULL;
		return result;
		}

	static void deleteNode ( node * ptr)
		{
		if(ptr->next!=NULL) deleteNode(ptr->next);
		ptr->next  = freeList_;
		freeList_  = ptr;
		}	
};

class GENERIC_SERVER_API FifoQueue : public QueueBase
	{
	private:
		int nodeCnt;
		
	public:
		FifoQueue  ( void ) : QueueBase(), nodeCnt(0) {}

		virtual ~FifoQueue ( void )
			{
			while(dequeue()!=NULL);
			}
							
		int empty ( void )
			{
			return head==NULL?1:0;
			}

		void enqueue ( void * ptr )
			{
			if(ptr != NULL)
				{
				if(tail==NULL) tail = newNode();
				else 
					{
					tail->next = newNode();
					tail = tail->next;
					}
				tail->binary    = ptr;
				if(head==NULL) head = tail;
				nodeCnt++;
				}
			}

		void enqueue ( char * ptr, size_t len )
			{
			if(ptr != NULL && len > 0 )
				{
				if(tail==NULL) tail = newNode();
				else 	{
					tail->next = newNode();
					tail = tail->next;
					}
				tail->binary    = ptr;
				tail->binaryLen = len;
				if(head==NULL) head = tail;
				nodeCnt++;
				}
			}

		void * dequeue ( void )
			{
			void * result = NULL;
			if(head!=NULL)
				{
				node * next = head->next;
				result      = head->binary;
				head->next  = NULL;
				deleteNode(head);
				head        = next;
				if(head==NULL) tail = NULL;
				nodeCnt--;
				}
			return result;
			}
	
	
		int dequeue ( char ** ptr, size_t * len )
			{
			int result = -1;
			*ptr = NULL;
			*len = 0;
			if(head!=NULL)
				{
				node * next = head->next;
				result      = 0;
				*ptr        = (char *)head->binary;
				*len        = head->binaryLen;
				head->next  = NULL;
				deleteNode(head);
				head        = next;
				if(head==NULL) tail = NULL;
				nodeCnt--;
				}
			return result;
			}

		int peek ( char ** ptr, size_t *len )
			{
			int result = -1;
			if(head!=NULL)
				{
				*ptr = (char *)head->binary;
				*len = head->binaryLen;
				result = 0;
				}
			return  result;
			}
			
		void undequeue ( void * ptr )
			{
			if(ptr != NULL)
				{
				if(tail==NULL) enqueue(ptr);
				else	{
					node * headnode = newNode();
					headnode->binary = ptr;
					headnode->next  = head;
					head            = headnode;				
					nodeCnt++;
					}
				}
			}

		void undequeue ( char *ptr, size_t len)
			{
			if(ptr != NULL && len > 0)
				{
				if(tail==NULL) enqueue(ptr, len);
				else	{
					node * headnode     = newNode();
					headnode->binary    = ptr;
					headnode->binaryLen = len;
					headnode->next      = head;
					head                = headnode;
					nodeCnt++;
					}
				}
			}
		
		int getCount ( void ) { return nodeCnt; }
		};
	
	
class GENERIC_SERVER_API ListQueue : public QueueBase	
	{
	protected:
		node * prev;
		node * bookmark;
		
	public:
		ListQueue ( void ) : QueueBase () 
			{
			prev     = NULL;
			bookmark = NULL;
			}
		virtual ~ListQueue ( void )
			{
			while(first()==0) remove();
			}
		int first  ( void ) 
			{ 
			prev     = NULL;
			bookmark = head;
			return (bookmark==NULL?-1:0);
			}		 	
		int next   ( void ) 
			{
			if(bookmark!=NULL) 
				{
				prev = bookmark;
				bookmark = bookmark->next;
				}
			return (bookmark==NULL?-1:0);
			}
		void * dequeue    ( void )
			{
			return (bookmark==NULL?NULL:bookmark->binary);
			}
		void enqueue ( void * ptr )
			{
			if(ptr != NULL)
				{
				prev = tail;
				if(tail==NULL) tail = newNode();
				else 
					{
					tail->next = newNode();
					tail = tail->next;
					}
				tail->binary = ptr;
				bookmark    = tail; 
				if(head==NULL) head = tail;
				}
			}
		int remove ( void )
			{
			int retval = -1;
			if(bookmark != NULL)
				{
				if(prev!=NULL) prev->next = bookmark->next;
				else           head       = bookmark->next;

				bookmark->next = NULL;
				deleteNode(bookmark);

				if(prev!=NULL) {
					bookmark = prev->next;
					}
				else if(head!=NULL && head->next!=NULL) {
					bookmark = head->next;
					}
				else bookmark = head;

				for(	tail=head; 
					tail!=NULL && tail->next!=NULL; 
					tail=tail->next);
				retval = 0;
				}
			else if(head!=NULL) first();
			else tail = NULL;
			return retval;
			}
	};

#ifdef _FIFO_QUEUE_MASTER_
	QueueBase::node * QueueBase::freeList_ = NULL;
#endif

#endif	// __FIFO_H_

