/*-------------------------------------------------------------------*/
/*                         List  Functionality                       */
/*-------------------------------------------------------------------*/
/* #define SH_LIST_DEBUG */
/*-------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include "shlist.h"
/*-------------------------------------------------------------------*/
void shListInitList( SHLIST *listPtr )
{
  listPtr->data = (void *)0L;
  listPtr->next = listPtr;
  listPtr->prev = listPtr;
}

SHLIST *shListFindItem( SHLIST *head, void *val, shListEqual func )
{
  SHLIST *item;

  for(item=head->next;( item != head );item=item->next)
    if( func ) {
      if( func( val, item->data ) ) {
        return( item );
      }
    }
    else {
      if( item->data == val ) {
        return( item );
      }
    }
  return( NULL );
}

SHLIST *shListGetLastItem( SHLIST *head )
{
  if( head->prev != head )
    return( head->prev );
  return( NULL );
}

SHLIST *shListGetFirstItem( SHLIST *head )
{
  if( head->next != head )
    return( head->next );
  return( NULL );
}

SHLIST *shListGetNItem( SHLIST *head, unsigned long num )
{
  SHLIST *item;
  unsigned long i;

  for(i=0,item=head->next;( (i < num) && (item != head) );i++,item=item->next);
  if( item != head )
    return( item );
  return( NULL );
}

SHLIST *shListGetNextItem( SHLIST *head, SHLIST *item )
{
  if( item == NULL )
    return( NULL );
  if( item->next != head )
    return( item->next );
  return( NULL );
}

SHLIST *shListGetPrevItem( SHLIST *head, SHLIST *item )
{
  if( item == NULL )
    return( NULL );
  if( item->prev != head )
    return( item->prev );
  return( NULL );
}

void shListDelItem( SHLIST *head, SHLIST *item, shListFree func )
{
  if( item == NULL )
    return;
#ifdef SH_LIST_DEBUG
  fprintf(stderr, "Del %lx\n", (unsigned long)(item->data));
#endif
  (item->prev)->next = item->next;
  (item->next)->prev = item->prev;
  if( func && item->data ) {
    func( (void *)(item->data) );
  }
  free( item );
  head->data = (void *)((unsigned long)(head->data) - 1);
}

void shListInsFirstItem( SHLIST *head, void *val )
{ /* Insert to the beginning of the list */
  SHLIST *item;

  item = (SHLIST *)malloc( sizeof(SHLIST) );
  if( item == NULL )
    return;
  item->data = val;
  item->next = head->next;
  item->prev = head;
  (head->next)->prev = item;
  head->next = item;
#ifdef SH_LIST_DEBUG
  fprintf(stderr, "Ins First %lx\n", (unsigned long)(item->data));
#endif
  head->data = (void *)((unsigned long)(head->data) + 1);
}

void shListInsLastItem( SHLIST *head, void *val )
{ /* Insert to the end of the list */
  SHLIST *item;

  item = (SHLIST *)malloc( sizeof(SHLIST) );
  if( item == NULL )
    return;
  item->data = val;
  item->next = head;
  item->prev = head->prev;
  (head->prev)->next = item;
  head->prev = item;
#ifdef SH_LIST_DEBUG
  fprintf(stderr, "Ins Last %lx\n", (unsigned long)(item->data));
#endif
  head->data = (void *)((unsigned long)(head->data) + 1);
}

void shListInsBeforeItem( SHLIST *head, void *val, void *etal, 
                          shListCmp func )
{
  SHLIST *item, *iptr;

  if( func == NULL )
    shListInsFirstItem( head, val );
  else {
    item = (SHLIST *)malloc( sizeof(SHLIST) );
    if( item == NULL )
      return;
    item->data = val;
    for(iptr=head->next;( iptr != head );iptr=iptr->next)
      if( func( val, iptr->data, etal ) )
         break;
    item->next = iptr;
    item->prev = iptr->prev;
    (iptr->prev)->next = item;
    iptr->prev = item;
#ifdef SH_LIST_DEBUG
    fprintf(stderr, "Ins Before %lx\n", (unsigned long)(item->data));
#endif
    head->data = (void *)((unsigned long)(head->data) + 1);
  }
}

void shListDelAllItems( SHLIST *head, shListFree func )
{
  SHLIST *item;

  for(item=head->next;( item != head );) {
    shListDelItem( head, item, func );
    item = head->next;
  }
  head->data = (void *)0L;
}

void shListPrintAllItems( SHLIST *head, shListPrint func )
{
#ifdef SH_LIST_DEBUG
  SHLIST *item;

  for(item=head->next;( item != head );item=item->next)
    if( func ) {
      func(item->data);
    }
    else {
      fprintf(stderr, "Item: %lx\n",(unsigned long)(item->data));
    }
#endif
}

unsigned long shListGetCount( SHLIST *head )
{
  return( (unsigned long)(head->data) );
}