
#import "TreeView.h"
#import "TreeButton.h"
#import "NamedTree.h"
#import "Line.h"

// constants to determine how the buttons are laid out
#define BUTTONWIDTH		128.0
#define BUTTONHEIGHT	24.0
#define VERTSPACING		8.0
#define HORIZSPACING	40.0

@implementation TreeView

- buildTreeFromNode:aNode bottom:(double)ybot
		top:(double)ytop atX:(double)xpos parent:(NXPoint *)pos
{	// add a button representing the node to the View
	// This method is recursive.
	NXRect butFrame = {{(xpos + HORIZSPACING),
			(ybot + (ytop - ybot) / 2 - BUTTONHEIGHT / 2)},
			{BUTTONWIDTH, BUTTONHEIGHT}};
	id newButton = [[[TreeButton alloc] initFrame:&butFrame]
			setTreeNode:aNode];
	id kid, kids = [aNode branches];
	int numBranches = [kids count];
	int i, treeWidth; double diff, accum = ybot;
	NXPoint myCenter = {(NX_X(&butFrame) + BUTTONWIDTH / 2),
			(NX_Y(&butFrame) + BUTTONHEIGHT / 2)};
	id newLine;
	
	[newButton setTitle:[aNode label]];
	[self addSubview:newButton];
	// line to parent:
	if (pos) {	// NULL if root, so no line
		newLine = [[Line alloc] init];
		[newLine setStart:pos end:&myCenter];
		[lineList addObject:newLine];
	}
	// now add any children and the lines to them.
	for (i=0; i<numBranches; i++) { // loop isn't entered if no kids.
		kid = [kids objectAt:i];
		treeWidth = [kid width];
		diff = (treeWidth * (BUTTONHEIGHT + VERTSPACING));
		[self buildTreeFromNode:kid bottom:accum
				top:(accum + diff + VERTSPACING)
				atX:(xpos + BUTTONWIDTH + HORIZSPACING)
				parent:&myCenter];
		accum += diff;
	}
	return self;
}

- attachTree:aTree
{
	int treeWidth = [aTree width];
	int treeDepth = [aTree depth];
	double height = (treeWidth * (BUTTONHEIGHT + VERTSPACING) + VERTSPACING);
	double width  = (treeDepth * (BUTTONWIDTH + HORIZSPACING) + HORIZSPACING);
	
	if (lineList) [[lineList freeObjects] free];
	lineList = [[List alloc] init];
	// resize the View to accomodate the Buttons
	[self sizeTo:width :height];
	[self buildTreeFromNode:aTree bottom:0.0 top:height atX:0.0 parent:NULL];

	return self;
}

- drawSelf:(NXRect *)rects :(int)rectCount  	// standard rendering method
{
    PSsetgray(NX_DKGRAY);
    NXRectFill(&bounds);
    PSsetgray(NX_BLACK);
    PSsetlinewidth(2.0);
	[lineList makeObjectsPerform:@selector(render)];
	return self;
}

@end
