#pragma comment( lib , "libL.lib" )
#pragma comment( lib , "libG.lib" )
#pragma comment( lib , "libP.lib" )
#pragma comment( lib , "libW.lib" )

#pragma warning ( push , 1 )
#include <LEDA/window.h>
#include <LEDA/stack.h>
#include <LEDA/queue.h>
#include <LEDA/dictionary.h>
#include <LEDA/string.h>
#include <LEDA/slist.h>
#pragma warning ( pop )
#undef node

#include <exception>
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <io.h>
#include <errno.h>
#include <stdio.h>
#include <math.h>
#include <time.h>

//various math functions
#define Ln(a) (log(a))
#define ToInt(a) ( int(((a)-floor(a))<=double(0.5)?floor(a):ceil(a)) )

#define BLOCKSIZE 128

//this here must be removed when istree becomes template
#define REP_TYPE int
#define IST_DATA int


//this must be removed because they are for debuuginf support ...
int errorcouner = 0;
int successcouner = 0;

////////////////////////
#include "except.h"
#include "filewrapper.h"
#include "fileobject.h"
#include "fileblock.h"
#include "leaf.h"
#include "node.h"
#include "datafile.h"
#include "stabptree.h"
#include "bptree.h"
#include "istnode.h"
#include "isttree.h"
#include "dataiterator.h"
#include "vclasses.h"
#include "actualwindow.h"
#include "memwindow.h"
#include "bptreewnd.h"

void BulkLoadIntegers(unsigned int size,isttree &tree,stabptree<int,int> &standalonebptree)
{
	isttree::INFO & ist_info = tree.Info();

	printf("Items size : %d\n",size);
	//remember that size cannot be more than UINT_MAX = 4294967295 (0xffffffff)

	//if i don't use ceil() some elements would be left out.
	int btree_size = ceil(Ln(size));
	printf("BPtrees size of Isttree : %d\n",btree_size);
//	btree_size = 1;
	ist_info.keys = ceil( double(size)/double(btree_size) );
	printf("ISttree keys size : %d\n",ist_info.keys);

	srand( (unsigned)time( NULL ) );

	KEY_BRANCH_PAIR * pkey_branch = (KEY_BRANCH_PAIR *) malloc( ist_info.keys*sizeof(KEY_BRANCH_PAIR) );

	int curkeyindex = 0;
	int lastkey=0;

	for (int i=0;(i<ist_info.keys && curkeyindex<size);i++)
	{
		long lreepos = bptree<REP_TYPE,IST_DATA>::createbtree(tree.get_full_index_file());
		bptree<REP_TYPE,IST_DATA> newtree(tree.get_full_index_file(),tree.get_full_data_file(),lreepos);
		pkey_branch[i].branch=lreepos;

		for (int j=0;(j<btree_size && curkeyindex<size);j++)
		{
			//the following ensures that i will not have dublicate keys and that they will be sorted ...
			int offset = (int) ((double(rand())/double(RAND_MAX))*(double(INT_MAX-lastkey-1)/double(size-curkeyindex)));
			offset = 0;
			int newkey = lastkey+offset+1;
			
			standalonebptree.insert(newkey,10);
			newtree.insert(newkey,10);
			
			long pos;
			assert( standalonebptree.find(newkey,pos) );
			assert( newtree.find(newkey,pos) );



			if (j==0)
				pkey_branch[i].key=newkey;

			if ( curkeyindex % 10000 == 0 )
				printf("Adding key : %d (%d) \n",newkey,curkeyindex);

			assert( newkey > lastkey );
			lastkey = newkey;
			curkeyindex++;
		}
	}

	ist_info.leftmostbtree = pkey_branch[0];
	ist_info.rightmostbtree = pkey_branch[ist_info.keys-1];
	ist_info.root_limits.a = pkey_branch[0].key;
	ist_info.root_limits.b = lastkey;


	printf("Now contructing isttree\n");
	tree.ConstructTree(pkey_branch);

	free(pkey_branch);
}

void Test(isttree &tree,stabptree<int,int> &standalonebptree)
{
	long pos;
	for (int i=20000000;i<30000000;i++)
	{
		int num = rand();
		num = i;
		if ( (num % 1000 )<3 )
			printf("%d\n",num);

		if ( num == 15 )
		{
			int k;
			k=6;
		}

		bool bfound;
		bfound = tree.find(num,pos);
		assert(bfound);

		bfound = standalonebptree.find(num,pos);
		assert(bfound);
	}
}


void main(void)
{
	//create a new pseudo random number sequence
	srand( (unsigned)time( NULL ) );

	try
	{

		logger loger(false,true,true,true);

		isttree tree;
		if ( !tree.open("index.file","data.file") )
		{
			printf("\nRecreating files and opening ...");
			isttree::createfiles("index.file","data.file");
			if ( !tree.open("index.file","data.file") )
			{
				printf("\nCould not open new files, program will exit !");
				return;
			}
		}

		stabptree<int,int> standalonebptree;
		if ( !standalonebptree.open("sta_index.file","sta_data.file") )
		{
			printf("\nRecreating sta bptree files and opening ...");
			stabptree<int,int>::createfiles("sta_index.file","sta_data.file");
			if ( !standalonebptree.open("sta_index.file","sta_data.file") )
			{
				printf("\nCould not open new sta bptree files, program will exit !");
				return;
			}
		}

		
		tree.get_data_file().assign_logger(&loger);
		tree.get_index_file().assign_logger(&loger);
		standalonebptree.get_data_file().assign_logger(&loger);
		standalonebptree.get_index_file().assign_logger(&loger);

		BulkLoadIntegers(100000000,tree,standalonebptree);
		printf("\r\n\r\nGlobal recontsruction cost ...");
		loger.print_statistics();

		loger.reset_ios();
		
		Test(tree,standalonebptree);
		printf("\r\n\r\nInsert & Search cost ...");
		loger.print_statistics();
		printf("\n\nInterpolation Errors %d - Successes %d \n",errorcouner,successcouner);

		tree.get_data_file().assign_logger(NULL);
		tree.get_index_file().assign_logger(NULL);
		standalonebptree.get_data_file().assign_logger(NULL);
		standalonebptree.get_index_file().assign_logger(NULL);

	}
	catch(exception * pe)
	{
		printf(pe->what());
		delete pe;
	}
}

