//-----------------------------------------------------------------------------
// Copyright (c) 1994,1995 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:
//	 Single Linked List for rsvcHashable* pointer
//
//       Note: remove and clean operations on the list
//             will only remove link nodes without removal of
//             the content inside the nodes. It is callers' 
//             responsiblity to clean up those contents
//
// Author:  Jie Chen
//       CEBAF Data Acquisition Group
//
// Revision History:
//   rsvcHSlist.cc,v
// Revision 1.1  1998/01/22  17:08:12  akers
// Addition of new NameServer
//
//
//
#include <rsvcHashable.h>
#include "rsvcHSlist.h"
 
//======================================================================
//	class rsvcHSlist implementation
//======================================================================
rsvcHSlist::rsvcHSlist (void)
#if defined (RSVC_USE_THREAD) && defined (_REENTRANT)
:ptrToFirstLink(0), count_ (0), lock_ ()
#else
:ptrToFirstLink(0), count_ (0)
#endif
{
#ifdef _TRACE_OBJECTS
  printf ("Create rsvcHSlist Class Object\n");
#endif
  // no further initialization
}

rsvcHSlist::rsvcHSlist (const rsvcHSlist & source)
:count_ (source.count_)
{
#ifdef _TRACE_OBJECTS
  printf ("Create rsvcHSlist Class Object\n");
#endif

  // duplicate elements from source list
  if (source.isEmpty_i())
    ptrToFirstLink = 0;
  else{
    rsvcHSlistLink * firstLink = source.ptrToFirstLink;
    ptrToFirstLink = firstLink->duplicate();
  }
}

rsvcHSlist::~rsvcHSlist (void)
{
  // empty all elements from the list
#ifdef _TRACE_OBJECTS
  printf ("Delete rsvcHSlist Class Object\n");
#endif
  deleteAllValues();
}

void
rsvcHSlist::add (rsvcHashable* val)
{
#if defined (RSVC_USE_THREAD) && defined (_REENTRANT)
  cpMutexGuard guard (lock_);
#endif

  // add a new value to the front of a linked list
  ptrToFirstLink = new rsvcHSlistLink(val, ptrToFirstLink);
  count_ ++;
  assert(ptrToFirstLink != 0);
}

void
rsvcHSlist::addToEnd (rsvcHashable* val)
{
#if defined (RSVC_USE_THREAD) && defined (_REENTRANT)
  cpMutexGuard guard (lock_);
#endif

  count_ ++;
  if (ptrToFirstLink == 0) {
    ptrToFirstLink = new rsvcHSlistLink(val, ptrToFirstLink); 
    return;
  }

  // loop through until last element
  rsvcHSlistLink *p = 0;
  for (p = ptrToFirstLink; p->ptrToNextLink; p = p->ptrToNextLink)
    ;

  rsvcHSlistLink* q = new rsvcHSlistLink (val, 0);
  p->ptrToNextLink = q;
}

void
rsvcHSlist::add_i (rsvcHashable* val)
{
  // add a new value to the front of a linked list
  count_ ++;
  ptrToFirstLink = new rsvcHSlistLink(val, ptrToFirstLink);
  assert(ptrToFirstLink != 0);
}

int
rsvcHSlist::remove (rsvcHashable* val)
{
#if defined (RSVC_USE_THREAD) && defined (_REENTRANT)
  cpMutexGuard guard (lock_);
#endif

  // remove an element from the list
  // loop to test each element
  rsvcHSlistLink *q = ptrToFirstLink;
  for (rsvcHSlistLink * p = ptrToFirstLink; p; p = p->ptrToNextLink){
    if (val == p->value){
      if (q == p){
	// remove first element
	ptrToFirstLink = p->ptrToNextLink;
	delete p;
      }
      else{
        q->ptrToNextLink = p->ptrToNextLink;
	delete p;
      }
      count_ --;
      return 1;
    }
    q = p;
  }
  // not found
  return 0; 
}

void
rsvcHSlist::deleteAllValues (void)
{
#if defined (RSVC_USE_THREAD) && defined (_REENTRANT)
  cpMutexGuard guard (lock_);
#endif

  // clear all items from the list
  rsvcHSlistLink * next;

  for (rsvcHSlistLink * p = ptrToFirstLink; p != 0; p = next){
    // delete the element pointed to by p
    next = p->ptrToNextLink;
    p->ptrToNextLink = 0;
    delete p;
  }
  
  // set count to zero
  count_ = 0;
  // mark that the list contains no elements
  ptrToFirstLink = 0;
}

void
rsvcHSlist::deleteAllValues_i (void)
{
  // clear all items from the list
  rsvcHSlistLink * next;

  for (rsvcHSlistLink * p = ptrToFirstLink; p != 0; p = next){
    // delete the element pointed to by p
    next = p->ptrToNextLink;
    p->ptrToNextLink = 0;
    delete p;
  }
  
  // set count to zero
  count_ = 0;

  // mark that the list contains no elements
  ptrToFirstLink = 0;
}

int
rsvcHSlist::count (void)
{
#if defined (RSVC_USE_THREAD) && defined (_REENTRANT)
  cpMutexGuard guard (lock_);
#endif

  return count_;
}

rsvcHSlist*
rsvcHSlist::duplicate (void)
{
#if defined (RSVC_USE_THREAD) && defined (_REENTRANT)
  cpMutexGuard guard (lock_);
#endif

  rsvcHSlist * newlist = new rsvcHSlist;
  assert(newlist != 0);

  // copy list
  if (ptrToFirstLink)
    newlist->ptrToFirstLink = ptrToFirstLink->duplicate();

  // set new list count
  newlist->count_ = count_;
  // return the new list
  return newlist;
}

rsvcHashable*
rsvcHSlist::firstElement (void)
{
#if defined (RSVC_USE_THREAD) && defined (_REENTRANT)
  cpMutexGuard guard (lock_);
#endif

  // return first value in list
  assert(ptrToFirstLink != 0);
  return ptrToFirstLink->value;
}

rsvcHashable*
rsvcHSlist::firstElement_i (void)
{
  // return first value in list
  assert(ptrToFirstLink != 0);
  return ptrToFirstLink->value;
}

rsvcHashable*
rsvcHSlist::lastElement (void)
{
#if defined (RSVC_USE_THREAD) && defined (_REENTRANT)
  cpMutexGuard guard (lock_);
#endif

  assert(ptrToFirstLink != 0);
  // loop through until last element
  rsvcHSlistLink *p = 0;
  for (p = ptrToFirstLink; p->ptrToNextLink; p = p->ptrToNextLink)
    ;
  return p->value;
}

rsvcHashable*
rsvcHSlist::lastElement_i (void)
{
  assert(ptrToFirstLink != 0);
  // loop through until last element
  rsvcHSlistLink *p = 0;
  for (p = ptrToFirstLink; p->ptrToNextLink; p = p->ptrToNextLink)
    ;
  return p->value;
}

int
rsvcHSlist::includes(rsvcHashable* v)
{
#if defined (RSVC_USE_THREAD) && defined (_REENTRANT)
  cpMutexGuard guard (lock_);
#endif

  // loop to test each element
  for (rsvcHSlistLink * p = ptrToFirstLink; p; p = p->ptrToNextLink)
    if (v == p->value)
      return 1;
  
  // not found
  return 0;
}

int
rsvcHSlist::isEmpty (void)
{
#if defined (RSVC_USE_THREAD) && defined (_REENTRANT)
  cpMutexGuard guard (lock_);
#endif

  // test to see if the list is empty
  // list is empty if the pointer to the first link is null
  return ptrToFirstLink == 0;
}

int
rsvcHSlist::isEmpty_i (void) const
{
  // test to see if the list is empty
  // list is empty if the pointer to the first link is null
  return ptrToFirstLink == 0;
}

void
rsvcHSlist::removeFirst (void)
{
#if defined (RSVC_USE_THREAD) && defined (_REENTRANT)
  cpMutexGuard guard (lock_);
#endif

  // make sure there is a first element
  assert(ptrToFirstLink != 0);
  
  // save pointer to the removed node
  rsvcHSlistLink * p = ptrToFirstLink;

  // reassign the ptrToFirstLink node
  ptrToFirstLink = p->ptrToNextLink;

  // decrease the count
  count_ --;
  // recover memory used by the first element
  delete p;
}

void
rsvcHSlist::removeFirst_i (void)
{
  // make sure there is a first element
  assert(ptrToFirstLink != 0);
  
  // save pointer to the removed node
  rsvcHSlistLink * p = ptrToFirstLink;

  // reassign the ptrToFirstLink node
  ptrToFirstLink = p->ptrToNextLink;

  // decrease the count
  count_ --;

  // recover memory used by the first element
  delete p;
}

//======================================================================
//	class slink implementation
//           No need to add any mutex protection since all member
//           functions are called with lock held
//======================================================================
rsvcHSlistLink* 
rsvcHSlistLink::insert(rsvcHashable* val)
{
  // insert a new link after current node
  ptrToNextLink = new rsvcHSlistLink(val, ptrToNextLink);

  // check that allocation was successful
  assert(ptrToNextLink != 0);
  return ptrToNextLink;
}

rsvcHSlistLink::rsvcHSlistLink (rsvcHashable* val, rsvcHSlistLink * nxt)
:value(val), ptrToNextLink(nxt)
{
  // create and initialize a new link field
}

rsvcHSlistLink* 
rsvcHSlistLink::duplicate (void)
{
  rsvcHSlistLink * newlink;

  // if there is a next field. copy remainder of list
  if (ptrToNextLink != 0)
    newlink = new rsvcHSlistLink(value, ptrToNextLink->duplicate());
  else
    newlink = new rsvcHSlistLink (value, 0);

  // check that allocation was successful
  assert(newlink != 0);
  return newlink;
}

rsvcHSlistLink*
rsvcHSlistLink::next (void)
{
  return ptrToNextLink;
}

rsvcHashable*
rsvcHSlistLink::data (void)
{
  return value;
}

//======================================================================
//	class listIterator implementation
//======================================================================
rsvcHSlistIterator::rsvcHSlistIterator(rsvcHSlist & aList)
#if defined (RSVC_USE_THREAD) && defined (_REENTRANT)
:theList(aList), lock_ ()
#else
:theList(aList)
#endif
{
  // create and initialize a new list
  init_i();
}

int
rsvcHSlistIterator::init_i()
{
  // set the iterator to the first element in the list
  previousLink = 0;
  currentLink = theList.ptrToFirstLink;
  return currentLink != 0;
}

int
rsvcHSlistIterator::init()
{
#if defined (RSVC_USE_THREAD) && defined (_REENTRANT)
  cpMutexGuard guard (lock_);
#endif

  // set the iterator to the first element in the list
  previousLink = 0;
  currentLink = theList.ptrToFirstLink;
  return currentLink != 0;
}

rsvcHashable*
rsvcHSlistIterator::operator () (void)
{
#if defined (RSVC_USE_THREAD) && defined (_REENTRANT)
  cpMutexGuard guard (lock_);
#endif
  // return value of current element
  // check to see if there is a current element
  assert(currentLink != 0);

  // return value associated with current element
  return currentLink->value;
}

int rsvcHSlistIterator::operator ! (void)
{
#if defined (RSVC_USE_THREAD) && defined (_REENTRANT)
  cpMutexGuard guard (lock_);
#endif
  // test for termination of the iterator
  // if current link references a removed value,
  // update current to point to next position
  if (currentLink == 0)
    if (previousLink != 0)
      currentLink = previousLink->ptrToNextLink;

  // now see if currentLink is valid
  return currentLink != 0;
}

int rsvcHSlistIterator::forward_i (void)
{
  // move current pointer to nect element
  // special processing if current link is deleted
  if (currentLink == 0){
    if (previousLink == 0)
      currentLink = theList.ptrToFirstLink;
    else
      currentLink = previousLink->ptrToNextLink;
  }
  else{
    // advance pointer
    previousLink = currentLink;
    currentLink = currentLink->ptrToNextLink;
  }

  // return true if we have a valid current element
  return currentLink != 0;
}


int rsvcHSlistIterator::operator ++()
{
#if defined (RSVC_USE_THREAD) && defined (_REENTRANT)
  cpMutexGuard guard (lock_);
#endif

  // move current pointer to nect element
  // special processing if current link is deleted
  if (currentLink == 0){
    if (previousLink == 0)
      currentLink = theList.ptrToFirstLink;
    else
      currentLink = previousLink->ptrToNextLink;
  }
  else{
    // advance pointer
    previousLink = currentLink;
    currentLink = currentLink->ptrToNextLink;
  }

  // return true if we have a valid current element
  return currentLink != 0;
}

void rsvcHSlistIterator::operator = (rsvcHashable* val)
{
#if defined (RSVC_USE_THREAD) && defined (_REENTRANT)
  cpMutexGuard guard (lock_);
#endif

  // modify value of current element
  assert(currentLink != 0);

  // modify value of the current link
  currentLink->value = val;
}

void rsvcHSlistIterator::removeCurrent_i (void)
{
  // remove the current element from a list
  // make sure there is a current element
  assert(currentLink != 0);

  // case 1, removing first element
  if (previousLink == 0)
    theList.ptrToFirstLink = currentLink->ptrToNextLink;
  
  // case 2, not removing the first element
  else
    previousLink->ptrToNextLink = currentLink->ptrToNextLink;
  
  // delete current node
  delete currentLink;

  // and set current pointer to null
  currentLink = 0;

  // decrease list count element
  theList.count_ --;
}

void rsvcHSlistIterator::removeCurrent (void)
{
#if defined (RSVC_USE_THREAD) && defined (_REENTRANT)
  cpMutexGuard guard(lock_);
#endif

  // remove the current element from a list
  // make sure there is a current element
  assert(currentLink != 0);

  // case 1, removing first element
  if (previousLink == 0)
    theList.ptrToFirstLink = currentLink->ptrToNextLink;
  
  // case 2, not removing the first element
  else
    previousLink->ptrToNextLink = currentLink->ptrToNextLink;
  
  // delete current node
  delete currentLink;

  // and set current pointer to null
  currentLink = 0;

  // decrease list count element
  theList.count_ --;
}

void rsvcHSlistIterator::addBefore(rsvcHashable* val)
{
#if defined (RSVC_USE_THREAD) && defined (_REENTRANT)
  cpMutexGuard guard (lock_);
#endif

  // add a new element to list before current value
  // case 1, not at start
  if (previousLink)
    previousLink = previousLink->insert(val);

  // case 2, at start of list
  else{
    theList.rsvcHSlist::add(val);
    previousLink = theList.ptrToFirstLink;
    currentLink = previousLink->ptrToNextLink;
  }

  // increase the count
  theList.count_ ++;
}

void rsvcHSlistIterator::addAfter(rsvcHashable* val)
{
#if defined (RSVC_USE_THREAD) && defined (_REENTRANT)
  cpMutexGuard guard(lock_);
#endif

  // a a new element to list after current value
  // case 1, not at start
  if (currentLink != 0)
    currentLink->insert(val);

  // case 2, at end of list
  else if (previousLink != 0)
    currentLink = previousLink->insert(val);
  
  // case 3, start of list
  else
    theList.rsvcHSlist::add(val);

  // increase the count
  theList.count_ ++;
}

int rsvcHSlistIterator::searchSame(rsvcHashable* &val)
{
#if defined (RSVC_USE_THREAD) && defined (_REENTRANT)
  cpMutexGuard guard(lock_);
#endif

  // search the list to find out whether we have this element
  // if we do, move cursor to this element return 1
  // if we don't return 0
  init_i();

  if (currentLink == 0){
  // empty link 
    return 0;
  }
  while (currentLink != 0){
    // advance pointer
    if (currentLink->value == val)
      break;
    previousLink = currentLink;
    currentLink = currentLink->ptrToNextLink;
  }

  // return true if we have a valid current element
  return currentLink != 0;
}

//========================================================================
//          Implementation of rsvcHSlistCursor
//                 Implements of cursor without changing list
//========================================================================
rsvcHSlistCursor::rsvcHSlistCursor(const rsvcHSlist & aList)
#if defined (RSVC_USE_THREAD) && defined (_REENTRANT)
:theList(aList), lock_ ()
#else
:theList(aList)
#endif
{
  // create and initialize a new list
  init_i();
}

int
rsvcHSlistCursor::init_i()
{
  // set the iterator to the first element in the list
  previousLink = 0;
  currentLink = theList.ptrToFirstLink;
  return currentLink != 0;
}

int
rsvcHSlistCursor::init()
{
#if defined (RSVC_USE_THREAD) && defined (_REENTRANT)
  cpMutexGuard guard(lock_);
#endif

  // set the iterator to the first element in the list
  previousLink = 0;
  currentLink = theList.ptrToFirstLink;
  return currentLink != 0;
}

rsvcHashable*
rsvcHSlistCursor::operator () (void)
{
#if defined (RSVC_USE_THREAD) && defined (_REENTRANT)
  cpMutexGuard guard(lock_);
#endif

  // return value of current element
  // check to see if there is a current element
  assert(currentLink != 0);

  // return value associated with current element
  return currentLink->value;
}

int rsvcHSlistCursor::operator ! (void)
{
#if defined (RSVC_USE_THREAD) && defined (_REENTRANT)
  cpMutexGuard guard(lock_);
#endif

  // test for termination of the iterator
  // if current link references a removed value,
  // update current to point to next position
  if (currentLink == 0)
    if (previousLink != 0)
      currentLink = previousLink->ptrToNextLink;
  
  // now see if currentLink is valid
  return currentLink != 0;
}

int rsvcHSlistCursor::operator ++ (void)
{
#if defined (RSVC_USE_THREAD) && defined (_REENTRANT)
  cpMutexGuard guard(lock_);
#endif

  // move current pointer to nect element
  // special processing if current link is deleted
  if (currentLink == 0){
    if (previousLink == 0)
      currentLink = theList.ptrToFirstLink;
    else
      currentLink = previousLink->ptrToNextLink;
  }
  else{
    // advance pointer
    previousLink = currentLink;
    currentLink = currentLink->ptrToNextLink;
  }

  // return true if we have a valid current element
  return currentLink != 0;
}

int rsvcHSlistCursor::searchSame (rsvcHashable* &val)
{
#if defined (RSVC_USE_THREAD) && defined (_REENTRANT)
  cpMutexGuard guard(lock_);
#endif
  // search the list to find out whether we have this element
  // if we do, move cursor to this element return 1
  // if we don't return 0
  init_i();

  if (currentLink == 0){
    // empty link 
    return 0;
  }
  while (currentLink != 0){
    // advance pointer
    if (currentLink->value == val)
      break;
    previousLink = currentLink;
    currentLink = currentLink->ptrToNextLink;
  }

  // return true if we have a valid current element
  return currentLink != 0;
}

void rsvcHSlistCursor::operator = (rsvcHashable* )
{
  // empty
}
