/****************************************************************************
  
  GLUI User Interface Toolkit
  ---------------------------

     glui_node.cpp - linked-list tree structure


          --------------------------------------------------

  Copyright (c) 1998 Paul Rademacher

  WWW:    http://sourceforge.net/projects/glui/
  Forums: http://sourceforge.net/forum/?group_id=92496

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library 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
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

*****************************************************************************/

#include "glui.h"
#include "glui_internal.h"

/********************************************* GLUI_Node::GLUI_Node() *******/

GLUI_Node::GLUI_Node()
: 
    parent_node(NULL),
    child_head(NULL),
    child_tail(NULL),
    next_sibling(NULL),
    prev_sibling(NULL)
{
}

/********************************************* GLUI_Node::first() *******/
/* Returns first sibling in 'this' node's sibling list                  */

GLUI_Node   *GLUI_Node::first_sibling( void )
{
  if ( parent_node == NULL )  
    return this;           /* root node has no siblings */
  else
    return parent_node->child_head;
}


/******************************************** GLUI_Node::next() ********/
/* Returns next sibling in 'this' node's sibling list                  */

GLUI_Node    *GLUI_Node::next( void )
{
  return next_sibling;
}


/******************************************** GLUI_Node::prev() ********/
/* Returns prev sibling in 'this' node's sibling list                  */

GLUI_Node    *GLUI_Node::prev( void )
{
  return prev_sibling;
}


/********************************************* GLUI_Node::last() *******/
/* Returns last sibling in 'this' node's sibling list                  */

GLUI_Node   *GLUI_Node::last_sibling( void )
{
  if ( parent_node == NULL )
    return this;            /* root node has no siblings */
  else
    return parent_node->child_tail;
}


/*************************** GLUI_Node::link_this_to_parent_last() *******/
/* Links as last child of parent                                         */

void   GLUI_Node::link_this_to_parent_last( GLUI_Node *new_parent )
{
  if ( new_parent->child_tail == NULL ) {   /* parent has no children */
    new_parent->child_head = this;
    new_parent->child_tail = this;
    this->parent_node      = new_parent;
  }
  else {                                 /* parent has children */
    new_parent->child_tail->next_sibling = this;
    this->prev_sibling                   = new_parent->child_tail;
    new_parent->child_tail               = this;
    this->parent_node                    = new_parent;
  }
}


/*************************** GLUI_Node::link_this_to_parent_first() *******/
/* Links as first child of parent                                         */

void   GLUI_Node::link_this_to_parent_first( GLUI_Node *new_parent )
{
  if ( new_parent->child_head == NULL ) {   /* parent has no children */
    new_parent->child_head               = this;
    new_parent->child_tail               = this;
    this->parent_node                    = new_parent;
  }
  else {                                 /* parent has children */
    new_parent->child_head->prev_sibling = this;
    this->next_sibling                   = new_parent->child_head;
    new_parent->child_head               = this;
    this->parent_node                    = new_parent;
  }
}

/**************************** GLUI_Node::link_this_to_sibling_next() *****/

void   GLUI_Node::link_this_to_sibling_next( GLUI_Node *sibling )
{
  if ( sibling->next_sibling == NULL ) {    /* node has no next sibling */
    sibling->next_sibling  = this;
    this->prev_sibling     = sibling;

    /* This was the parent's last child, so update that as well */
    if ( sibling->parent_node  != NULL ) {
      sibling->parent_node->child_tail = this;
    }
  }
  else {                            /* node already has a next sibling */
    sibling->next_sibling->prev_sibling = this;
    this->next_sibling                  = sibling->next_sibling;
    sibling->next_sibling               = this;
    this->prev_sibling                  = sibling;
  }

  this->parent_node = sibling->parent_node;
}


/**************************** GLUI_Node::link_this_to_sibling_prev() *****/

void   GLUI_Node::link_this_to_sibling_prev( GLUI_Node *sibling )
{
  if ( sibling->prev_sibling == NULL ) {    /* node has no prev sibling */
    sibling->prev_sibling  = this;
    this->next_sibling     = sibling;

    /* This was the parent's first child, so update that as well */
    if ( sibling->parent_node  != NULL ) {
      sibling->parent_node->child_head = this;
    }
  }
  else {                            /* node already has a prev sibling */
    sibling->prev_sibling->next_sibling = this;
    this->prev_sibling                  = sibling->prev_sibling;
    sibling->prev_sibling               = this;
    this->next_sibling                  = sibling;
  }

  this->parent_node = sibling->parent_node;
}

/**************************************** GLUI_Node::unlink() **************/

void   GLUI_Node::unlink( void )
{
  /* Unlink from prev sibling */
  if ( this->prev_sibling != NULL ) {
    this->prev_sibling->next_sibling = this->next_sibling;
  }
  else {                 /* No prev sibling: this was parent's first child */
    this->parent_node->child_head = this->next_sibling;
  }

  /* Unlink from next sibling */
  if ( this->next_sibling != NULL ) {
    this->next_sibling->prev_sibling = this->prev_sibling;
  }
  else {                /* No next sibling: this was parent's last child */
    this->parent_node->child_tail = this->prev_sibling;
  }

  this->parent_node  = NULL;
  this->next_sibling = NULL;
  this->prev_sibling = NULL;
  this->child_head   = NULL;
  this->child_tail   = NULL;
}

/**************************************** GLUI_Node::dump() **************/

void GLUI_Node::dump( FILE *out, const char *name )
{
    fprintf( out, "GLUI_node: %s\n", name );
    fprintf( out, "   parent: %p     child_head: %p    child_tail: %p\n",
        (void *) parent_node,
        (void *) child_head,
        (void *) child_tail );
    fprintf( out, "   next: %p       prev: %p\n",
        (void *) next_sibling,
        (void *) prev_sibling );
}
