#include <fstream>
#include <cstring>
using namespace std ;

#include "btree.hxx"

//  (c) J. Dean Brock, 1998, 1999, 2002
//  Written for UNCA CSCI 343
//  Routines to update the B+-tree

void bTree::update(char *key, int value) {
  char leftMaxKey[KEYSIZE] ;
  int  rightPos = -1 ;
  simpRecT newRec ;
  bzero((char *)&newRec, sizeof(simpRecT)) ;
  (void) strncpy(&newRec.name[0], key, KEYSIZE) ;
  newRec.value = value ;
  updateInt(0, newRec, &leftMaxKey[0], rightPos) ;
  if (rightPos != -1) {
    // We gotta split the root and raise the tree a level
    int leftPos ;
    leftPos = addBlock(btRoot) ;	// Yeah...  the root was overwritten
    if (!btState)
      return ;
    clearLeaf(&btRoot) ;
    btRoot.recs[0].value = leftPos ;
    (void) strncpy(&btRoot.recs[0].name[0], leftMaxKey, KEYSIZE);
    btRoot.recs[1].value = rightPos ;
    setUsedRecords(&btRoot, 1) ;
    updateBlock(0, btRoot) ;
  }    
}

void bTree::updateInt(
	int   subPos,		// index of subtree for update
	const simpRecT &newRec,	// record to be inserted
	char splitKey[KEYSIZE],	// in case of split, store split key here
	int &splitPos)		// in case of split, store new block addr here
{
  blockRecT subBlock ;
  int childSlot, found ;

  if (subPos == 0)
    subBlock = btRoot ;
  else {
    readBlock(subPos, subBlock) ;
    if (!btState)
      return ;
  }

  findLEslot(subBlock, newRec.name, childSlot, found) ;

  if (isLeaf(&subBlock)) {
    if (found)
      // Replacing an existing value
      subBlock.recs[childSlot].value = newRec.value ;
    else if (getUsedRecords(&subBlock) < RECSINBLK)
      // Adding a new value to this leaf
      insertRec(subBlock, childSlot, newRec) ;
    else {
      int newPos ;
      blockRecT newBlock ;
      splitBlock(subBlock, newBlock, splitKey, newRec, childSlot) ;
      newPos = addBlock(newBlock) ;
      if (!btState)
	return ;
      splitPos = newPos ;
      subBlock.recs[METAPNTR].value = splitPos ;
    }
    updateBlock(subPos, subBlock) ;
  } else {
    char newSplitKey[KEYSIZE] ;
    int  newSplitPos = -1 ;
    updateInt(subBlock.recs[childSlot].value,newRec,newSplitKey,newSplitPos);
    if (newSplitPos != -1) {
      simpRecT newIntRec ;
      (void) strncpy(newIntRec.name, newSplitKey, KEYSIZE) ;
      newIntRec.value = subBlock.recs[childSlot].value ;
      subBlock.recs[childSlot].value = newSplitPos ;
      if (getUsedRecords(&subBlock) < RECSINBLK)
	// Adding a new record to this interior node.
	insertRec(subBlock, childSlot, newIntRec) ;
      else {
	// Spliting an interior node
	int newPos ;
	blockRecT newBlock ;
	splitBlock(subBlock, newBlock, splitKey, newIntRec, childSlot) ;
	newPos = addBlock(newBlock) ;
	if (!btState)
	  return ;
	splitPos = newPos ;
	if (isLeaf(&subBlock))
	  subBlock.recs[METAPNTR].value = splitPos ;
      }
      updateBlock(subPos, subBlock) ;
    }
  }
}

