//
//  EXPGraphComponent.m
//  Expression
//
//  Created by ashley on 01/01/2009.
//  Copyright 2009 __MyCompanyName__. All rights reserved.
//

#import "EXPGraphComponent.h"
#import "EXPModelObject.h"
#import "PLTMatrix.h"

/*

The next routine is shamelessly plagiarised from the nxyplot programme, by

Dennis Jespersen                  Tom Pulliam
jesperse@rft28.nas.nasa.gov       pulliam@rft29.nas.nasa.gov

Source code is at URL http://ftp.nice.ch/pub/next/science/mathematics/nxyplot.NIHS.bs.tar.gz

*/

void computeNiceLinInc(double *pmin, double *pmax, double *pinc)
{
	double fmin = *pmin, fmax = *pmax, finc = (fmax - fmin)/5.0, x;
	int n;

	if (finc <= 0.0) {
		fmin = (fmin>0.0? 0.9*fmin : 1.1*fmin);
		fmax = (fmax>0.0? 1.1*fmax : 0.9*fmax);
		finc = (fmax - fmin)/5.0;
    // for safety:
		if (finc < 0.0) {
/*			n = NSRunAlertPanel("computeNiceLinInc",
		      "Impossible increment = %g.\n"
		      "I'm very confused "
		      "(Perhaps all data is being ignored -- no lines, no symbols)",
		      "Quit", "Continue", NULL, finc);
			if (n==NX_ALERTDEFAULT)
				exit(0);
			else if (n==NX_ALERTALTERNATE) { */
			*pmin = 0.0;
			*pmax = 1.0;
			*pinc = 0.2;
			return;
//      }
		}
	}
	n = ( log10((double)finc) >= 0.0 ? (int)floor(log10((double)finc)) :
		(int)ceil(log10((double)finc)) );
	if (finc > 1.0) n++;
	x = finc * (float)pow((double)10.0, (double)(-n));
	finc = 0.1;
	if (x > 0.1)  finc = 0.2;
	if (x > 0.2)  finc = 0.25;
	if (x > 0.25) finc = 0.5;
	if (x > 0.5)  finc = 1.0;
	finc = finc * (float)pow((double)10.0, (double)n);

	if (fmin < ((int)(fmin/finc))*finc) fmin = ((int)(fmin/finc - 1))*finc;
	else                                fmin = ((int)(fmin/finc))*finc;

	if (fmax > ((int)(fmax/finc))*finc) fmax = ((int)(fmax/finc + 1))*finc;
	else                                fmax = ((int)(fmax/finc))*finc;

	*pmin = fmin;
	*pmax = fmax;
	*pinc = finc;
	return;
}

void drawMarker(int markerCode, NSRect rect)
{
	NSBezierPath *path = [[NSBezierPath alloc] init];
	
	float w = rect.size.width;
	float h = rect.size.height;
	float x = rect.origin.x - w/2.0;
	float y = rect.origin.y - h/2.0;
	
	if (markerCode==1) {
		[path moveToPoint:NSMakePoint(x,y)];
		[path relativeLineToPoint:NSMakePoint(w, h)];
		[path relativeMoveToPoint:NSMakePoint(-w, 0)];
		[path relativeLineToPoint:NSMakePoint(w, -h)];
		[path stroke];
	} else if (markerCode==2) {
		[path moveToPoint:NSMakePoint(x, y+h/2)];
		[path relativeLineToPoint:NSMakePoint(w,0)];
		[path relativeMoveToPoint:NSMakePoint(-w/2, h/2)];
		[path relativeLineToPoint:NSMakePoint(0, -h)];
		[path stroke];
	} else if (markerCode==3) {
		[path moveToPoint:NSMakePoint(x,y)];
		[path relativeLineToPoint:NSMakePoint(w, h)];
		[path relativeMoveToPoint:NSMakePoint(-w, 0)];
		[path relativeLineToPoint:NSMakePoint(w, -h)];
		[path moveToPoint:NSMakePoint(x, y+h/2)];
		[path relativeLineToPoint:NSMakePoint(w,0)];
		[path relativeMoveToPoint:NSMakePoint(-w/2, h/2)];
		[path relativeLineToPoint:NSMakePoint(0, -h)];
		[path stroke];
	} else if (markerCode==4) {
		[path moveToPoint:NSMakePoint(x, y+h/2)];
		[path relativeLineToPoint:NSMakePoint(w/2, h/2)];
		[path relativeLineToPoint:NSMakePoint(w/2, -h/2)];
		[path relativeLineToPoint:NSMakePoint(-w/2, -h/2)];
		[path closePath];
		[path fill];
	} else if (markerCode==5) {
		[path moveToPoint:NSMakePoint(x,y)];
		[path relativeLineToPoint:NSMakePoint(0, h)];
		[path relativeLineToPoint:NSMakePoint(w, 0)];
		[path relativeLineToPoint:NSMakePoint(0, -h)];
		[path closePath];
		[path fill];
	} else if (markerCode==6) {
		[path moveToPoint:NSMakePoint(x,y)];
		[path relativeLineToPoint:NSMakePoint(w/2, h)];
		[path relativeLineToPoint:NSMakePoint(w/2, -h)];
		[path closePath];
		[path fill];
	} else if (markerCode==7) {
		NSRect offsetRect = NSMakeRect(x, y, w, h);
		[path appendBezierPathWithOvalInRect:offsetRect];
		[path fill];
	}
	
	[path release];
}

@implementation EXPGraphComponent

- (id) componentType
{
	return @"Graph";
}

- (void) setFromElement:(NSXMLElement *)element
{
	[super setFromElement:element];
	
	NSArray *plots = [element elementsForName:@"plot"];
	int i;
	for(i=0; i<[plots count]; i++) {
		NSXMLElement *plotElement = [plots objectAtIndex:i];
		NSString *title = [[self getElementChild:@"title" forElement:plotElement] stringValue];
		[self setPlotTitle:title];
		NSString *xGrid = [[self getElementChild:@"xgrid" forElement:plotElement] stringValue];
		[self setXGrid:[xGrid isEqualToString:@"Yes"]];
		NSString *yGrid = [[self getElementChild:@"ygrid" forElement:plotElement] stringValue];
		[self setYGrid:[yGrid isEqualToString:@"Yes"]];
		NSString *abscissa = [[self getElementChild:@"abscissa" forElement:plotElement] stringValue];
		[self setXValueName:abscissa];
		NSString *autoscalex = [[self getElementChild:@"autoscalex" forElement:plotElement] stringValue];
		[self setAutoscaleX:[autoscalex isEqualToString:@"Yes"]];
		NSString *autoscaley = [[self getElementChild:@"autoscaley" forElement:plotElement] stringValue];
		[self setAutoscaleY:[autoscaley isEqualToString:@"Yes"]];
		
		NSMutableArray *lineNames = [[NSMutableArray alloc] init];
		NSArray *lines = [plotElement elementsForName:@"line"];
		int j;
		for(j=0; j<[lines count]; j++) {
			NSXMLElement *lineElement = [lines objectAtIndex:i];
			NSString *line = [lineElement stringValue];
			[lineNames addObject:line];
		}
		[self setYValueNames:lineNames];
		[lineNames release];
	}
}

- (void)  putToElement:(NSXMLElement *)element
{
	[super  putToElement:element];
	NSXMLElement *plotElement = [[NSXMLElement alloc] initWithName:@"plot"];
	[self putString:[self plotTitle] toElement:plotElement named:@"title"];
	[self putString:[self xGrid]?@"Yes":@"No" toElement:plotElement named:@"xgrid"];
	[self putString:[self yGrid]?@"Yes":@"No" toElement:plotElement named:@"ygrid"];
	[self putString:[self autoscaleX]?@"Yes":@"No" toElement:plotElement named:@"autoscalex"];
	[self putString:[self autoscaleY]?@"Yes":@"No" toElement:plotElement named:@"autoscaley"];
	[self putString:[self xValueName] toElement:plotElement named:@"abscissa"];
	
	NSArray *yValueNames = [self yValueNames];
	int i;
	for(i=0; i<[yValueNames count]; i++) {
		NSString *yValueName = [yValueNames objectAtIndex:i];
		[self putString:yValueName toElement:plotElement named:@"line"];
	}
	[plotElement release];
}

- (void) setYValueNames:(id)yValueNames
{
	[yValueNames retain];
	[_yValueNames release];
	_yValueNames = yValueNames;
}

- (id) yValueNames
{
	return _yValueNames;
}

- (void) setXValueName:(id)xValueName
{
	[xValueName retain];
	[_xValueName release];
	_xValueName = xValueName;
}

- (id) xValueName
{
	return _xValueName;
}

- (BOOL) autoscaleX
{
	return _autoscaleX;
}

- (void) setAutoscaleX:(BOOL)newAutoscaleX
{
	_autoscaleX = newAutoscaleX;
}

- (BOOL) autoscaleY
{
	return _autoscaleY;
}

- (void) setAutoscaleY:(BOOL)newAutoscaleY
{
	_autoscaleY = newAutoscaleY;
}

- (BOOL) xGrid
{
	return _xGrid;
}

- (void) setXGrid:(BOOL)newXGrid
{
	_xGrid = newXGrid;
}

- (BOOL) yGrid
{
	return _yGrid;
}

- (void) setYGrid:(BOOL)newYGrid
{
	_yGrid = newYGrid;
}

- (id)plotTitle
{
	return _plotTitle;
}

- (void) setPlotTitle:(id)newplotTitle
{
	[newplotTitle retain];
	[_plotTitle release];
	_plotTitle = newplotTitle;
}

- (id)xLabel
{
	return _xLabel;
}

- (void) setXLabel:(id)newXLabel
{
	[newXLabel retain];
	[_xLabel release];
	_xLabel = newXLabel;
}

- (id)yLabel
{
	return _yLabel;
}

- (void) setYLabel:(id)newYLabel
{
	[newYLabel retain];
	[_yLabel release];
	_yLabel = newYLabel;
}

- (int) legendPosition
{
	return _legendPosition;
}

- (void) setLegendPosition:(int)newLegendPosition
{
	_legendPosition = newLegendPosition;
}

- (void) drawInView:(id)view isSelected:(BOOL)flag
{
//	NSRect bounds = [self bounds];
	NSPoint pos = [self pos];
	float orig_x = pos.x;
	float orig_y = pos.y;
	NSSize size = [self size];
	float width = size.width;
	float height = size.height;
	NSRect bounds = NSMakeRect(orig_x, orig_y, width, height);
	
	[[NSColor whiteColor] set];
	[NSBezierPath fillRect:bounds];
	[[NSColor blackColor] set];
	[NSBezierPath strokeRect:bounds];
	
	EXPModelObject *modelObject = [self modelObject];
//	id ctrl = [_windowController plotter];
	PLTMatrix *matrix = [modelObject matrix];
	if (matrix==nil) {
		return;
	}
	
	NSArray *yValueNames = [self yValueNames];
	NSString *xValueName = [self xValueName];
	int nLines = [yValueNames count];
	int nPoints = [matrix rows];
	if ((nLines==0) || (nPoints==0)) {
		return;
	}
	
	double xmin = [[modelObject option:@"tstart"] doubleValue];
	double xmax = [[modelObject option:@"tstop"] doubleValue];
	if (xmin==xmax) {
		return;
	}

	NSArray *columnNames = [matrix columnHeadings];
	int xColumnIndex = [columnNames indexOfObject:xValueName];
	int *yColumnIndices = calloc(nLines, sizeof(int));
	int i;
	for(i=0; i<nLines; i++) {
/*		NSString *columnName = [columnNames objectAtIndex:i];
		if ([columnName isEqualToString:xValueName]) {
			xColumnIndex = i;
		}
		int j;
		for(j=0; j<nLines; j++) {
			if ([columnName isEqualToString:[yValueNames objectAtIndex:j]]) {
				yColumnIndices[i] = j;
				break;
			}
		}  */
		yColumnIndices[i] = [columnNames indexOfObject:[yValueNames objectAtIndex:i]];
	}
	
//	PLTMatrix *xPoints = [ctrl xPoints];
//	PLTMatrix *yPoints = [ctrl yPoints];
	double ymin;
	double ymax;
	[matrix minAndMaxValues:&ymin and:&ymax];

	double xinc = -1.0;
	if (xinc<=0.0) {
		xinc = (xmax - xmin)/2.0;
	}
	double yinc = -1.0;
	if ([self autoscaleX]) {
		computeNiceLinInc(&xmin, &xmax, &xinc);
	}

	if (yinc<=0.0) {
		yinc = (ymax - ymin)/2.0;
	}
	if ([self autoscaleY]) {
		computeNiceLinInc(&ymin, &ymax, &yinc);
	}
	
	NSMutableDictionary *attribs  = [modelObject textAttributes];
	
	float xleft = 0.0;
	float xright = 40.0;
	float ybottom = 0.0;
	float ytop = 15.0;
	float xSliver = 2.0;
	float ySliver = 2.0;
	
	int legendPosition = [self legendPosition];
	float legendWidth = 0.0;
	float legendHeight = 0.0;
	float legendTextHeight = 0.0;
	float legendTextWidth = 0.0;
	float xLegendOffset = 10.0;
	float yLegendOffset = 10.0;
	float legendLineLength = 20.0;
	
	if (legendPosition>0) {
		int j;
		for(j=0; j<nLines; j++) {
			NSString *lineTitle = [yValueNames objectAtIndex:j];
			NSSize titleSize = [lineTitle sizeWithAttributes:attribs];
			if ((legendPosition==5) || (legendPosition==6)) {
				legendWidth += titleSize.width + xSliver;
				if (titleSize.height>legendHeight) legendHeight = titleSize.height;
			} else {
				if (titleSize.width>legendWidth) legendWidth = titleSize.width;
				legendHeight += titleSize.height + ySliver;
			}
			if (titleSize.height>legendTextHeight) legendTextHeight = titleSize.height;
			if (titleSize.width>legendTextWidth) legendTextWidth = titleSize.width;
		}
		legendTextHeight += ySliver;
		legendTextWidth += xSliver + legendLineLength;
	}

	float xv;
	float xp;
	float yv;
	float yp;
	
	NSString *plotTitle = [self plotTitle];
	NSSize titleSize = [plotTitle sizeWithAttributes:attribs];
	ytop += titleSize.height;
	[plotTitle drawAtPoint:NSMakePoint(orig_x + width/2 - titleSize.width/2, orig_y/* + titleSize.height*/) withAttributes:attribs];

// Sort out y margins
	yv = ymin;
	while(yv<=ymax) {
		NSNumber *num = [[NSNumber alloc] initWithDouble:yv];
		NSString *string = [num stringValue];
		[num release];
		NSSize stringSize = [string sizeWithAttributes:attribs];
		if (stringSize.width>xleft) {
			xleft = stringSize.width;
		}
	
		yv += yinc;
	}
	
	NSSize yLabelSize = [[self yLabel]  sizeWithAttributes:attribs];
	xleft += yLabelSize.height + xSliver;
	
// Sort out x margins
	xv = xmin;
	while(xv<=xmax) {
		NSNumber *num = [[NSNumber alloc] initWithDouble:xv];
		NSString *string = [num stringValue];
		[num release];
		NSSize stringSize = [string sizeWithAttributes:attribs];
		if (stringSize.height>ybottom) {
			ybottom = stringSize.height;
		}
	
		xv += xinc;
	}
	
	NSSize xLabelSize = [[self xLabel] sizeWithAttributes:attribs];
	ybottom += xLabelSize.height;
	
	if (legendPosition==5) {
		height -= legendHeight + ySliver;
	}
	if (legendPosition==6) {
		height -= legendHeight + ySliver;
		orig_y += legendHeight + ySliver;
	}
	if (legendPosition==7) {
		width -= legendWidth + legendLineLength + xSliver;
		orig_x += legendWidth + legendLineLength + xSliver;
	}
	if (legendPosition==8) {
		width -= legendWidth + legendLineLength + xSliver;
	}

// Now actually draw the labels
	yv = ymin;
	while(yv<=ymax) {
		yp = orig_y - (height - ytop - ybottom)*(yv - ymin)/(ymax - ymin) + height - ytop;
		NSNumber *num = [[NSNumber alloc] initWithDouble:yv];
		NSString *string = [num stringValue];
		[num release];
		[string drawAtPoint:NSMakePoint(orig_x + yLabelSize.height, yp) withAttributes:attribs];
		yv += yinc;
	}
	
	xv = xmin;
	float labely = orig_y + height - ytop;
	while(xv<=xmax) {
		xp =  orig_x + (width - xright - xleft)*(xv - xmin)/(xmax - xmin) + xleft;
		NSNumber *num = [[NSNumber alloc] initWithDouble:xv];
		NSString *string = [num stringValue];
		[num release];
		[string drawAtPoint:NSMakePoint(xp, labely/*orig_y + xLabelSize.height*/) withAttributes:attribs];
		xv += xinc;
	}
	
	float ww =  xLabelSize.width;
	[[self xLabel] drawAtPoint:NSMakePoint(orig_x + (width - ww)/2.0, orig_y) withAttributes:attribs];
	
	NSPoint pt = NSMakePoint(orig_x, orig_y + (height - yLabelSize.height)/2.0);
	NSSize yLabelStringSize = [[self yLabel] sizeWithAttributes:attribs];
	NSGraphicsContext *context = [NSGraphicsContext currentContext];
	NSAffineTransform *transform = [NSAffineTransform transform];
	[transform rotateByDegrees:90.0];
	[transform translateXBy:(pt.y - pt.x) yBy:(-pt.y - pt.x - yLabelStringSize.height)];
	[context saveGraphicsState];
	[transform concat];
	[view lockFocus];
	[[self yLabel] drawAtPoint:pt withAttributes:attribs]; 
	[view unlockFocus];
	[context restoreGraphicsState];
		
	[[NSColor blackColor] set];
	NSRect borderRect = NSMakeRect(orig_x+xleft, orig_y+ybottom, width-xleft-xright, height-ybottom-ytop);
	[NSBezierPath strokeRect:borderRect];
	
	float dashPattern[2];
	dashPattern[0] = 4.0;
	dashPattern[1] = 6.0;

	if ([self xGrid]) {
		xv = xmin + xinc;
		while(xv<xmax) {
			xp =  orig_x + (width - xright - xleft)*(xv - xmin)/(xmax - xmin) + xleft;

			NSBezierPath *path = [[NSBezierPath alloc] init];
		
			[path moveToPoint:NSMakePoint(xp, orig_y + ybottom)];
			[path lineToPoint:NSMakePoint(xp, orig_y + height - ytop)];
	
			[path setLineDash:dashPattern count:2 phase:0.0];

			[path stroke];
			[path release];
		
			xv += xinc;
		}
	}

	if ([self yGrid]) {
		yv = ymin + yinc;
		while(yv<ymax) {
			yp = orig_y - (height - ytop - ybottom)*(yv - ymin)/(ymax - ymin) + height - ytop;

			NSBezierPath *path = [[NSBezierPath alloc] init];
		
			[path moveToPoint:NSMakePoint(orig_x + xleft, yp)];
			[path lineToPoint:NSMakePoint(orig_x + width - xright, yp)];
	
			[path setLineDash:dashPattern count:2 phase:0.0];

			[path stroke];
			[path release];
		
			yv += yinc;
		}
	}
	
	xv = xmin;
	while(xv<xmax) {
		xp =  orig_x + (width - xright - xleft)*(xv - xmin)/(xmax - xmin) + xleft;
		NSString *tickLabel = [[NSString alloc] initWithFormat:@"%f", xv];
		
		[tickLabel release];

		xv += xinc;
	}

// Draw	the lines
	int j;
	for(j=0; j<nLines; j++) {
		if ([modelObject lineStyleForLine:j]>0) {
			NSBezierPath *path = [[NSBezierPath alloc] init];
			BOOL notPlotted = YES;
			int i;
			for(i=0; i<nPoints; i++) {
				float xv = [matrix cellAtRow:i andCol:xColumnIndex];
				float xp =  orig_x + (width - xright - xleft)*(xv - xmin)/(xmax - xmin) + xleft;
		
				float yv = [matrix cellAtRow:i andCol:yColumnIndices[j]];
//				float yp = orig_y + (height - ytop - ybottom)*(yv - ymin)/(ymax - ymin) + ybottom;
				float yp = orig_y - (height - ytop - ybottom)*(yv - ymin)/(ymax - ymin)  + height - ytop;
//				yp = height - yp;
				
				if ((xv>=xmin) && (xv<=xmax) && (yv>=ymin) && (yv<=ymax)) {
					if (notPlotted) {
						[path moveToPoint:NSMakePoint(xp, yp)];
						notPlotted = NO;
					} else {
						[path lineToPoint:NSMakePoint(xp, yp)];
					}
				}
			}
			
			if ([modelObject lineStyleForLine:j]==2) {
				float dashPattern[2];
				dashPattern[0] = 4.0;
				dashPattern[1] = 6.0;
				[path setLineDash:dashPattern count:2 phase:0.0];
			} else if ([modelObject lineStyleForLine:j]==3) {
				float dashPattern[2];
				dashPattern[0] = 2.0;
				dashPattern[1] = 2.0;
				[path setLineDash:dashPattern count:2 phase:0.0];
			}
		
			NSColor *colour = [modelObject lineColourForLine:j];
			[colour set]; 
			
			float thickness = [modelObject lineThicknessForLine:j];
			[path setLineWidth:thickness];

			[path stroke];
			[path release]; 
		}
	}

// Now draw the markers	
	for(j=0; j<nLines; j++) {
		[[modelObject markerColourForLine:j] set];
		
		int i;
		for(i=0; i<nPoints; i++) {
			float xv = [matrix cellAtRow:i andCol:xColumnIndex];
			float xp = orig_x + (width - xright - xleft)*(xv - xmin)/(xmax - xmin) + xleft;
			float yv = [matrix cellAtRow:i andCol:yColumnIndices[j]];
			float yp = orig_y - (height - ytop - ybottom)*(yv - ymin)/(ymax - ymin) + height - ytop;
//			yp = height - yp;

			if ((xv>=xmin) && (xv<=xmax) && (yv>=ymin) && (yv<=ymax)) {
				int markerStyle = [modelObject markerStyleForLine:j];
				float w = [modelObject markerSizeForLine:j];
				drawMarker(markerStyle, NSMakeRect(xp, yp, w, w));
			}
		}
	}

// Draw the legend.	
	float xStep;
	float yStep;
	switch (legendPosition) 
	{
// Top left
		case 1:
			xp = orig_x + xleft + xLegendOffset;
			yp = orig_y + height - ytop - legendHeight - yLegendOffset;
			xStep = 0.0;
			yStep = legendTextHeight;
			break;
// Bottom left
		case 2:
			xp = orig_x + xleft + xLegendOffset;
			yp = orig_y + ybottom + yLegendOffset;
			xStep = 0.0;
			yStep = legendTextHeight;
			break;
// Top Right
		case 3:
			xp = orig_x + width - xright - legendWidth - legendLineLength - xLegendOffset;
			yp = orig_y + height - ytop - legendHeight - yLegendOffset;
			xStep = 0.0;
			yStep = legendTextHeight;
			break;
// Bottom Right
		case 4:
			xp = orig_x + width - xright - legendWidth - legendLineLength - xLegendOffset;
			yp = orig_y + ybottom + yLegendOffset;
			xStep = 0.0;
			yStep = legendTextHeight;
			break;
// Outside Top
		case 5:
//			xp = orig_x + (width - legendTextWidth*nLines)/2.0;
			xp = orig_x + (width + legendTextWidth*nLines)/2.0;
			yp =  height - titleSize.height - legendTextHeight;
			xStep = -(legendTextWidth + legendLineLength);
			yStep = 0.0;
			break;
// Outside Bottom
		case 6:
			xp = orig_x + (width + legendTextWidth*nLines)/2.0;
			yp =  orig_y - legendTextHeight;
			xStep = -(legendTextWidth + legendLineLength);
			yStep = 0.0;
			break;
// Outside left
		case 7:
			xp = bounds.origin.x + xSliver;
			yp = orig_y + height - ytop - legendHeight - yLegendOffset;
			xStep = 0.0;
			yStep = legendTextHeight;
			break;
// Outside right
		case 8:
			xp = orig_x + width/* + xLegendOffset */;
			yp = orig_y + height - ytop - legendHeight - yLegendOffset;
			xStep = 0.0;
			yStep = legendTextHeight;
			break;
	}
	
	if (legendPosition>0) {
		int i;
		for(i=nLines-1; i>=0; i--) {
			NSString *legendTitle = [yValueNames objectAtIndex:i];
			[legendTitle drawAtPoint:NSMakePoint(xp + legendLineLength, yp) withAttributes:attribs];
			NSBezierPath *path = [[NSBezierPath alloc] init];
			[path moveToPoint:NSMakePoint(xp, yp + legendTextHeight/2.0)];
			[path lineToPoint:NSMakePoint(xp + legendLineLength, yp + legendTextHeight/2.0)];
			[[modelObject lineColourForLine:i] set];
			[path stroke];
			[path release];
			[[modelObject markerColourForLine:i] set];
			float w = [modelObject markerSizeForLine:i];
			drawMarker([modelObject markerStyleForLine:i], NSMakeRect(xp + legendLineLength/2.0, yp + legendTextHeight/2.0, w, w));
			xp += xStep;
			yp += yStep;
		}
	}
	
	free(yColumnIndices);

}

@end