/* symidxnode.cpp */

#include <stdio.h>
#include "symidxnode.h"

/* "compare" Confronta con il nodo "to".
 * >0 -> this > to
 * =0 -> this = to
 * <0 -> this < to
 *
 * Voglio che le chiavi nel nodo siano crescenti, quindi, per ogni chiave
 *	dato [i]->compare (dato [i+1]) <= 0;
 */


SymIdxNode *SymIdxNode::insert (SymNode *n, SymIdxNode *right, idxs keyNum, SymIdxInsert *split)
{
SymNode *d;			// Chiave in eccesso, quando inserisco
SymIdxNode *allRight;	// Punatore destro in eccesso
int i;
SymIdxNode *r = (SymIdxNode *) 0;	// Eventuale nuova root

	// Cerca il punto di inserimento
	if (data [NODELEN - 1] && data [NODELEN - 1] -> compare (keyNum, n) <= 0) {	// E' maggiore dell'ultmo
		d = n;						// Metto nuovo nodo in overflow
		allRight = right;
	} else {
		i = NODELEN - 1;
		d = data [i];				// Metto l'ultimo, pieno o vuoto, in overflow
		allRight = left [i + 1];
		while (i) {	// Fino che non arriva alla prima posizione
			i--;	// Va alla posizione precedente
			// Se c'e' il nodo ed e' minore del dato da inserire, interrompe
			if (data [i] && data [i] -> compare (keyNum, n) <= 0) {
				i ++;
				break;
			}
			// Libero la posizione "i"
			data [i+1] = data [i];
			left [i + 2] = left [i + 1];
		}
    	// e' arrivato al punto - ci inserisce la nuova chiave
		data [i] = n;
		left [i + 1] = right;
	}
	if (d) {	// Se ha fatto overflow
	SymIdxNode *s = new SymIdxNode ();
	int n = NODELEN/2;
		if (split) {					// se non siamo alla root,	ritorniamo la chiave nuova in split
			split -> data = data [n];
			split -> right = s;
		} else {						// Se siamo alla root, creiamo una nuova root
			r = new SymIdxNode ();
			r -> data [0] = data [n];
			r -> left [0] = this;
			r -> left [1] = s;
		}
		data [n++] = NULL;				// Questa chiave finisce nel nodo superiore
		// Copia meta' nodo di sopra
		s -> left [0] = left [n];		// Estrema sinistra
		left [n] = NULL;				// Cancello
		for (i = 0; n < NODELEN;) {		// Copio la parte alta del nodo corrente nel nuovo nodo
			s -> data [i++] = data [n];	// Copio il dato
			data [n++] = NULL;			// Cancello
			s -> left [i] = left [n];	// Copio la chiave
			left [n] = NULL;			// cancello
		}
		// Inserisce l'elemento in eccesso;
		s -> data [i++] = d;
		s -> left [i] = allRight;
	}
	return r;
}

/* Se split e' NULL, allora siamo nella root e creiamo sullo split un nuovo nodo con una sola chiave */
SymIdxNode *SymIdxNode::add (SymNode *n, idxs keyNum, SymIdxInsert *split)
{
int i;
	// Cerca nel nodo il posto giusto
	for (i = 0; i < NODELEN && data [i]; i++) {
		if (data [i] -> compare (keyNum, n) > 0) {
			break;
		}
	}
	if (left [i]) {// Se non e' foglia (ha il puntatore), ricorsivamente scende
	SymIdxInsert subSplit;
		left [i]->add (n, keyNum, &subSplit);	// Tenta di inserire nella foglia
		if (subSplit.data) {					// Il nodo inferiore ha fatto overflow - inserisco
			return insert (subSplit.data, subSplit.right, keyNum, split);
		}
	} else { // Se e' foglia, tenta di inserire
		return insert (n, (SymIdxNode *) 0, keyNum, split);
	}
	return (SymIdxNode *) 0;
}

SymNode *SymIdxNode::findEq (SymNode *ref, idxs keyNum)
{
int i, c;
	// Cerca nel nodo il posoto giusto
	for (i = 0; i < NODELEN && data [i]; i++) {
		c = data [i] -> compare (keyNum, ref);
		if (c == 0) {
			return data [i];
		} else if (c > 0) {
			break;
		}
	}
	if (left [i]) {
		return left [i] -> findEq (ref, keyNum);
	}
	return NULL;
}

SymNode *SymIdxNode::findLastEq (SymNode *ref, idxs keyNum, SymNode *lastEqu)
{
int i, c;
	// Cerca nel nodo il posoto giusto
	for (i = 0; i < NODELEN && data [i]; i++) {
		c = data [i] -> compare (keyNum, ref);
		if (c == 0) {
			lastEqu = data [i];
		} else if (c > 0) {
			break;
		}
	}
	if (left [i]) {
		return left [i] -> findLastEq (ref, keyNum, lastEqu);
	}
	return lastEqu;
}

SymNode *SymIdxNode::findLt (SymNode *ref, idxs keyNum)
{
int i, c;
SymNode *last = NULL;
	// Cerca nel nodo il posoto giusto
	for (i = 0; i < NODELEN && data [i]; i++) {
		c = data [i] -> compare (keyNum, ref);
		if (c == 0) {
			return data [i];
		} else if (c > 0) {
			break;
		} else {
			last = data [i];
		}
	}
	if (left [i]) {
		return left [i] -> findLt (ref, keyNum);
	}
	return last;
}

#ifdef TREEDEBUG
void SymIdxNode::debPrint ()
{
int i;
	if (left [0]) {
		left [0] -> debPrint ();
	}
	for (i = 0; i < NODELEN  && data [i];) {
		printf ("[%x] %d ", this, i);
		data [i++] -> debPrint ();
		if (left [i]) {
			left [i] -> debPrint ();
		}
	}
}
#endif


SymIdxNode::SymIdxNode ()
{
int i;
	for (i = 0; i < NODELEN; i++) {
		data [i] = NULL;
	}
	for (i = 0; i < NODELEN + 1; i++) {
		left [i] = NULL;
	}
}

SymIdxNode::~SymIdxNode ()
{
int i;
	for (i = 0; i < NODELEN + 1; i++) {
		if (left [i]) { delete left [i]; }
	}
}
