/* splay.c
 * Written by Daniel Sleator <sleator@cs.cmu.edu> with many modifications
 * made by Dr. Tom <tomh@po.crl.go.jp> for libwcomp
 *
 * Daniel Sleator's homepage may be found at http://www.cs.cmu.edu/~sleator/
 * I have contacted Dr. Sleator and he has told me that this source code is
 * in the public domain.  -- David Allen <s2mdalle@titan.vcu.edu>
 *
 * Splay tree routines for libwcomp
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "config.h"
#include "wcomp.h"

#define set_parent_left(t)  {if((t)->left  != NULL) (t)->left->parent  = (t);}
#define set_parent_right(t) {if((t)->right != NULL) (t)->right->parent = (t);}

extern char *wcomp_new(int size);

/* Search for w and bring the nearest node up to the root. */

WCompTree *wcomp_splay(char *w, WCompTree * t)
{
     int c;
     WCompTree N, *l, *r, *y;
     
     if (t == NULL) return t;
     N.left = N.right = NULL;
     l = r = &N;
     
     while(1) 
     {
          c = CMP(w, t->key);
          if (c < 0) 
          {
               if (t->left == NULL) 
                    break;

               if (CMP(w, t->left->key) < 0) 
               {
                    y = t->left;            /* rotate right */
                    t->left = y->right;
                    set_parent_left(t);
                    y->right = t;
                    t->parent = y;
                    t = y;
                    if (t->left == NULL) 
                         break;
               } /* End if */
               r->left = t;                    /* link right */
               t->parent = r;
               r = t;
               t = t->left;
          } /* End if */
          else if (c > 0) 
          {
               if (t->right == NULL) 
                    break;
               if (CMP(w, t->right->key) > 0) 
               {
                    y = t->right;           /* rotate left */
                    t->right = y->left;
                    set_parent_right(t);
                    y->left = t;
                    t->parent = y;
                    t = y;
                    if (t->right == NULL) 
                         break;
               } /* End if */
               
               l->right = t;                   /* link left */
               t->parent = l;
               l = t;
               t = t->right;
          } /* End else if */
          else break;
     } /* End while */
     
     l->right = t->left;                             /* assemble */
     set_parent_right(l);
     r->left = t->right;
     set_parent_left(r);
     t->left = N.right;
     set_parent_left(t);
     t->right = N.left;
     set_parent_right(t);
     t->parent = NULL;
     
     return t;
} /* End wcomp_splay() */

/* Insert w into the tree t, unless it's already there.  Return a pointer to
 * the resulting tree. 
 */
WCompTree *wcomp_insert(char *w, WCompTree *t)
{
     int c;
     WCompTree *new;
     
     new = (WCompTree *)wcomp_new(sizeof(WCompTree));
     new->key = w;

     if (t == NULL) 
     {
          new->left = new->right = new->parent = NULL;
          return new;
     } /* End if */

     t = wcomp_splay(w, t);
     c = CMP(w, t->key);
     if (c < 0) 
     {
          new->left = t->left;
          new->right = t;
          t->left = NULL;
          set_parent_left(new);
          set_parent_right(new);
          return new;
     } /* End if */

     if (c > 0) 
     {
          new->right = t->right;
          new->left = t;
          t->right = NULL;
          set_parent_left(new);
          set_parent_right(new);
          return new;
     } /* End if */
     
     /* We get here if it's already in the tree.  Don't add it again. */
     
     free(new);
     return t;
} /* End wcomp_insert() */

/* Find a node; the cursor points at the last node examined if it wasn't
 * found. 
 */

void wcomp_find(char *w, WCompTree *t, WCompCursor *p)
{
     int c;
     
     if (t == NULL) return;
     p->depth = 0;
     while (1) 
     {
          c = CMP(w, t->key);
          if (c < 0) 
          {
               if (t->left == NULL) break;
               t = t->left;
          } /* End if */
          else if (c > 0) 
          {
               if (t->right == NULL) break;
               t = t->right;
          } /* End else if */
          else break;
          p->depth++;
     } /* End while */

     p->t = t;
} /* End wcomp_find() */

/* Update the cursor to point to the next node of the tree or NULL. */

void wcomp_next(WCompCursor *p)
{
     WCompTree *t, *x;
     
     t = p->t;
     if (t == NULL) return;
     
     x = t->right;
     if (x != NULL) 
     {
          p->depth++;
          while (x->left != NULL) 
          {
               x = x->left;
               p->depth++;
          } /* End while */
          p->t = x;
          return;
     } /* End if */

     x = t->parent;
     while (x != NULL) 
     {
          p->depth--;
          if (x->left == t)
               break;
          
          t = x;
          x = t->parent;
     } /* End while */
     
     p->t = x;
} /* End wcomp_next() */
