/*
  ArtToSpr Artworks/Draw to Sprite convertor
  Copyright (c) 1998 Tony Houghton

  This source is distributed under the GPL. Please see the file
  "COPYING" for details.
*/

#include "linklist.h"

#ifndef NULL
#define NULL 0
#endif

extern void LinkList_AddToHead(linklist_header *anchor, linklist_header *item)
{
  linklist_header *oldfirst;

  oldfirst       = anchor->next;
  item->next     = oldfirst;                                /* link in next  */
  item->previous = NULL;                                    /* First in list */

  if (oldfirst == NULL)
    anchor->previous = item;              /* First item, so it is 1st & last */
  else
    oldfirst->previous = item;                              /* reverse link  */
  anchor->next = item;                                      /* forward link  */
}

extern void LinkList_AddToTail(linklist_header *anchor, linklist_header *item)
{
  linklist_header *oldlast;

  oldlast          = anchor->previous;
  item->next       = NULL;                           /* This item is last    */
  item->previous   = oldlast;                        /* Link to end          */

  if (oldlast == NULL)
    anchor->next = item;                  /* First item, so it is 1st & last */
  else
    oldlast->next = item;                            /* link to previous     */
  anchor->previous = item;                           /* And link to header   */
}

extern bool LinkList_InList(linklist_header *anchor, linklist_header *item)
{
  linklist_header *ptr;

  ptr = anchor->next;
  while (ptr != NULL)
  {
    if (ptr == item)                               /* compare item ADDRESSES */
      return(true);

    ptr = ptr->next;
  }

  return(false);
}

extern void LinkList_InsertAfter(linklist_header *anchor,
                                 linklist_header *pos,
                                 linklist_header *item)
{
  linklist_header *oldnext;

  oldnext = pos->next;

  if (oldnext == NULL)                             /* Insert at tail of list */
    LinkList_AddToTail(anchor, item);
  else
  {
    oldnext->previous = item;                      /* Link to next in list   */
    item->next        = oldnext;

    pos->next         = item;                      /* Link "pos" in as prev  */
    item->previous    = pos;
  }
}

extern void LinkList_InsertBefore(linklist_header *anchor,
                                  linklist_header *pos,
                                  linklist_header *item)
{
  linklist_header *oldprev;

  oldprev = pos->previous;

  if (oldprev == NULL)                             /* Insert at head of list */
    LinkList_AddToHead(anchor, item);
  else
  {
    oldprev->next  = item;                         /* Link to prev in list   */
    item->previous = oldprev;

    pos->previous  = item;                         /* Link "pos" in as next  */
    item->next     = pos;
  }
}

extern int LinkList_ListLength(linklist_header *anchor)
{
  linklist_header *ptr;
  register int    length = 0;

  ptr = anchor->next;
  while (ptr != NULL)
  {
    length ++;
    ptr = ptr->next;
  }

  return(length);
}

extern void LinkList_Unlink(linklist_header *anchor, linklist_header *item)
{
  linklist_header *prev, *next;

  next = item->next;
  prev = item->previous;

  if (next == NULL)
    anchor->previous = prev;                            /* was last in list  */
  else
    next->previous   = prev;                            /* was in middle     */

  if (prev == NULL)
    anchor->next = next;                                /* was first in list */
  else
    prev->next   = next;                                /* was in middle     */

  item->next     = NULL;                                /* kill to be safe   */
  item->previous = NULL;
}
