/* Converts |tree| into a vine. */
static void
tree_to_vine (struct pbst_table *tree)
{
  struct pbst_node *q, *p;

  q = (struct pbst_node *) &tree->pbst_root;
  p = tree->pbst_root;
  while (p != NULL)
    if (p->pbst_link[1] == NULL)
      {
        q = p;
        p = p->pbst_link[0];
      }
    else
      {
        struct pbst_node *r = p->pbst_link[1];
        p->pbst_link[1] = r->pbst_link[0];
        r->pbst_link[0] = p;
        p = r;
        q->pbst_link[0] = r;
      }
}

/* Performs a compression transformation |count| times,
   starting at |root|. */
static void
compress (struct pbst_node *root, unsigned long count)
{
  assert (root != NULL);

  while (count--)
    {
      struct pbst_node *red = root->pbst_link[0];
      struct pbst_node *black = red->pbst_link[0];

      root->pbst_link[0] = black;
      red->pbst_link[0] = black->pbst_link[1];
      black->pbst_link[1] = red;
      root = black;
    }
}

/* Converts |tree|, which must be in the shape of a vine, into a balanced
   tree. */
static void
vine_to_tree (struct pbst_table *tree)
{
  unsigned long vine;      /* Number of nodes in main vine. */
  unsigned long leaves;    /* Nodes in incomplete bottom level, if any. */
  int height;              /* Height of produced balanced tree. */

  leaves = tree->pbst_count + 1;
  for (;;)
    {
      unsigned long next = leaves & (leaves - 1);
      if (next == 0)
        break;
      leaves = next;
    }
  leaves = tree->pbst_count + 1 - leaves;

  compress ((struct pbst_node *) &tree->pbst_root, leaves);

  vine = tree->pbst_count - leaves;
  height = 1 + (leaves > 0);
  while (vine > 1)
    {
      compress ((struct pbst_node *) &tree->pbst_root, vine / 2);
      vine /= 2;
      height++;
    }

}

static void
update_parents (struct pbst_table *tree)
{
  struct pbst_node *p;

  if (tree->pbst_root == NULL)
    return;

  tree->pbst_root->pbst_parent = NULL;
  for (p = tree->pbst_root; ; p = p->pbst_link[1])
    {
      for (; p->pbst_link[0] != NULL; p = p->pbst_link[0])
        p->pbst_link[0]->pbst_parent = p;

      for (; p->pbst_link[1] == NULL; p = p->pbst_parent)
        {
          for (;;)
            {
              if (p->pbst_parent == NULL)
                return;

              if (p == p->pbst_parent->pbst_link[0])
                break;
              p = p->pbst_parent;
            }
        }

      p->pbst_link[1]->pbst_parent = p;
    }
}

/* Balances |tree|.
   Ensures that no simple path from the root to a leaf has more than
   |PBST_MAX_HEIGHT| nodes. */
void
pbst_balance (struct pbst_table *tree)
{
  assert (tree != NULL);

  tree_to_vine (tree);
  vine_to_tree (tree);
  update_parents (tree);
}

