//-*- c++ -*-
// ------------------------------------------
// RCS data:
// $Date: 2003/06/23 14:47:23 $
// $Revision: 1.1.1.1 $
// $Source: /cvsroot/miwm/miwm/miwm/nodes.cc,v $
// $Id: nodes.cc,v 1.1.1.1 2003/06/23 14:47:23 bwise837 Exp $
// $RCSfile: nodes.cc,v $
// ------------------------------------------
// Copyright by Ben Paul Wise.
// -------------------------------------------
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
// -------------------------------------------
// this is a very limited kind of list. It is
// not suitable for general purpose use.
// it was developed strictly to make templates
// unnecessary in this application. it was
// harder to get the standard template library
// to work WITHOUT lots of #ifdef conditional
// compilation than it was to get this code
// to work.
// -------------------------------------------

#include <stdlib.h>
#include "nodes.h"

// ------------------------------------------

Node::Node() {
  next = NULL;
  prev = NULL;
  data = NULL;
}

Node::~Node() {
  next = NULL;
  prev = NULL;
  data = NULL;
}

// ------------------------------------------

NodeList::NodeList() {
  first = NULL;
  last = first;
  actual = first;
}

NodeList::~NodeList() {
  while (NULL != first) 
    remove(first);
  first = NULL;
  last = NULL;
  actual = NULL;
}


// ------------------------------------------
// delete each node's contents, then delete each node, then delete the list itself
void 
obliterateNodeList(NodeList* nList) {
//    Node *nd;
//    void* nData;
  if (NULL != nList) {
    // this was redundant. ~NodeList recursively destroys nodes (and their contents?)
//      for (nd = nList->first; nd != NULL; nd = nList->nextNode(nd)) {
//        nData = nd->data;
//        if (NULL != nData) {
//  	delete nData;
//  	nd->data = NULL;
//        }
//      }
    delete nList;
    nList = NULL;
  }
  return;
}
// ------------------------------------------
//  inList - searches for given data pointer in list and returns pointer to
//              corresponding Node-structure if found else NULL.

Node *
NodeList::inList(void *dataPtr) {
  Node *InList = NULL;
  Node *p;

  p  =  first;
  while (p) {
    if (p->data == dataPtr) { 
      InList = p;
      break;
    }
    p = p->next;
  }

  return (InList);
}
// ------------------------------------------
// append - Appends element at end of list, creating a new node to put it in.
// Will return tbFalse if element is not in list after call, else
// tbTrue.
// note that we allow duplicates to be appended

TLogical
NodeList::append(void *ptr) {
  Node *nd;
  nd = new Node();
  if (NULL == nd) {
    // ran out of memory!
    return (tbFalse);
  }

  nd->prev = last;
  nd->next = NULL;
  nd->data = ptr;

  if (nd->prev) 
    nd->prev->next = nd;
  else 
    first = nd;

  last = nd;
  return (tbTrue);
}




// ------------------------------------------
Node* 
NodeList::at(int i) {
  Node *nd = first;
  assert (i >= 0);
  while ((NULL != nd) && (i >=0)) {
    if (0 == i)
      return nd;
    nd = nd->next;
    i = i - 1;
  }
  return nd;
}


// ------------------------------------------
int 
NodeList::length() {
  int population = 0;
  Node *nd = first;
  while (nd != NULL)
    {
      population = population + 1;
      nd = nd->next;
    }
  return population;
}


// ------------------------------------------
// prepend - Inserts new element as the first element of list and resets the
// actual-pointer to first element.
// Will return tbFalse if element is not in list after call, else
// tbTrue.
// note that we allow duplicates to be prepended

TLogical
NodeList::prepend(void *ptr) {
  Node *nd = new Node();

  if (NULL == nd)
    return (tbFalse);

  nd->prev = NULL;
  nd->next = first;
  nd->data = ptr;

  if (nd->next) 
    nd->next->prev = nd;
  else 
    last = nd;

  first = nd;
  actual = first;

  return (tbTrue);
}


// ------------------------------------------
// remove - Deletes node from List. The data must either be already deleted
// or saved, else it will become unreferenced garbage.
// Returns pointer to next Node if existing, else pointer to
// previous one. Returns NULL if the list now is empty and pointer
// to Node itself if node is not in list.


Node *
NodeList::remove(Node *nd)  {
  Node *rn;
  if (NULL == nd) 
    return (NULL);
  if (NULL == inList(nd->data)) 
    return (nd);

  if (nd->prev) {
    nd->prev->next = nd->next;
    rn = nd->prev;
  } 
  else {
    first = nd->next;
    rn = NULL;
  }
  if (nd->next) {
    nd->next->prev = nd->prev;
    rn = nd->next;
  } else 
    last = nd->prev;

  delete nd;
  return (rn);
}


// ------------------------------------------
//  nextNode - returns pointer to following node.

Node* 
NodeList::nextNode(Node *nd) {
  if (NULL != nd)
    return (nd->next);
  else 
    return (first);
}

// ------------------------------------------
//  prevNode - returns pointer to previous node.

Node* 
NodeList::prevNode(Node *nd) {
  if (NULL != nd) 
    return (nd->prev);
  else 
    return (last);
}

// ------------------------------------------
void 
NodeList::moveToEnd(Node *nd) {
  assert (NULL != nd);
  assert (NULL != inList(nd->data));

  if (NULL == nd->next)
    return;

  if (nd->prev) 
    nd->prev->next = nd->next;
  else 
    first = nd->next;

  nd->next->prev = nd->prev;

  last->next = nd;
  nd->prev = last;
  last = nd;
  nd->next = NULL;
}


// ------------------------------------------

void 
NodeList::moveToFront(Node *nd) {
  assert (NULL != nd);
  assert (NULL != inList(nd->data));

  if (NULL == nd->prev)
    return;

  if (nd->next) 
    nd->next->prev = nd->prev;
  else 
    last = nd->prev;

  nd->prev->next = nd->next;

  first->prev = nd;
  nd->next = first;
  first = nd;
  nd->prev = NULL;
}

// ------------------------------------------
// end of nodes.cc
// ------------------------------------------
