/* Filename: LBT.h
 *
 * Programmer: Papaloukopoulos K. George and S.Sioutas
 *
 * Date: June 23, 2006
 * Last Update October 1, 2006
 *
 * This file implements the interface of the Lazy Btree.
 *
 */


#ifndef __LBT_H__
#define __LBT_H__

#include "Bucket.h"
#include "Criticality.h"

int N;
Disk * D;
int numOfBuckets;


/* Given:   Nothing.
 *           
 * Task:    Defines the prototype classes of LBTree.
 *	    Also defines the methods and the data members of 
 *	    this class.	
 * Return:  The implicity LBTree object.
 */
template <class T>
class LBT {

	public:
		LBT(); 
		~LBT();
		void insert(T key);
		void remove(T key);
		LLNode<T> * search(T key);

	private:
		btr::BTree<T> * bt;
		Criticality<T> * C;
		int numOfUpdates;
		double alpha;
		int B;
		int count;
	private:
		void initialize();
};

/* Given:   Nothing.
 *           
 * Task:    Defines the prototype classes of BTree and BTNode.
 *	    Also difines the methods and the data members of 
 *	    those classes.	
 * Return:  The implicit LBTree object.
 */
template <class T>
LBT<T>::LBT() { 

	D = new Disk("LBT.bin");
	bt = new btr::BTree<T> ();

	//_CLLNode<long> * c = new _CLLNode<long>();
	
    	numOfUpdates = 0;
	alpha = 1;
	N = 0;
	B = 8;
	count = 0;		//hold the elements that have been inserted or deleted between one epoch
	numOfBuckets = 0;	//hold the number of buckets, used by Criticality structure

	if (bt->isEmpty()) {
		Bucket<T> * buc = new Bucket<T>(D->getFreeDiskBlock(sizeof(Bucket<T>)));
		C = new Criticality<T>();
		C->add(buc);
		insert(0);		//bug!!!
		//numOfBuckets++;
		//cout<<"L="<<sizeof(LLNode<T>)<<" CL="<<sizeof(CLLNode<long>)<<endl;
	}
	
	//initialize();
}

/* Given:   Nothing.
 *           
 * Task:    Defines the deconstructor.	
 * Return:  Nothing.
 */
template <class T>
LBT<T>::~LBT() { 

	bt->display();
}

/* Given:   Nothing.
 *           
 * Task:    .	
 * Return:  Nothing.
 */
template <class T>
void LBT<T>::initialize() { 	//Is not used!!!

	int i;

	for (i = 0; i < 256; i++) 
		insert(50*i);

	N = 256;
}

/* Given:   A key that we want to insert.
 *           
 * Task:    Find the bucket where the key must be inserted and do the operation.	
 * Return:  Nothing.
 */
template <class T>
void LBT<T>::insert(T key) {

	Bucket<T> * buc = new Bucket<T>();
	long bucketLoc;
  
	cout<<"LBT: key = "<<key<<" bucketLoc="<<bucketLoc<<endl;
	
	bucketLoc = bt->find(key);
    	D->read((char *)buc, sizeof(Bucket<T>), bucketLoc);
	if (buc->insert(key) == -1) 	//the key has already inserted
		return;

	bt->rebalancing ();
	//buc->display();
	
	numOfUpdates++;
	count++;
	if (N < 64) {
		N++;
		if (N == 64) {
			//numOfUpdates = (int)round(log((double)N)/log((double)B)*log2(log2(log2(N))));
			numOfUpdates = (int)round(log((double)N)/log((double)B));
			count = 0;
			buc->prevCritic = buc->criticality(N);
		}
	}

	if (buc->criticality(N) < buc->prevCritic) {
		buc->prevCritic = buc->criticality(N);
		D->write((char *)buc, sizeof(Bucket<T>), buc->getLocation());
	}
	

	if (N >= 64 && (buc->criticality(N) - buc->prevCritic) >= 1) {
		buc->prevCritic = buc->criticality(N);
		C->inc(buc);
		D->write((char *)buc, sizeof(Bucket<T>), buc->getLocation());
	}

	if (numOfUpdates == round(alpha*log((double)N)/log((double)B))) {		//log base B
	
		long location = C->getMostCriticalBucket();

		Bucket<T> * newBuck = new Bucket<T>();
		Bucket<T> * criticalBucket = new Bucket<T>();

		cout<<"LBT_INSERT: End of epoch... N = "<<N<<endl;
		N += count;
		numOfUpdates = 0;
        	count = 0;
		//take the most critical Bucket
		if (location == -1)		//there is no critical bucket
			return;
		D->read((char *)criticalBucket, sizeof(Bucket<T>), location);
		//newBuck = buc->rebalancing(bt);
		newBuck = criticalBucket->rebalancing(bt);			//if split operation take place then return the new bucket
		if (newBuck != NULL) {
			//take care the new criticalities
			C->adjustCriticalities(criticalBucket, newBuck, operation);
			numOfBuckets++;
		}
	}
	
	//cout<<"N = "<<N<<"numOfUpdates = "<<numOfUpdates<<endl;
	
}


/* Given:   A key that we want to delete.
 *           
 * Task:    Find the appropriate bucket where the key must be in 
 * 	    and delete it.	
 * Return:  Nothing.
 */
template <class T>
void LBT<T>::remove(T key) {

	Bucket<T> * buc = new Bucket<T>();

	long bucketLoc = bt->find(key);	
	D->read((char *)buc, sizeof(Bucket<T>), bucketLoc);
	
	if (buc->remove(key) == -1)	//the key is not into the node
		return;
	
	bt->rebalancing ();
	buc->display();
    	
	numOfUpdates++;
	count--;

	/*if (buc->criticality(N) < buc->prevCritic) {
		buc->prevCritic = buc->criticality(N);
		D->write((char *)buc, sizeof(Bucket<T>), buc->getLocation());
	}*/
	

	if ((buc->criticality(N) - buc->prevCritic) >= 1) {
		buc->prevCritic = buc->criticality(N);
		C->inc(buc);
		D->write((char *)buc, sizeof(Bucket<T>), buc->getLocation());
	}

	if (numOfUpdates == round(alpha*log((double)N)/log((double)B)))	{	//log base B
		cout<<"LBT_REMOVE: End of epoch... N = "<<N<<endl;
		long location = C->getMostCriticalBucket();
		Bucket<T> * newBuck = new Bucket<T>();
		Bucket<T> * criticalBucket = new Bucket<T>();
		
		N += count;
		numOfUpdates = 0;
		count = 0;
		
		if (location == -1)
			return;

		//take the most critical Bucket
		D->read((char *)criticalBucket, sizeof(Bucket<T>), C->getMostCriticalBucket());
		//newBuck = buc->rebalancing(bt);
		newBuck = criticalBucket->rebalancing(bt);			//if transfer/fuse operation take place then 
		if (newBuck != NULL)						//return the other bucket
			//take care the new criticalities
			C->adjustCriticalities(criticalBucket, newBuck, operation);
	}
	
}


/* Given:   A key which we to determine if there is in the data structure.
 *           
 * Task:    Perform a search into the data structure and return the block
 * 	    of the second layer list where the key must be.
 * Return:  A node of the second layer list.
 */
template <class T>
LLNode<T> * LBT<T>::search(T key) {

	Bucket<T> * buc = new Bucket<T>();
	
	long bucketLoc = bt->search(key);
	D->read(buc, sizeof(Bucket<T>), bucketLoc);

	return buc->search(key);		//return the node of the corresponding 2nd layer list
}

#endif
