//
//  EXPComponent.m
//  Expression
//
//  Created by ashley on 15/11/2008.
//  Copyright 2008 __MyCompanyName__. All rights reserved.
//

#import "EXPComponent.h"
#import "EXPConnectorComponent.h"
#import "EXPModelObject.h"
#import "EXPDocument.h"
#import "EXPModelView.h"
#import "EXPSymbolTable.h"
#import "EXPParser.h"

NSPoint EXPNearestPointOnUnitSquareToPoint(float x, float y)
{
	float xs;
	float ys;
	
	if ((fabs(x)<0.01) && (fabs(y)<0.001)) {
		xs = 0.0;
		ys = 1.0;
	} else if((x>=1.0) && (y>=1.0)) {
		xs = 1.0;
		ys = 1.0;
	} else if((x>=1.0) && (y<=-1.0)) {
		xs = 1.0;
		ys = -1.0;
	} else if((x<=-1.0) && (y>=1.0)) {
		xs = -1.0;
		ys = 1.0;
	} else if((x<=-1.0) && (y<=-1.0)) {
		xs = -1.0;
		ys = -1.0;
	} else if ((y>=x) && (y>=-x)) {
		xs = x;
		ys = 1.0;
	} else if ((y>=x) && (y<=-x)) {
		xs =-1.0;
		ys = y;
	} else if ((y<=x) && (y>=-x)) {
		xs = 1.0;
		ys = y;
	} else if ((y<=x) && (y<=-x)) {
		xs = x;
		ys = -1.0;
	} else {
		printf("nearestPointOnUnitSquareToPoint:= !!!!!\n");
	}

	return NSMakePoint(xs, ys);
}

@implementation EXPComponent

- (id) init
{
	if ((self = [super init]) != nil) {
		_inputs = [[NSMutableArray alloc] init];
		_outputs = [[NSMutableArray alloc] init];
		_namePosition = nil;
	}
	return self;
}

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

- (void) setName:(id)name
{
	[name retain];
	[_name release];
	_name = name;
}

- (id) name
{
	return _name;
}

- (id) displayName
{
	NSMutableString *name = [[NSMutableString alloc] initWithString:[self name]];
	[name replaceOccurrencesOfString:@" " withString:@"_" options:0 range:NSMakeRange(0, [name length])];
	
	return name;
}

- (void) setPosition:(NSPoint)pos
{
	_pos = pos;
//	[self computePath];
	[self setPath:nil];
}

- (NSPoint) pos
{
	return _pos;
}

- (void) setSize:(NSSize)size
{
	_size = size;
//	[self computePath];
	[self setPath:nil];
}

- (NSSize) size
{
	NSSize size = _size;
	if (abs(size.width)<0.001 || abs(size.height)<0.001) {
		EXPModelObject *modelObject = [self modelObject];
		NSDictionary *defaults = [modelObject defaults];
		NSString *type = [self componentType];
		NSString *key = [type stringByAppendingString:@"Size"];
		NSArray *array = [defaults objectForKey:key];
		float width = [[array objectAtIndex:0] floatValue];
		float height = [[array objectAtIndex:1] floatValue];
		size = NSMakeSize(width, height);
	}
	return size;
}

- (void) setDocument:(id)document
{
//	NSLog(@"Changing document string of %@ to \"%@\".", [self name], document);
	[document retain];
	[_document release];
	_document = document;
}

- (id) document
{
//	NSLog(@"Getting document string of %@ as \"%@\".", [self name], _document);
	return _document;
}

- (void) setDefinition:(id)definition
{
	[definition retain];
	[_definition release];
	_definition = definition;
}

- (id) definition
{
	return _definition;
}

- (void) setDefinitionFromString:(NSString *)definitionString
{
	EXPParser *parser = [[EXPParser alloc] init];
	[parser setString:[definitionString stringByAppendingString:@"\n"]];
	[parser setEcho:YES];
	NSMutableArray *array = [[NSMutableArray alloc] init];
	BOOL success = YES;
	
	while (![parser isEndOfFile]) {
//		printf("%s\n", [[parser symbol] UTF8String]);
		NSString *symbol = [parser symbol];
		if ([parser isLiteral]) {
			NSNumber *num = [[NSNumber alloc] initWithDouble:[symbol doubleValue]];
			[array addObject:num];
			[num release];
		} else if ([parser isIdentifier]) {
			int i;
			EXPComponent *component = nil;
//			NSString *symbol = [parser symbol];
			NSArray *inputs = [self inputComponents];
			for(i=0; i<[inputs count]; i++) {
				EXPComponent *input = [inputs objectAtIndex:i];
				NSString *name = [input displayName];
				if ([name isEqualToString:symbol]) {
					component = input;
				} else if ([symbol isEqualToString:[self name]]) {
					component = self;
					break;
				}
			}
			if (component!=nil) {
				[array addObject:component];
			} else {
				success = NO;
			}
		} else {
			NSString *ident = [[NSString alloc] initWithString:symbol];
			[array addObject:ident];
			[ident release];
		}
		[parser readSymbol];
	}
	
	if (success) {
		[self setDefinition:array];
	}
	
	[array release];
	[parser release];
}

- (id) definitionAsString
{
	NSMutableString *definitionString = [[[NSMutableString alloc] init] autorelease];
	NSArray *definition = [self definition];
	int i;
	for(i=0; i<[definition count]; i++) {
		NSObject *object = [definition objectAtIndex:i];
		if ([object isKindOfClass:[NSNumber class]]) {
			[definitionString appendString:[(NSNumber *)object stringValue]];
		} else if ([object isKindOfClass:[EXPComponent class]]) {
			[definitionString appendString:[(EXPComponent *)object displayName]];
		} else if ([object isKindOfClass:[NSString class]]) {
			[definitionString appendString:(NSString *)object];
		}
	}
	
	return definitionString;
}

- (BOOL) process:(id)symbolTable
{
	BOOL success = YES;
	
	NSMutableArray *definition = [self definition];
	int i;
	for (i=0; i<[definition count]; i++) {
		NSDictionary *dict = [definition objectAtIndex:i];
		NSString *name = [dict objectForKey:@"name"];
		NSString *string = [dict objectForKey:@"value"];
		if ([name isEqualToString:@"tkn"]) {
			EXPComponent *component = [symbolTable symbolForName:string];
			if (component!=nil) {
				[definition replaceObjectAtIndex:i withObject:component];
			} else {
				success = NO;
				break;
			}
		} else if ([name isEqualToString:@"op"]) {
			[definition replaceObjectAtIndex:i withObject:string];
		} else if ([name isEqualToString:@"lit"]) {
			double value = [string doubleValue];
			NSNumber *num = [[NSNumber alloc] initWithDouble:value];
			[definition replaceObjectAtIndex:i withObject:num];
			[num release];
		}
	}
	
	NSMutableArray *inputs = [self inputs];
	if (inputs!=nil) {
		int j;
		for(j=0; i<[inputs count]; j++) {
			NSString *inputName = [inputs objectAtIndex:j];
			EXPComponent *component = [symbolTable symbolForName:inputName];
			if (component==nil) {
				NSLog(@"Ooops!");
			} else {
				[inputs replaceObjectAtIndex:j withObject:component];
			}
		}
	}
	
//	NSLog(@"%@", [self definitionAsString]);
	
	return success;
}

- (void) setInputs:(id)inputs
{
	[inputs retain];
	[_inputs release];
	_inputs = inputs;
}

- (id) inputs
{
	return _inputs;
}

- (id) inputComponents
{
	NSMutableArray *array = [NSMutableArray array];
	NSArray *inputs = [self inputs];
	
	int i;
	for(i=0; i<[inputs count]; i++) {
		EXPConnectorComponent *connector = [inputs objectAtIndex:i];
		[array addObject:[connector start]];
	}
	
	return array;
}

- (void) setOutputs:(id)outputs
{
	[outputs retain];
	[_outputs release];
	_outputs = outputs;
}

- (id) outputs
{
	return _outputs;
}

- (void) setConnectedComponents:(id)connectedComponents
{
	[connectedComponents retain];
	[_connectedComponents release];
	_connectedComponents = connectedComponents;
}

- (id) connectedComponents
{
	return _connectedComponents;
}

- (void) addObjectsForDeletionTo:(id)array
{
	int i;
	NSArray *inputs = [self inputs];
	for(i=0; i<[inputs count]; i++) {
		EXPConnectorComponent *component = [inputs objectAtIndex:i];
		if (![array containsObject:component]) {
			[component unlinkFromConnections];
			[array addObject:component];
		}
	}
	
	NSArray *outputs = [self outputs];
	for(i=0; i<[outputs count]; i++) {
		EXPConnectorComponent *component = [outputs objectAtIndex:i];
		if (![array containsObject:component]) {
			[component unlinkFromConnections];
			[array addObject:component];
		}
	}
	
}

- (void) removeOutput:(id)component
{
	NSMutableArray *outputs = [self outputs];
	[outputs removeObject:component];
}

- (void) removeInput:(id)component
{
	NSMutableArray *inputs = [self inputs];
	[inputs removeObject:component];
}

- (id) getElementChild:(NSString *)name forElement:(NSXMLElement *)element
{
	NSArray *children = [element elementsForName:name];
	id ans = nil;
	if ([children count]>0) {
		ans = [children objectAtIndex:0];
	}
	
	return ans;
}

- (NSSize) getSizeFromElement:(NSXMLElement *)element
{
	float w = [[[self getElementChild:@"w" forElement:element] stringValue] floatValue];
	float h = [[[self getElementChild:@"h" forElement:element] stringValue] floatValue];
	NSSize size = NSMakeSize(w,h);
	
	return size;
}


- (NSPoint) getPointFromElement:(NSXMLElement *)element
{
	float x = [[[self getElementChild:@"x" forElement:element] stringValue] floatValue];
	float y = [[[self getElementChild:@"y" forElement:element] stringValue] floatValue];
	NSPoint point = NSMakePoint(x,y);
	
	return point;
}

- (void) setFromElement:(NSXMLElement *)element
{
	NSArray *array = [element elementsForName:@"name"];
	if ([array count]>0) {
		NSString *name = [[array objectAtIndex:0] stringValue];
//		NSLog(@"%@: %@", [[self class] description], name);
		[self setName:name];
	}
	
//	NSXMLElement *pos = [[element elementsForName:@"pos"] objectAtIndex:0];
	NSXMLElement *pos = [self getElementChild:@"pos" forElement:element];
/*	float x = [[[[pos elementsForName:@"x"] objectAtIndex:0] stringValue] floatValue];
	float y = [[[[pos elementsForName:@"y"] objectAtIndex:0] stringValue] floatValue];
	NSPoint point = NSMakePoint(x,y); */
	if (pos!=nil){
		NSPoint point = [self getPointFromElement:pos];
		[self setPosition:point];
	}

	NSXMLElement *sizeElement = [self getElementChild:@"size" forElement:element];
	if (sizeElement!=nil){
		NSSize size = [self getSizeFromElement:sizeElement];
		[self setSize:size];
	}

	NSXMLElement *documentElement = [self getElementChild:@"doc" forElement:element];
	if (documentElement!=nil) {
		NSString *document = [documentElement stringValue];
		[self setDocument:document];
//		NSLog(@"%@", document);
	}

	NSXMLElement *expressionElement = [self getElementChild:@"def" forElement:element];
	if (expressionElement!=nil) {
		NSArray *expressions = [expressionElement children];
		NSMutableArray *exprList = [[NSMutableArray alloc] init];
		int i;
		for(i=0; i<[expressions count]; i++) {
			NSXMLElement *expression = [expressions objectAtIndex:i];
			NSString *name = [expression name];
			NSString *str = [expression stringValue];
			NSDictionary *dict = [[NSDictionary alloc] initWithObjectsAndKeys:
				str, @"value", 
				name, @"name", 
				nil];
			[exprList addObject:dict];
			[dict release]; 
//			[exprList addObject:str];
		}
		[self setDefinition:exprList];
//		NSLog(@"%@", exprList);
		[exprList release];
	}

	/*NSXMLElement * */pos = [self getElementChild:@"endpos" forElement:element];
	if (pos!=nil) {
		NSPoint point = [self getPointFromElement:pos];
		[self setPosition2:point];
	}

	NSXMLElement *cv1 = [self getElementChild:@"controlvector1" forElement:element];
	if (cv1!=nil) {
		NSPoint point = [self getPointFromElement:cv1];
		[self setControlvector:point];
	}

	NSXMLElement *cv2 = [self getElementChild:@"controlvector2" forElement:element];
	if (cv2!=nil) {
		NSPoint point = [self getPointFromElement:cv2];
		[self setControlvector2:point];
	}

	NSArray *inputs = [element elementsForName:@"input"];
	int i;
	for(i=0; i<[inputs count]; i++) {
		NSXMLElement *inputElement = [inputs objectAtIndex:i];
		[[self inputs] addObject:[inputElement stringValue]];
//		NSLog(@"Input = %@", [inputElement stringValue]);
	}

	NSArray *outputs = [element elementsForName:@"output"];
	for(i=0; i<[outputs count]; i++) {
		NSXMLElement *outputElement = [outputs objectAtIndex:i];
		[[self outputs] addObject:[outputElement stringValue]];
//		NSLog(@"Output = %@", [outputElement stringValue]);
	}

}

- (void) putString:(NSString *)string toElement:(NSXMLElement *)element named:(NSString *)name
{
	if ((string!=nil) && ([string length]>0)) {
		NSXMLElement *newElement = [[NSXMLElement alloc] init];
		[newElement setName:name];
		[newElement setStringValue:string];
		[element addChild:newElement];
		[newElement release];
	}
}

- (void) putPoint:(NSPoint)point toElement:(NSXMLElement *)element named:(NSString *)name
{
	NSXMLElement *newElement = [[NSXMLElement alloc] init];
	[newElement setName:name];

	NSString *string = [[NSString alloc] initWithFormat:@"%g", point.x];
	[self putString:string toElement:newElement named:@"x"];
	[string release];

	string = [[NSString alloc] initWithFormat:@"%g", point.y];
	[self putString:string toElement:newElement named:@"y"];
	[string release];

	[element addChild:newElement];
	[newElement release];
}

- (void)  putToElement:(NSXMLElement *)element
{
	[element setName:@"component"];

/*	NSXMLElement *name = [[NSXMLElement alloc] init];
	[name setName:@"name"];
	[name setStringValue:[self name]];
	[element addChild:name];
	[name release]; */
	[self putString:[self name] toElement:element named:@"name"];
	[self putString:[self componentType] toElement:element named:@"type"];
	[self putPoint:[self pos] toElement:element named:@"pos"];
	[self putPoint:[self pos2] toElement:element named:@"endpos"];
	[self putPoint:[self controlVector] toElement:element named:@"controlvector1"];
	[self putPoint:[self controlVector2] toElement:element named:@"controlvector2"];
//	Size?
	
	NSString *doc = [self document];
	if ((doc!=nil) && ([doc length]>0)) {
		[self putString:doc toElement:element named:@"doc"];
	}
	
	NSArray *definition = [self definition];
	NSXMLElement *definitionElement = [[NSXMLElement alloc] init];
	[definitionElement setName:@"def"];	
	if (definition!=nil) {
		int i;
		for(i=0; i<[definition count]; i++) {
			NSObject *value = [definition objectAtIndex:i];
			if ([value isKindOfClass:[EXPComponent class]]) {
				EXPComponent *component = (EXPComponent *)value;
				[self putString:[component name] toElement:definitionElement named:@"tkn"];
			} else if ([value isKindOfClass:[NSNumber class]]) {
				NSNumber *num = (NSNumber *)value;
				[self putString:[num stringValue] toElement:definitionElement named:@"lit"];
			} else if ([value isKindOfClass:[NSString class]]) {
				NSString *string = (NSString *)value;
				[self putString:string toElement:definitionElement named:@"op"];
			} else {
			}
		}
		[element addChild:definitionElement];
		[definitionElement release];

	}
	
}

- (void) setPosition2:(NSPoint)pos2
{
	_pos2 = pos2;
	[self setPath:nil];
}

- (NSPoint) pos2
{
	return _pos2;
}

- (void) setControlvector:(NSPoint)vec
{
	_controlVector = vec;
	[self setPath:nil];
}

- (NSPoint) controlVector
{
	return _controlVector;
}

- (void) setControlvector2:(NSPoint)vec
{
	_controlVector2 = vec;
	[self setPath:nil];
}

- (NSPoint) controlVector2
{
	return _controlVector2;
}

- (void) setNamePosition:(id)namePosition
{
	[namePosition retain];
	[_namePosition release];
	_namePosition = namePosition;
}

- (id) namePosition
{
	if (_namePosition==nil) {
		EXPModelObject *modelObject = [self modelObject];
		NSDictionary *defaults = [modelObject defaults];
		_namePosition = [defaults objectForKey:@"namePosition"];
	}
	
	return _namePosition;
}

- (void) setModelObject:(id)model
{
	_modelObject = model;
}

- (id) modelObject
{
	return _modelObject;
}

- (NSRect) drawingBounds
{
	return NSMakeRect(0.0, 0.0, 0.0, 0.0);
}

- (BOOL) containsPoint:(NSPoint)point
{
	return NO;
}

- (void) setControlPointSelected:(int)controlPointSelected
{
	_controlPointSelected = controlPointSelected;
}

- (int) controlPointSelected
{
	return _controlPointSelected;
}

- (BOOL) controlAreaContainsPoint:(NSPoint)point
{
	return NO;
}

- (NSPoint) normalVectorForPoint:(NSPoint)point length:(float)length
{
	return NSMakePoint(0.0, 0.0);
}

- (NSPoint) closestSurfacePointToPoint:(NSPoint)point
{
	return NSMakePoint(0.0, 0.0);
}

- (BOOL) acceptsInputs
{
	return NO;
}

- (BOOL) acceptsOutputs
{
	return NO;
}

- (BOOL) acceptsInFlows
{
	return NO;
}

- (BOOL) acceptsOutFlows
{
	return NO;
}

- (void) dump
{
	printf("Name = \"%s\" type = %s\n", [[self name] UTF8String], [[self componentType] UTF8String]);
	printf("Definition = %s\n", [[self definitionAsString] UTF8String]);

	NSPoint pos = [self pos];
	printf("Position = (%g,%g)\n", pos.x, pos.y);
	NSPoint pos2 = [self pos2];
	printf("Position2 = (%g,%g)\n", pos2.x, pos2.y);
	NSSize size = [self size];
	printf("Size = (%g,%g)\n", size.width, size.height);

	NSPoint cv1 = [self controlVector];
	printf("Control vector 1 = (%g,%g)\n", cv1.x, cv1.y);
	NSPoint cv2 = [self controlVector2];
	printf("Control vector 2 = (%g,%g)\n", cv2.x, cv2.y);

	int i;
	NSArray *inputs = [self inputs];
	int n = [inputs count];
	if (n>0) {
		printf("Inputs\n");
		for(i=0; i<n; i++) {
			EXPConnectorComponent *input = [inputs objectAtIndex:i];
			printf("\t%s <-- %s\n", [[input name] UTF8String], [[[input start] name] UTF8String]);
		}
	}
	
	NSArray *outputs = [self outputs];
	n = [outputs count];
	if (n>0) {
		printf("Outputs\n");
		for(i=0; i<n; i++) {
			EXPConnectorComponent *output = [outputs objectAtIndex:i];
			printf("\t%s --> %s\n", [[output name] UTF8String], [[[output end] name] UTF8String]);
		}
	}
	
}

- (void) moveComponentTo:(NSPoint)point inView:(id)view
{
/*	NSPoint pos = [self pos];
	[self setPosition:NSMakePoint(pos.x + change.x, pos.y + change.y)];
	NSPoint pos2 = [self pos2];
	[self setPosition2:NSMakePoint(pos2.x + change.x, pos2.y + change.y)]; */

	int controlPoint = [self controlPointSelected];
	if (controlPoint==0) {
		NSPoint lastPoint = [view lastPoint];
//		printf("Got control point %d. Last point = %s\n", controlPoint, [NSStringFromPoint(lastPoint) UTF8String]);
		NSPoint oldPosition = [self pos];
		NSPoint oldPosition2 = [self pos2];
		NSPoint positionChange = NSMakePoint(point.x - lastPoint.x, point.y - lastPoint.y);
		NSPoint newPosition = NSMakePoint(positionChange.x + oldPosition.x, positionChange.y + oldPosition.y);
		NSPoint newPosition2 = NSMakePoint(positionChange.x + oldPosition2.x, positionChange.y + oldPosition2.y);
		[self setPosition:newPosition];
		[self setPosition2:newPosition2];
		[self moveConnectedComponentsBy:positionChange];
		[view setLastPoint:point];
	} else if (controlPoint==1) {
//		printf("Got control point %d\n", controlPoint);
		NSPoint pos = [self pos];
		NSPoint newControlVector = NSMakePoint(point.x - pos.x, point.y - pos.y);
		[self setControlvector:newControlVector];
	} else if (controlPoint==2) {
//		printf("Got control point %d\n", controlPoint);
		NSPoint pos2 = [self pos2];
		NSPoint newControlVector = NSMakePoint(-point.x + pos2.x, -point.y + pos2.y);
		[self setControlvector2:newControlVector];
	} else if (controlPoint==3) {
//		printf("Got control point %d\n", controlPoint);
		EXPFlowComponent *component = (EXPFlowComponent *)self;
		EXPComponent *startComponent = [component start];
		NSPoint nearestPoint = [startComponent closestSurfacePointToPoint:point];
		[component setPosition:nearestPoint];
	} else if (controlPoint==4) {
//		printf("Got control point %d\n", controlPoint);
		EXPFlowComponent *component = (EXPFlowComponent *)self;
		EXPComponent *endComponent = [component end];
		NSPoint nearestPoint = [endComponent closestSurfacePointToPoint:point];
		[component setPosition2:nearestPoint];
	} else {
	}
}

- (void) moveConnectedComponentsBy:(NSPoint)change
{
	EXPModelObject *modelObject = [self modelObject];
	NSSet *selection = [modelObject selection];
	NSArray *inputs = [self inputs];
	int i;
	for(i=0; i<[inputs count]; i++) {
		EXPComponent *input = [inputs objectAtIndex:i];
		if (![selection containsObject:input]) {
			NSPoint pos2 = [input pos2];
			[input setPosition2:NSMakePoint(pos2.x + change.x, pos2.y + change.y)];
		}
	}

	NSArray *outputs = [self outputs];
	for(i=0; i<[outputs count]; i++) {
		EXPComponent *output = [outputs objectAtIndex:i];
		if (![selection containsObject:output]) {
			NSPoint pos = [output pos];
			[output setPosition:NSMakePoint(pos.x + change.x, pos.y + change.y)];
		}
	}
	
/*	if ([component isKindOfClass:[EXPStockComponent class]]) {
		EXPStockComponent *stock = (EXPStockComponent *)component;
		NSArray *inflows = [stock inflows];
		for(i=0; i<[inflows count]; i++) {
			EXPComponent *inflow = [inflows objectAtIndex:i];
			if (![selection containsObject:inflow]) {
				 [self moveFlow:(EXPFlowComponent *)inflow by:change moveStart:NO];
			}
		}

		NSArray *outflows = [stock outflows];
		for(i=0; i<[outflows count]; i++) {
			EXPComponent *outflow = [outflows objectAtIndex:i];
			if (![selection containsObject:outflow]) {
				 [self moveFlow:(EXPFlowComponent *)outflow by:change moveStart:YES];
			}
		}
	} else if ([[component componentType] isEqualToString:@"Flow"]) {
		EXPFlowComponent *flow = (EXPFlowComponent *)component;
		EXPStockComponent *start = [flow start];
		if ((start!=nil) && ![selection containsObject:start]) {
			NSPoint pos = [start pos];
			[start setPosition:NSMakePoint(pos.x + change.x, pos.y + change.y)];
			NSPoint pos2 = [start pos2];
			[start setPosition2:NSMakePoint(pos2.x + change.x, pos2.y + change.y)];
		}
		EXPStockComponent *end = [flow end];
		if ((end!=nil) && ![selection containsObject:end]) {
			NSPoint pos = [end pos];
			[end setPosition:NSMakePoint(pos.x + change.x, pos.y + change.y)];
			NSPoint pos2 = [end pos2];
			[end setPosition2:NSMakePoint(pos2.x + change.x, pos2.y + change.y)];
		}
	} */

}

- (void) setPath:(id)path
{
	[path retain];
	[_path release];
	_path = path;
}

- (void) computePath
{
}

- (id)path
{
	return _path;
}

- (id) arrowHeadAt:(NSPoint)pos inDirection:(NSPoint)cv size:(NSSize)size
{
	float x = pos.x;
	float y = pos.y;
	float cvx = cv.x;
	float cvy = cv.y;

	float hypotenuse = hypot(cvx, cvy);
	float nx = cvx/hypotenuse;
	float ny = -cvy/hypotenuse;
	float w = size.width;
	float h = size.height;
	NSBezierPath *path = [[NSBezierPath alloc] init];
	[path moveToPoint:NSMakePoint(x, y)];
	[path lineToPoint:NSMakePoint(x - w*nx + h*ny, y + w*ny + h*nx)];
	[path lineToPoint:NSMakePoint(x - w*nx - h*ny, y + w*ny - h*nx)];
	[path closePath];
//	[[NSColor blackColor] set];
//	[path fill];
	return [path autorelease];
}

- (void) drawArrowheadAt:(NSPoint)pos inDirection:(NSPoint)cv size:(NSSize)size
{
	float x = pos.x;
	float y = pos.y;
	float cvx = cv.x;
	float cvy = cv.y;

	float hypotenuse = hypot(cvx, cvy);
	float nx = cvx/hypotenuse;
	float ny = -cvy/hypotenuse;
	float w = size.width;
	float h = size.height;
	NSBezierPath *path = [[NSBezierPath alloc] init];
	[path moveToPoint:NSMakePoint(x, y)];
	[path lineToPoint:NSMakePoint(x - w*nx + h*ny, y + w*ny + h*nx)];
	[path lineToPoint:NSMakePoint(x - w*nx - h*ny, y + w*ny - h*nx)];
	[path closePath];
	[[NSColor blackColor] set];
	[path fill];
	[path release];
}

- (void) addCurveFrom:(NSPoint)pos to:(NSPoint)pos2 normal1:(NSPoint)cv1 normal2:(NSPoint)cv2 toPath:(NSBezierPath *)path//thickness:(float)thickness style:(linestyle)style
{
	float pi = 3.14159265358979;
	float x1 = pos.x;
	float y1 = pos.y;
	float x2 = pos2.x;
	float y2 = pos2.y;

	float d = hypot(cv1.x, cv1.y);
	float n1x = cv1.x/d;
	float n1y = cv1.y/d;
	
	d = hypot(cv2.x, cv2.y);
	float n2x = cv2.x/d;
	float n2y = cv2.y/d;
	
//	NSBezierPath *path = [[NSBezierPath alloc] init];
	[path moveToPoint:pos];
	
	float det = n2x*n1y - n2y*n1x;
	if (fabs(det)<1e-3) {
		[path lineToPoint:pos2];
	} else {
		float temp1 = (x2*n2x + y2*n2y)/det;
		float temp2 = (x1*n1x + y1*n1y)/det;
		float xc = (n1y*temp1 - n2y*temp2);
		float yc = (-n1x*temp1 + temp2*n2x);
		float r = hypot(x1 - xc, y1 - yc);
//		[path appendBezierPathWithArcFromPoint:pos toPoint:pos2 radius:r];
		float theta1 = (180/pi)*atan2f(y1 - yc, x1 - xc);
		float theta2 = (180/pi)*atan2f(y2 - yc, x2 - xc);
		[path appendBezierPathWithArcWithCenter:NSMakePoint(xc, yc) radius:r startAngle:theta1 endAngle:theta2];
	}
	
/*	if (style==dashed) {
	}
	
	[path stroke];
	[path release]; */
}

/*- (NSPoint) namePos
{
	NSPoint pos = [self pos];
	NSSize size = [self size];
	float xp = pos.x + size.width/2.0;
	float yp = pos.y;

	NSString *namePosition = [self namePosition];
	NSPoint namePos;
	if ([namePosition isEqualToString:@"Above"]) {
		namePos = NSMakePoint(xp - nameSize.width/2.0, yp - nameSize.height - 2.0);
	} else {
		namePos = NSMakePoint(xp - nameSize.width/2.0, yp + size.height);
	}
	
	return  namePos;
} */

- (void) drawName
{
	EXPModelObject *modelObject = [self modelObject];

	NSPoint pos = [self pos];
	NSSize size = [self size];
	float xp = pos.x + size.width/2.0;
	float yp = pos.y;

	NSString *namePosition = [self namePosition];
	NSPoint namePos;
	
	NSString *name = [self name];
	NSDictionary *attribs = [modelObject textAttributes];
	NSSize nameSize = [name sizeWithAttributes:attribs];

	if ([namePosition isEqualToString:@"Above"]) {
		namePos = NSMakePoint(xp - nameSize.width/2.0, yp - nameSize.height - 2.0);
	} else {
		namePos = NSMakePoint(xp - nameSize.width/2.0, yp + size.height);
	}

	[name drawAtPoint:namePos withAttributes:attribs];
}

- (void) drawInView:(id)view isSelected:(BOOL)flag
{
}

- (id) description
{
	return [NSString stringWithFormat:@"EXPComponent: type = %@, name = %@", [self componentType], [self name]];
}

- (void) dealloc
{
	[_name release];
	[_path release];
	[_document release];
	[_namePosition release];
	[_definition release];
	[_inputs release];
	[_outputs release];
	[_connectedComponents release];
	[super dealloc];
}

@end