#define ROWHEIGHT 80
#define SEPWIDTH 10

#define ADD_BTN 1
#define REMOVE_BTN 2
#define RESET_BTN 3
#define RANDVAL_BTN 4
#define FIND_BTN 5


#define PREV_SCREEN_BTN 6
#define NEXT_SCREEN_BTN 7
#define CUR_SCREEN_BTN 8

#define CLOSE_BTN 9

class bptreewnd : public memwindow
{
	bptree<int,int>			&_tree;
	int					_curvalue;
	int					_curkey;

	int readitem(int,long,int &);
	static void on_action(int);
	static void redrawfunc(window *);
public:
	bptreewnd(bptree<int,int> &);
	~bptreewnd(){};

	void readtree(string &);
	void draw();
	void exit();
};

bptreewnd::bptreewnd(bptree<int,int> &tree):_tree(tree),_curvalue(0),_curkey(0),memwindow()
{
	
	init(0,width(),0);
//	set_grid_style(line_grid);
	set_text_font();
	buttons_per_line(5);
	set_panel_bg_color(grey2);
	set_show_coordinates(true);
	
	button("Find",FIND_BTN,on_action);
	fbutton("Add",ADD_BTN,on_action);
	button("Remove",REMOVE_BTN,on_action);
	button("Reset",RESET_BTN,on_action);
	button("Random",RANDVAL_BTN,on_action);
	
	button("Prev screen",PREV_SCREEN_BTN,on_action);
	button("Next screen",NEXT_SCREEN_BTN,on_action);
	button("Current screen",CUR_SCREEN_BTN,on_action);
	button("Close",CLOSE_BTN,on_action);

	int_item("Key",_curkey);
	int_item("Value",_curvalue);

	set_redraw(redrawfunc);
	display();
}

void bptreewnd::readtree(string &s)
{
	start_buffering();
	clear();
	int width = 0;
	readitem(0,_tree.info().root,width );
	int height = (_tree.info().depth+2)*ROWHEIGHT+100;

	grabscreen(width+15,height,s);
}

int bptreewnd::readitem(int curdepth,long pos,int &x)
{
	static int x_leaf_link = 0;
	if ( !x )
		x_leaf_link = 0;

	if ( curdepth < _tree.info().depth )
	{//this is a node
		const vnode temp(pos);
		
		int xleft = x;
		queue<int> x_arrow;
		for (int i=0;i<temp.keycount()+1;i++)
			x_arrow.append( readitem(curdepth+1,temp.branch(i),x) );

		int ret = temp.draw(this,xleft,x,ymax()-curdepth*ROWHEIGHT,x_arrow,ymax()-(curdepth+1)*ROWHEIGHT+2);
		return ret;
	}
	else
	{//this is a leaf
		const vleaf temp(pos);

		int ret = temp.draw(this,_tree,x,ymax()-curdepth*ROWHEIGHT,_curkey,x_leaf_link);
		x_leaf_link = x;
		
		x += SEPWIDTH;
		return ret;
	}

	//does not come here never
	return 0;
}


void bptreewnd::redrawfunc(window *pwnd)
{
	((bptreewnd*)pwnd)->draw();
}

void bptreewnd::on_action(int actioncal)
{
	bptreewnd *pwnd = (bptreewnd*) window::get_call_window();

	switch( actioncal )
	{
	case(PREV_SCREEN_BTN):
		pwnd->prev();
		break;
	case(NEXT_SCREEN_BTN):
		pwnd->next();
		break;
	case(CUR_SCREEN_BTN):
		pwnd->current();
		break;

	case(FIND_BTN):
		{
			long data;
			bool bfound = pwnd->_tree.find(pwnd->_curkey,data);
			string s("Find value %d",pwnd->_curkey);
			if (  bfound )
				s+= " , value was FOUND";
			else
				s+= " , value was NOT FOUND";
			pwnd->readtree(s);
		}
		break;

	case(ADD_BTN):
		{
			string s("Insert value %d",pwnd->_curkey);
			pwnd->_tree.insert( pwnd->_curkey,pwnd->_curvalue );
			pwnd->readtree(s);
		}
		break;
	case(REMOVE_BTN):
		{
			bool bdeleted = pwnd->_tree.del(pwnd->_curkey );
			string s("Delete value %d",pwnd->_curkey);
			if (  bdeleted )
				s+= " , value was FOUND and removed";
			else
				s+= " , value was NOT FOUND";
			
			pwnd->readtree(s);
		}
		break;
	case(RANDVAL_BTN):
		{
			int i;
			for (i=0;i<20;i++)
			{
				pwnd->_tree.insert( int(float(rand())/float(RAND_MAX)*50 +1)*10 ,
					int(float(rand())/float(RAND_MAX)*200 +1) );
			}
			for (i=0;i<40;i++)
			{
				pwnd->_tree.del( int(float(rand())/float(RAND_MAX)*50 +1)*10 );
			}
			
			string s("Insert 20 random numbers and remove 40 random numbers (10 - 500)");
			int prev = pwnd->_curkey;
			pwnd->_curkey = -1;//so that it will not be seen as new
			pwnd->readtree(s);
			pwnd->_curkey = prev;//so that it will be that what it is shown
		}
		break;
	case(RESET_BTN):
		{
			pwnd->_tree.clear();
			pwnd->clearscreens();
			string s("The tree was cleared");
			pwnd->readtree(s);
		}
		break;
	case(CLOSE_BTN):
		pwnd->close_window();
		break;
	default:
		assert(false);
	}
}

void bptreewnd::draw()
{
	memwindow::draw();

	int centerpos = (xmax()-xmin())/2;
	draw_ctext(centerpos,50,
		string("b+ tree factor = %d, block size = %d bytes, size of key item = %d, sizeof data item = %d",
			_tree.info().nodekeys+1,_tree.info().blocksize,_tree.info().keysize,_tree.info().datasize),brown);
	draw_ctext( centerpos,30,
		string("keys per node = %d - %d, branch pointers per node = %d - %d",
			_tree.info().nodekeys,_tree.info().nodekeys/2,_tree.info().nodekeys+1,(_tree.info().nodekeys/2)+1),brown );
	draw_ctext( centerpos,10,string("keys and data pointers per leaf : %d - %d",
			_tree.info().leafkeys,_tree.info().leafkeys/2),brown );
}

