/*
 * nasd_cheops_mgr_btree.c
 *
 * B-tree manipulation routines
 *
 * Khalil Amiri, CMU ECE/SCS, 1997
 */
/*
 * Copyright (c) of Carnegie Mellon University, 1996,1997,1998,1999.
 *
 * Permission to reproduce, use, and prepare derivative works of
 * this software for internal use is granted provided the copyright
 * and "No Warranty" statements are included with all reproductions
 * and derivative works. This software may also be redistributed
 * without charge provided that the copyright and "No Warranty"
 * statements are included in all redistributions.
 *
 * NO WARRANTY. THIS SOFTWARE IS FURNISHED ON AN "AS IS" BASIS.
 * CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY KIND, EITHER
 * EXPRESSED OR IMPLIED AS TO THE MATTER INCLUDING, BUT NOT LIMITED
 * TO: WARRANTY OF FITNESS FOR PURPOSE OR MERCHANTABILITY, EXCLUSIVITY
 * OF RESULTS OR RESULTS OBTAINED FROM USE OF THIS SOFTWARE. CARNEGIE
 * MELLON UNIVERSITY DOES NOT MAKE ANY WARRANTY OF ANY KIND WITH RESPECT
 * TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT.
 */


#include <nasd/nasd_options.h>
#include <nasd/nasd_mem.h>
#include <nasd/nasd_general.h>
#include <nasd/nasd_cheops_mgr_btree.h>

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

node_t *imPtrs[MAX_BTREE_NODES];
keynode_pair_t noKey;
nodeid_t NodeID;
int tree_depth;
int mergeNeeded;
typekey mergeNodeKey;
int keyExists;

int node_print(node_t *t);

node_t *
nodeunfix(node_ptr_t tp)
{
  return NULL;
}

node_t *
nodefix(node_ptr_t tp)
{
  if ( tp<NodeID )
    return imPtrs[tp];
  else {
    nasd_printf("illegal node index %d\n",tp); 
    return NULL;
  }
}

node_ptr_t  
emptyNode(void)
{
  node_t *newnode;
 
  newnode = (node_t *) malloc ( sizeof(node_t) );
  newnode->nodeid = NodeID++;
  newnode->d = 0;
  imPtrs[newnode->nodeid]=newnode;
  return( newnode->nodeid );
}

/* insert in node "t" (assuming "t" not full), key value "key"
 * set the pointer associated with "key" to "ptr"
 */
int 
insInNode(node_t *t, typekey key, node_ptr_t ptr)
{
  int j;

  for( j=t->d; j>0 && key<t->k[j-1]; j-- ) {
    t->k[j] = t->k[j-1];
    t->p[j+1] = t->p[j];
  }
  t->d++;
  t->k[j] = key;
  t->p[j+1] = ptr;
  return 0;
}

keynode_pair_t  
insertInternal(typekey key, node_ptr_t mfp, node_ptr_t tp)
{
  int i;
  int j;
  keynode_pair_t ins;
  node_ptr_t nnp;
  node_t *nn;
  node_t *t;

  t = nodefix(tp);
  if (t->level==0) { 
    if ( FULL_NODE(t) ) { /* XX */
      insInNode(t, key, mfp); 
      nnp= emptyNode();
      nn = nodefix(nnp);
      for (j=D+1; j<=2*D+1; j++)
        insInNode(nn, t->k[j-1], t->p[j]);
      t->d = D;
      nn->p[0] = 0; /*  not used for level 0 */
      nn->level = 0;
      ins.key = nn->k[0];
      ins.nodeid = nnp;
      return ins;
    } else {
      insInNode(t, key, mfp); 
      return noKey;
    }
  }

  for (i=0; i<t->d && key>t->k[i]; i++) ;
  if (key==t->k[i]) {
    keyExists = NASD_TRUE;
    return noKey; 
  }

  if (t->level>0) {
    ins = insertInternal(key, mfp, t->p[i]);
    if ( (ins.key!=noKey.key) || (ins.nodeid!=noKey.nodeid) ) {
      if (t->d<2*D)
        insInNode(t,ins.key,ins.nodeid);
      else { 
        /* non-leaf node is full, split */	   
        insInNode(t, ins.key, ins.nodeid); 
        nnp = emptyNode();
        nn = nodefix(nnp);
        for (j=D+2; j<=2*D+1; j++)
          insInNode(nn, t->k[j-1], t->p[j]);
        t->d = D;
        nn->p[0] = t->p[D+1];
        nn->level = t->level;
        ins.key = t->k[D];
        ins.nodeid = nnp;
        return ins;
      }	  
    } /* end if insert Internal returned a key */
  }
  return noKey;
}

/* insert "key" at the root of btree pointed to by "tp" */
node_ptr_t  
insert(typekey key, node_ptr_t mfp, node_ptr_t *tp)
{ 
  int i;
  int j;
  int level;
  keynode_pair_t ins;
  node_ptr_t nnp;
  node_ptr_t ntp;
  node_ptr_t ep;
  node_t *nn;
  node_t *nt;
  node_t *e;

  /* insert into main file 
     e = insertInMainFile(key);
  */
  keyExists = NASD_FALSE;
  e = nodefix(*tp);
  level = e->level;

  if ( level ==0 ) {
    if ( !FULL_NODE(e) )
      insInNode(e, key, mfp);
    else {
      nnp= emptyNode(); /* new node */
      nn = nodefix(nnp);
      ntp= emptyNode(); /* new tree */
      nt = nodefix(ntp);
      insInNode(e,key, mfp);
      nt->level = level+1;
      nn->level = level;
      for (j=D+1; j<=2*D+1; j++)
        insInNode(nn, e->k[j-1], e->p[j]);
      e->d = D;
      nn->p[0] = 0;
      nt->p[0] = *tp;
      nt->p[1] = nnp;
      nt->k[0] = nn->k[0];
      nt->d =1;
      *tp = ntp;
    }
  } else { /* root is not at level 0 */
    for (i=0; i<e->d && key>e->k[i]; i++) ;
    if ( e->p[i] )
      ins = insertInternal(key, mfp, e->p[i]);
    else
      return 0; /* null pointer associated with key -- should panic */
    if ( (ins.key!=noKey.key) || (ins.nodeid!=noKey.nodeid)) {
      if ( !FULL_NODE(e)) 
        insInNode(e, ins.key, ins.nodeid);
      else {
        nnp = emptyNode(); /* new node */
        nn = nodefix(nnp);
        ntp = emptyNode(); /* new tree */
        nt = nodefix(ntp);
        insInNode(e, ins.key, ins.nodeid);
        nn->level = level;
        nt->level = level+1;
        for (j=D+2; j<=2*D+1; j++)
          insInNode(nn, e->k[j-1], e->p[j]);
        e->d = D;
        nn->p[0] = e->p[D+1];
        nt->p[0] = *tp;
        nt->p[1] = nnp;
        nt->k[0] = e->k[D];
        nt->d =1;
        *tp = ntp;
      }
    }
  }
  return *tp;
}

int
mergeNodes(node_t *t, int ni, int si)
{
  int i;
	int j;
	int d1, d2;
	int red_d1, aug_d1;
	int start_i1;
	node_t *e;
	node_t *n1;
	node_t *n2;
	node_ptr_t n1p, n2p;
	
	/* assert si = ni+1 */
	e = t;
	n1p = e->p[ni];  n1 = nodefix(n1p);
	n2p = e->p[si]; n2 = nodefix(n2p);
	d1 = n1->d;
	d2 = n2->d;
	if ( d1+d2 <= 2*D-1 ) { /* merge */
	  insInNode(n1, e->k[ni], n2->p[0]);
	  for (j=1;j<d2;j++)
	    insInNode(n1, n2->k[j], n2->p[j+1]);
	  for (j=ni;j<t->d-1;j++) {
	    e->k[j] = e->k[j+1];
	    e->p[j+1] = e->p[j+2];
	  }
	  e->d--;
	  free(n2);
	} else { /* redistribute keys evenly */
	  if (d1<D) { 
	    aug_d1 = (d1+d2)/2 - d1;
	    insInNode(n1, e->k[ni], n2->p[0]);
	    for (i=1;i<aug_d1;i++)
	      insInNode(n1, n2->k[i-1], n2->p[i]);
	    e->k[ni] = n2->k[aug_d1-1];
	    n2->p[0] = n2->p[aug_d1];
	    for (j=aug_d1;j<d2;j++) {
	      n2->k[j-aug_d1] = n2->k[j];
	      n2->p[j-aug_d1+1] = n2->p[j+1];
	    }
	    n2->d = d2-aug_d1;
	  } else {
	    /* copy keys from n1 to n2 */
	    red_d1 = (d1+d2)/2 - d2;
	    for (j=d2-1; j>=0; j--) {
	      n2->k[j+red_d1] = n2->k[j];
	      n2->p[j+red_d1+1] = n2->p[j+1];
	    }
	    n2->p[red_d1] = n2->p[0];
	    n2->k[red_d1-1] = e->k[ni];
	    start_i1 = d1-red_d1;
	    for(j=1;j<red_d1;j++) {
	      n2->k[j-1]=n1->k[start_i1+j];
	      n2->p[j]=n1->p[start_i1+j];
	    }
	    n1->d -= red_d1;
	    n2->d += red_d1;
	    n2->p[0] = n1->p[start_i1+1];
	    e->k[ni] = n1->k[start_i1];
	  }
	}
	if (e->d<D)
	  return 1;
	else
	  return 0;
}

int
mergeLeafNodes(node_t *t, int ni, int si)
{
  int i;
  int j;
  int d1, d2;
  int red_d1, aug_d1;
  int start_i1;
  node_t *e;
  node_t *n1;
  node_t *n2;
  node_ptr_t n1p, n2p;
       
  /* assert si = ni+1 */
  e = t;
  n1p = e->p[ni];  n1 = nodefix(n1p);
  n2p = e->p[si]; n2 = nodefix(n2p);
  d1 = n1->d;
  d2 = n2->d;
       
  if ( d1+d2 <= 2*D-1 ){ /* merge */
    insInNode(n1, e->k[ni], n2->p[0]);
    for (j=1;j<d2;j++)
      insInNode(n1, n2->k[j], n2->p[j+1]);
    for (j=ni;j<t->d-1;j++) {
      e->k[j] = e->k[j+1];
      e->p[j+1] = e->p[j+2];
    }
    e->d--;
    free(n2);
  } else { /* redistribute keys evenly */
    if (d1<D) { 
      aug_d1 = (d1+d2)/2 - d1;
      for (i=0;i<aug_d1;i++)
        insInNode(n1, n2->k[i], n2->p[i+1]);
      n2->p[0] = 0; /* not used in leaf nodes */;
      for (j=aug_d1;j<d2;j++) {
        n2->k[j-aug_d1] = n2->k[j];
        n2->p[j-aug_d1+1] = n2->p[j+1];
      }
      n2->d = d2-aug_d1;
      e->k[ni] = n2->k[0];
    } else {
      /* copy keys from n1 to n2 */
      red_d1 = (d1+d2)/2 - d2;
      for (j=0; j<red_d1;j++) {
        n2->k[j+red_d1] = n2->k[j];
        n2->p[j+red_d1+1] = n2->p[j+1];
      }
      start_i1 = d1-red_d1;
      for(j=0;j<red_d1;j++) {
        n2->k[j]=n1->k[start_i1+j];
        n2->p[j+1]=n1->p[start_i1+j+1];
      }
      n1->d -= red_d1;
      n2->d += red_d1;
      e->k[ni] = n2->k[0];
    }
  }
  if (e->d<D)
    return 1;
  else
    return 0;
}


/* merge Internal */
int
mergeInternal(typekey key, node_ptr_t tp)
{
  int i;
	int j;
	int d, dbefore, dafter;
	int underflow;
	node_t *e;
	node_t *e1;
	node_t *ea;
	node_t *eb;
	
	e = nodefix(tp);
	if (e->level==1) {
	  for (i=0;i<e->d && key>=e->k[i];i++);
	  if (i==0) 
	    return ( mergeLeafNodes(e, 0, 1) );
	  else if (i==e->d)
	    return mergeLeafNodes(e, e->d-1, e->d);
	  else {
	    e1 = nodefix(e->p[i]);
	    eb = nodefix(e->p[i-1]);
	    ea = nodefix(e->p[i+1]);
	    d = e1->d;
	    dbefore = eb->d;
	    dafter  = ea->d;
	    if (d+dbefore <= 2*D-1)
	      return mergeLeafNodes(e, i-1, i);
	    else
	      return mergeLeafNodes(e, i, i+1);
	  }
	}
	
	for (i=0; i<e->d && key>=e->k[i]; i++);
	underflow = mergeInternal(key, e->p[i]);
	if (underflow) {
	  if (i==0) 
	    return ( mergeNodes(e, 0, 1) );
	  else if (i==e->d)
	    return mergeNodes(e, e->d-1, e->d);
	  else {
	    e1 = nodefix(e->p[i]);
	    eb = nodefix(e->p[i-1]);
	    ea = nodefix(e->p[i+1]);
	    d = e1->d;
	    dbefore = eb->d;
	    dafter  = ea->d;
	    if (d+dbefore <= 2*D-1)
	      return mergeNodes(e, i-1, i);
	    else
	      return mergeNodes(e, i, i+1);
	  }
	}
	if (e->d<D)
	  return 1;
	else
	  return 0;
}

keynode_pair_t
deleteInternal (typekey key, node_ptr_t tp)
{
  int i;
	int j; 
	node_t *e;
	keynode_pair_t del;
	
	e= nodefix(tp);
	del.key = noKey.key;
	del.nodeid = 0;
	if (e->level==0) {
	  for (i=0; i<e->d && key>e->k[i]; i++);
    if (e->k[i]!=key) {
      nasd_printf("key %d not found \n", key);
      return del; /* key not found */
    } else {
      for (j=i; j<e->d-1; j++) {
        e->k[j] = e->k[j+1];
        e->p[j+1] = e->p[j+2];
      }
      e->d--;	
    }
    if (e->d<D) {
      mergeNeeded = NASD_TRUE;
      mergeNodeKey = e->k[0];
    } 
    if (i==0) 
      del.key = e->k[0];
    return del;	
	}

	/* deletion at internal node */
	for (i=0; i<e->d && key>=e->k[i]; i++);
	del = deleteInternal(key, e->p[i]);
	if (i==0) 
	  return del;
	else
	  if (del.key != noKey.key)
	    e->k[i-1] = del.key; 
	del.key = noKey.key;
	return del;

}

int
delete(typekey key, node_ptr_t *tp)
{
  int i;
	int j;
	int underflow;
	node_t *e;
	keynode_pair_t del;
	keynode_pair_t merge;
	
	mergeNeeded= NASD_FALSE;
	e = nodefix(*tp); 
	if (e->level==0) {
	  for (i=0; i<e->d && key>e->k[i]; i++);
	  if (e->k[i]!=key)
	    return -1; /* key not found */
	  else {
	    for (j=i; j<e->d-1; j++) {
	      e->k[j] = e->k[j+1];
	      e->p[j+1] = e->p[j+2];
	    }
	    e->d--;	
	  }
	  return 0;
	} 

	/* root node is not leaf node */
	for (i=0; i<e->d && key>=e->k[i]; i++); 
	del = deleteInternal(key, e->p[i]);
	if  ( i>0 && del.key!=noKey.key ) {
	  e->k[i-1]=del.key;
	} 
	if (mergeNeeded) 
	  nasd_printf("Merge needed \n");
	
	/* deletion complete, initiate recursive merge */
	if ( !mergeNeeded )
	  return 0;
	if (e->level==1) {
	  nasd_printf("merge needed for children of root\n"); /* TO-DO */
	} else {
	  for (i=0; i<e->d && mergeNodeKey>=e->k[i]; i++);
	  underflow = mergeInternal(mergeNodeKey, e->p[i]);
	  if ( !underflow )
	    return 0;
	  else {
	    nasd_printf("merge needed for children of root\n");
	  }
	}

	return 0;
}

/*
 * search for value "key" in btree "t"
 */
int
search(typekey key, node_ptr_t tp)
{
  int i;
	node_t *t;
	
	t = nodefix(tp);
	while (t->level>0) {
	  for (i=0; i<t->d && key>=t->k[i]; i++);
	  t = nodefix(t->p[i]);
	}
	for (i=0; i<t->d && key>t->k[i]; i++);
	if ( (i<t->d) && (key==t->k[i]) )
	  return NASD_TRUE;
	else
	  return NASD_FALSE; /* not found */
}

node_t *
btree_create (node_ptr_t *btree)
{
  node_t *bt;

	NodeID=1;
	noKey.key = 0;
	noKey.nodeid = 0;
	bt = (node_t *) malloc (sizeof(node_t));
	bt->d = 0;
	bt->level = 0;
	bt->nodeid = NodeID++;
	*btree = bt->nodeid;
	imPtrs[1] = bt;

	return NULL;
}

int
btree_print(node_ptr_t tp)
{
  node_t *t;
  int i;

  t = nodefix(tp);
  if (!t) { 
    nasd_printf("Null tree\n"); 
    return 0; 
  }
  node_print(t);
  if (t->level==0)
    return 0;
  for (i=0; i<=t->d; i++) 
    if ( t->p[i] )
      btree_print(t->p[i]); 

  return 0;
}

int
node_print(node_t *t)
{
  int level;
  int i;
      
  level = t->level;
  if (level) {
    nasd_printf("%d:",level);
    for (i=0;i<(tree_depth-t->level);i++) nasd_printf("> ");
    for (i=0; i<t->d; i++)
      nasd_printf("%d ", t->k[i]);
    nasd_printf("\n");
  } else {
    nasd_printf("%d:",level);
    for (i=0;i<(tree_depth-t->level);i++) nasd_printf("> ");
    for (i=0; i<t->d; i++)
      nasd_printf("(%d,%d) ", t->k[i], t->p[i+1]);
    nasd_printf("\n");
  }

  return 0;
}

/*

int
main()
{
       node_t  *btree_root;
       int     i;
       int     vals[] = {1,4,9,256,144,100,25,99,101,121,111,104,108,228,328,16,169, \
			 196,171,180,110,432,123,511,802};

       btree_create (&btree_root);
       for (i=0;i<25; i++) {
	 insert (vals[i], 0, &btree_root);
	 insert (vals[i]+1000, 0, &btree_root);
	 insert (vals[i]+2000, 0, &btree_root);
	 insert (vals[i]+3000, 0, &btree_root);
	 insert (vals[i]+4000, 0, &btree_root);
	 insert (vals[i]+5000, 0, &btree_root);
	 insert (vals[i]+6000, 0, &btree_root);
	 insert (vals[i]+7000, 0, &btree_root);
       }
       
       delete (9, &btree_root);  
       delete (169, &btree_root);
       delete (328, &btree_root);
       delete (99, &btree_root); 
       delete (25, &btree_root); 
       delete (196, &btree_root);
       delete (104, &btree_root);
       delete (180, &btree_root);
       delete (228, &btree_root);
       
       nasd_printf("number of nodes in tree=%d\n", NodeID);
       tree_depth = btree_root->level;
       btree_print(btree_root);
       
       for (i=0;i<25;i++)
	 if ( search(vals[i], btree_root) )
	   nasd_printf(".",vals[i]); 
	 else 
	   nasd_printf ("%d not found\n",vals[i]);

}

*/


/* Local Variables:  */
/* indent-tabs-mode: nil */
/* tab-width: 2 */
/* End: */
