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

#import "EXPDocument.h"
#import "EXPModelObject.h"
#import "EXPModelView.h"
#import "EXPComponent.h"
#import "EXPFlowComponent.h"
#import "EXPStockComponent.h"
#import "EXPCloudComponent.h"
#import "EXPAuxiliaryComponent.h"
#import "EXPParameterComponent.h"
#import "EXPConnectorComponent.h"
#import "EXPToolPaletteController.h"
#import "EXPInspectorController.h"
#import "EXPTableFunctionWindowController.h"
#import "EXPSetupWindowController.h"
#import "PLTMatrix.h"

NSPoint EXPDocumentGetQuadrant(NSPoint point, NSPoint startPoint, float length)
{
	float dx = point.x - startPoint.x;
	float dy = point.y - startPoint.y;
	
	NSPoint cv;
	
	if ((dy<=dx) && (dy>=-dx)) {
		cv = NSMakePoint(length, 0.0);
	} else if ((dy<=dx) && (dy<=-dx)) {
		cv = NSMakePoint(0.0, -length);
	} else if ((dy>=dx) && (dy>=-dx)) {
		cv = NSMakePoint(-length, 0.0);
	} else {
		cv = NSMakePoint(0.0, length);
	}
	
	return cv;
}

@implementation EXPDocument

- (id)init
{
    self = [super init];
    if (self) {
		_currentTool = @"Select";
/*		NSString *pathName = @"/Users/Ashley/Projects/Objective-C/MathsProgs/DDESolver/EXP-Examples";
		NSString *fileStub = @"rabbits";					//@"linear-growth_v10"; @"stock-flow_v2"; @"exponential-growth_v10"; @"stock-flow_v2";
		NSString *fileName = [fileStub stringByAppendingPathExtension:@"xmodel"];
		fileName = [pathName stringByAppendingPathComponent:fileName];
		NSData *data = [[NSData alloc] initWithContentsOfFile:fileName];
		_model = [[EXPModelObject alloc] init];
		[_model setDocument:self];
		[_model loadData:data];
		[data release];
		[self setFilename:fileName];
		[self solve:nil]; */
		_model = [[EXPModelObject alloc] init];
		[_model setDocument:self];
		
/*		NSString *pathName = @"/Users/Ashley/Projects/Objective-C/MathsProgs/DDESolver/EXP-Examples";
		NSString *fileStub = @"rabbits";			//@"Untitled";@"rabbits"; @"linear-growth_v10"; @"stock-flow_v2"; @"exponential-growth_v10"; @"stock-flow_v2";
		NSString *fileName = [fileStub stringByAppendingPathExtension:@"xmodel"];
		fileName = [pathName stringByAppendingPathComponent:fileName];
		NSData *data = [[NSData alloc] initWithContentsOfFile:fileName];
		[_model loadData:data];
		[data release];
		[_model dump];
		[self setFilename:fileName]; */
		
    }
    return self;
}

- (void) setFilename:(id)filename
{
	[filename retain];
	[_filename release];
	_filename = filename;
}

- (id) filename
{
	return _filename;
}

- (void) setMatrix:(id)matrix
{
	[matrix retain];
	[_matrix release];
	_matrix = matrix;
}

- (id) matrix
{
	return _matrix;
}
/* - (void)awakeFromNib
{
	NSLog(@"EXPDocument -awakeFromNib");
	NSData *data = [[NSData alloc] initWithContentsOfFile:@"/Users/Ashley/Projects/Objective-C/MathsProgs/DDESolver/EXP-Examples/rabbits.xmodel"];
	_model = [[EXPModelObject alloc] initWithData:data];
	[data release];
} */

- (NSString *)windowNibName
{
    return @"EXPDocument";
}

- (void)windowControllerDidLoadNib:(NSWindowController *) aController
{
    [super windowControllerDidLoadNib:aController];
    [[NSNotificationCenter defaultCenter] addObserver:self 
			selector:@selector(selectedToolDidChange:) 
			name:EXPSelectedToolDidChangeNotification 
			object:[EXPToolPaletteController sharedToolPaletteController]];
	[_mainView setDelegate:self];
}

- (NSData *)dataRepresentationOfType:(NSString *)type
{
	NSLog(@"dataRepresentationOfType:\"%@\"", type);
	EXPModelObject *modelObject = [self modelObject];
	NSXMLDocument *xmlDoc = [modelObject XMLRepresentation];
	NSData *data = [[xmlDoc XMLStringWithOptions:NSXMLNodePrettyPrint] dataUsingEncoding:NSUTF8StringEncoding];
	
    return data;
}

- (BOOL)loadDataRepresentation:(NSData *)data ofType:(NSString *)aType
{
	BOOL success = YES;
	
	EXPModelObject *model = [[EXPModelObject alloc] init];
	success = [model loadData:data];
	if (success) {
		[self setModelObject:model];
		[model setDocument:self];
		[model dump];
		[model release];
	}
	
    return success;
}

- (void) selectedToolDidChange:(id)sender
{
	NSLog(@"EXPDocument -selectedToolDidChange");
	EXPToolPaletteController *toolPaletteController = [sender object];
	NSString *mode = [toolPaletteController mode];
	[self setCurrentTool:mode];
	[[_mainView window] makeKeyAndOrderFront:self];
}

- (IBAction) selectAll:(id)sender
{
	NSLog(@"EXPDocument -selectAll");
	EXPModelObject *modelObject = [self modelObject];
	NSArray *objects = [modelObject objects];
	NSMutableSet *selection = [[NSMutableSet alloc] initWithArray:objects];
	[modelObject setSelection:selection];
	[selection release];
	
	[_mainView setNeedsDisplay:YES];
}

/*- (IBAction) newDocument:(id)sender
{
	[super newDocument:sender];
} */

- (IBAction) solve:(id)sender
{
	NSLog(@"Solve Model");

    NSTask *pipeTask = [[NSTask alloc] init];
    NSPipe *newPipe = [NSPipe pipe];
    NSFileHandle *readHandle = [newPipe fileHandleForReading];
    NSData *data = nil;
	
	NSMutableArray *arguments = [[NSMutableArray alloc] init];
//	[arguments addObject:@"-v"];
//	[arguments addObject:@"-g"];
	[arguments addObject:@"-P"];
	[arguments addObject:@"-Fxml"];
	[arguments addObject:[self filename]];
 
    [pipeTask setStandardOutput:newPipe];
	[pipeTask setArguments:arguments];
    [pipeTask setLaunchPath:@"/Users/Ashley/Projects/Objective-C/MathsProgs/DDESolver/dde/build/Debug/dde"];
    [pipeTask launch];
	[arguments release];
	
//	int status = [pipeTask terminationStatus];
 
	NSMutableString *output = [[NSMutableString alloc] init];
    while ((data = [readHandle availableData]) && [data length]) {
		NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
 //       NSLog(@"%@", string);
		[output appendString:string];
		[string release];
    }
    [pipeTask release];
	
//	NSArray *output= componentsSeparatedByString:;
//	PLTMatrix *matrix = [[PLTMatrix alloc] initWithString:output withHeaders:NO];
	NSXMLDocument *doc = [[NSXMLDocument alloc] initWithXMLString:output options:NSXMLDocumentTidyXML error:nil];
	NSXMLElement *root = [doc rootElement];
	NSXMLElement *headingElements = [[root elementsForName:@"heading"] objectAtIndex:0];
	
	NSArray *headerCells = [headingElements elementsForName:@"cell"];
	int nColumns = [headerCells count];
	NSMutableArray *headings = [[NSMutableArray alloc] init];
	int i;
	for(i=0; i<nColumns; i++) {
		NSString *heading = [[headerCells objectAtIndex:i] stringValue];
		[headings addObject:heading];
	}
	
	NSArray *rowElements = [root elementsForName:@"row"];
	int nRows = [rowElements count];
	PLTMatrix *matrix = [[PLTMatrix alloc] initWithRows:nRows andCols:nColumns];
	[matrix setColumnHeadings:headings];
	
	for(i=0; i<nRows; i++) {
		NSXMLElement *row = [rowElements objectAtIndex:i];
		NSArray *rowCells = [row elementsForName:@"cell"];
		int j;
		for(j=0; j<nColumns; j++) {
			NSString *cell = [[rowCells objectAtIndex:j] stringValue];
			double value = [cell doubleValue];
			[matrix setCell:value atRow:i andCol:j];
		}
	}
	NSLog(@"%@", [matrix delimitedStringRepresentation:@"\t" outputPoints:nRows]);
	
	[[self modelObject] setOutputMatrix:matrix];
	
	[matrix release];
	[headings release];
	[doc release];
	
	[output release];
}

- (IBAction) showTableFunctionWindow:(id)sender
{
	NSLog(@"showTableFunctionWindow");
	EXPModelObject *modelObject = [self modelObject];
//	NSArray *objects = [modelObject objects];
	NSMutableArray *tables = [modelObject tables];

	EXPTableFunctionWindowController *tableFunctionWindowController = [EXPTableFunctionWindowController sharedTableFunctionWindowController];

	[tableFunctionWindowController setTables:tables];
	[tableFunctionWindowController updateTableList];
	[tableFunctionWindowController refresh];

	[tableFunctionWindowController showWindow:sender];
	
}

- (IBAction) showSimSetup:(id)sender
{
	NSLog(@"showSimSetup.");
	if (!setupWindowController) {
		setupWindowController = [[EXPSetupWindowController alloc] init];
	}
	
	[setupWindowController setDocument:self];
	[setupWindowController refresh];
	[setupWindowController showWindow:self];
}

- (IBAction) delete:(id)sender
{
	NSLog(@"Delete.");
	EXPModelObject *modelObject = [self modelObject];
	NSSet *selection = [[self modelObject] selection];
/*	NSEnumerator *enumerator = [selection objectEnumerator];
	EXPComponent *component;
 
	while ((component = [enumerator nextObject])) {
		NSLog(@"Deleting \"%@\"", [component name]);
		[modelObject deleteComponent:component];
	} */
/*	if ([selection count]==1) {
		EXPComponent *component = [selection anyObject];
		NSLog(@"Deleting \"%@\"", [component name]);
		[modelObject deleteComponent:component];
	} else {
	} */
	[modelObject deleteComponents:selection];
	[modelObject setSelection:nil];
	[_mainView setNeedsDisplay:YES];

}

- (IBAction) exportToFile:(id)sender
{
	NSLog(@"EXPDocument -  exportToFile:%@", sender);
	NSSavePanel *savePanel = [NSSavePanel savePanel];
	int button = [savePanel runModalForDirectory:nil file:@"test.png"];
	if (button==NSFileHandlingPanelCancelButton) {
		return;
	}

	NSString *fileName = [savePanel filename];
	[self exportDiagramToFile:fileName];
}

- (id) selectedObjectForPoint:(NSPoint)point
{
	NSLog(@"EXPDocument -  selectedObjectForPoint:(%g, %g)", point.x, point.y);
	EXPModelObject *modelObject = [self modelObject];
	NSArray *objects = [modelObject objects];
	NSMutableSet *selection = [modelObject selection];
	
	BOOL found = NO;
	EXPComponent *component = nil;

//	If there is a selection already
	if (selection!=nil) {
		NSEnumerator *enumerator = [selection objectEnumerator];
		EXPComponent *value;
 
		while ((value = [enumerator nextObject])) {
//			NSLog(@"%@", value);
			BOOL b1 = [value controlAreaContainsPoint:point];
			BOOL b2 = [value containsPoint:point];
			if (b1 || b2) {
				component = value;
				found = YES;
				break;
			}
		}
	}
	
	if (component==nil) {
		int i;
		for(i=0; i<[objects count]; i++) {
			component = [objects objectAtIndex:i];
			if ([component containsPoint:point]) {
				found = YES;
				break;
			}
		}
	}
	
	if (!found) {
		component = nil;
	}
	
	return component;
		
}

//	Why am I here????
- (void) moveFlow:(EXPFlowComponent *)flow by:(NSPoint)change moveStart:(BOOL)moveStart
{
	NSPoint oldValvePosition = [flow valvePosition];
	if (moveStart) {
		NSPoint pos = [flow pos];
		[flow setPosition:NSMakePoint(pos.x + change.x, pos.y + change.y)];
	} else {
		NSPoint pos2 = [flow pos2];
		[flow setPosition2:NSMakePoint(pos2.x + change.x, pos2.y + change.y)];
	}
	NSPoint valvePosition = [flow valvePosition];

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

}

- (void) moveComponentsConnectedTo:(EXPComponent *)component by:(NSPoint)change
{
	NSSet *selection = [[self modelObject] selection];
	NSArray *inputs = [component 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 = [component 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 componentType] isEqualToString:@"Stock"]) {
	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) mouseDownAtPoint:(NSPoint)point
{
	EXPModelObject *modelObject = [self modelObject];
	NSDictionary *defaults = [modelObject defaults];
	
	NSString *mode = [self currentTool];
	EXPComponent *component = [self selectedObjectForPoint:point];
	
	EXPInspectorController *inspectorControler = [EXPInspectorController sharedInspectorController];
	[inspectorControler setSelection:nil];
	[inspectorControler setDocument:self];
	NSMutableSet *selection = [[NSMutableSet alloc] init];
	
	if ([mode isEqualToString:@"Select"] || [mode isEqualToString:@"Delete"]) {
		if (component!=nil) {
//		NSLog(@"%@ is now selected.", component);
//			NSMutableSet *selection = [[NSMutableSet alloc] initWithObjects:component, nil];
//			[modelObject setSelection:selection];
//			[inspectorControler setSelection:selection];
//			[selection release];
			[selection addObject:component];
//		} else {
//			[modelObject setSelection:nil];
		}
	
		_lastComponent = component;
	} else if ([mode isEqualToString:@"Stock"]) {
		EXPStockComponent *stock = [[EXPStockComponent alloc] init];
//		[stock setName:@"New Stock"];
		[modelObject setNameForNewComponent:stock];
		[stock setPosition:point];
		NSArray *stockSize = [defaults objectForKey:@"StockSize"];
		NSSize size = NSMakeSize([[stockSize objectAtIndex:0] floatValue], [[stockSize objectAtIndex:1] floatValue]);
		[stock setSize:size];
		[stock setModelObject:modelObject];
		NSMutableArray *objects = [modelObject objects];
		[objects addObject:stock];
		[selection addObject:stock];
		[stock release];
		[self setCurrentTool:@"Select"];
		[modelObject dump];
	} else if ([mode isEqualToString:@"Aux"]) {
		EXPAuxiliaryComponent *aux = [[EXPAuxiliaryComponent alloc] init];
//		[aux setName:@"New Auxiliary"];
		[modelObject setNameForNewComponent:aux];
		[aux setPosition:point];
		NSArray *auxSize = [defaults objectForKey:@"AuxiliarySize"];
		NSSize size = NSMakeSize([[auxSize objectAtIndex:0] floatValue], [[auxSize objectAtIndex:1] floatValue]);
		[aux setSize:size];
		[aux setModelObject:modelObject];
		NSMutableArray *objects = [modelObject objects];
		[objects addObject:aux];
		[selection addObject:aux];
		[aux release];
		[self setCurrentTool:@"Select"];
		[modelObject dump];
	} else if ([mode isEqualToString:@"Param"]) {
		EXPParameterComponent *param = [[EXPParameterComponent alloc] init];
//		[param setName:@"New Parameter"];
		[modelObject setNameForNewComponent:param];
		[param setPosition:point];
		NSArray *paramSize = [defaults objectForKey:@"ParameterSize"];
		NSSize size = NSMakeSize([[paramSize objectAtIndex:0] floatValue], [[paramSize objectAtIndex:1] floatValue]);
		[param setSize:size];
		[param setModelObject:modelObject];
		NSMutableArray *objects = [modelObject objects];
		[objects addObject:param];
		[selection addObject:param];
		[param release];
		[self setCurrentTool:@"Select"];
		[modelObject dump];
	} else if ([mode isEqualToString:@"Flow"] || [mode isEqualToString:@"Conn"]) {
		startPoint = point;
	}
	
	[modelObject setSelection:selection];
	[inspectorControler setSelection:selection];
	[selection release];
	[_mainView setNeedsDisplay:YES];

}

- (void) mouseUpAtPoint:(NSPoint)point
{
	EXPModelObject *modelObject = [self modelObject];
//	NSDictionary *defaults = [modelObject defaults];
	
	NSString *mode = [self currentTool];
//	EXPComponent *component = [self selectedObjectForPoint:point];
//	NSLog(@" mouseUpAtPoint: mode = %@, name = %@.", mode, [component name]);
	
	float length = 20.0;
	NSPoint pt1;
	NSPoint pt2;
	NSPoint cv1;
	NSPoint cv2;
	EXPCloudComponent *cloud1 = nil;
	EXPCloudComponent *cloud2 = nil;
	NSMutableArray *objects = [modelObject objects];
	EXPInspectorController *inspectorControler = [EXPInspectorController sharedInspectorController];
	NSMutableSet *selection = [[NSMutableSet alloc] init];
	
	if ([mode isEqualToString:@"Flow"]) {
		EXPFlowComponent *flow = [[EXPFlowComponent alloc] init];
/*		[flow setName:@"New Flow"];
		[flow setPosition:startPoint];
		[flow setPosition2:point]; */
//		[flow setControlvector:NSMakePoint(20.0, 0.0)];
//		[flow setControlvector2:NSMakePoint(20.0, 0.0)];
		EXPComponent *startComponent = [self selectedObjectForPoint:startPoint];
		if ((startComponent==nil) || ![startComponent acceptsOutFlows]) {
			cv1 = EXPDocumentGetQuadrant(point, startPoint, length);
			cloud1 = [[EXPCloudComponent alloc] init];
			[cloud1 setPosition:NSMakePoint(startPoint.x - 80.0, startPoint.y - 25.0)];
			[cloud1 setModelObject:modelObject];
			[flow setStart:cloud1];
			[[cloud1 outflows] addObject:flow];
			[modelObject setNameForNewComponent:cloud1];
		} else {
			EXPStockComponent *stock = (EXPStockComponent *)startComponent;
			startPoint = [stock closestSurfacePointToPoint:startPoint];
			[flow setStart:stock];
			cv1 = [stock normalVectorForPoint:startPoint length:length];
			[[stock outflows] addObject:flow];
		}
		EXPComponent *endComponent = [self selectedObjectForPoint:point];
		if ((endComponent==nil) || ![endComponent acceptsInFlows]) {
			cv2 = EXPDocumentGetQuadrant(point, startPoint, length);
			cloud2 = [[EXPCloudComponent alloc] init];
			[cloud2 setPosition:NSMakePoint(point.x, point.y - 25.0)];
			[cloud2 setModelObject:modelObject];
			[flow setEnd:cloud2];
			[[cloud2 inflows] addObject:flow];
			[modelObject setNameForNewComponent:cloud2];
//			[objects addObject:cloud2];
		} else {
			EXPStockComponent *stock = (EXPStockComponent *)endComponent;
			[[stock inflows] addObject:flow];
			point = [stock closestSurfacePointToPoint:point];
			cv2 = [stock normalVectorForPoint:point length:length];
			[flow setEnd:stock];
		}
//		[flow setName:@"New Flow"];
		[modelObject setNameForNewComponent:flow];
		[flow setPosition:startPoint];
		[flow setPosition2:point];
		[flow setControlvector:cv1];
		[flow setControlvector2:cv2];
		[flow setModelObject:modelObject];
		[objects addObject:flow];
		[selection addObject:flow];
		if (cloud1!=nil) {
			[objects addObject:cloud1];
			[cloud1 release];
		}
		if (cloud2!=nil) {
			[objects addObject:cloud2];
			[cloud2 release];
		}
		[flow release];
		[self setCurrentTool:@"Select"];
		[modelObject dump];
	} else if ([mode isEqualToString:@"Conn"]) {
		EXPComponent *startComponent = [self selectedObjectForPoint:startPoint];
		EXPComponent *endComponent = [self selectedObjectForPoint:point];
		if ([startComponent acceptsOutputs] && [endComponent acceptsInputs]) {
			EXPConnectorComponent *connector = [[EXPConnectorComponent alloc] init];
			pt1 = [startComponent closestSurfacePointToPoint:startPoint];
			cv1 = [startComponent normalVectorForPoint:pt1 length:-20.0];
			pt2 = [endComponent closestSurfacePointToPoint:point];
			cv2 = [endComponent normalVectorForPoint:pt2 length:-20.0];
//			[connector setName:@"New Connector"];
			[modelObject setNameForNewComponent:connector];
			[connector setPosition:pt1];
			[connector setPosition2:pt2];
			[connector setControlvector:NSMakePoint(-cv1.x, -cv1.y)];
			[connector setControlvector2:cv2];
			[connector setModelObject:modelObject];
			[connector setStart:startComponent];
			[connector setEnd:endComponent];
			[[startComponent outputs] addObject:connector];
			[[endComponent inputs] addObject:connector];
			[objects addObject:connector];
			[selection addObject:connector];
			[connector release];
		} else {
			NSLog(@"Invalid start/end components: %@/%@.", [startComponent name], [endComponent name]);
		}
		[inspectorControler refreshSelection];
		[modelObject dump];
		[self setCurrentTool:@"Select"];
	} else if ([mode isEqualToString:@"Delete"]) {
		[self delete:nil];
	}
	
	[selection release];
	_lastComponent = nil;
	[_mainView setNeedsDisplay:YES];

}

- (void) mouseDraggedToPoint:(NSPoint)point
{
	EXPComponent *lastComponent = _lastComponent;
	
	NSString *mode = [self currentTool];
	
	if ([mode isEqualToString:@"Select"] /*&& !([[lastComponent componentType] isEqualToString:@"Flow"])*/) {
//		if ([[lastComponent componentType] isEqualToString:@"Flow"]) {
//			NSLog(@"Dragging Flow to %@", NSStringFromPoint(startPoint));
//		} else {
/*		int controlPoint = [lastComponent controlPointSelected];
		if (controlPoint==0) {
			NSPoint lastPoint = [_mainView lastPoint];
			printf("Got control point %d. Last point = %s\n", controlPoint, [NSStringFromPoint(lastPoint) UTF8String]);
			NSPoint oldPosition = [lastComponent pos];
			NSPoint oldPosition2 = [lastComponent 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);
			[lastComponent setPosition:newPosition];
			[lastComponent setPosition2:newPosition2];
			[self moveComponentsConnectedTo:lastComponent by:positionChange];
			[_mainView setLastPoint:point];
		} else if (controlPoint==1) {
			printf("Got control point %d\n", controlPoint);
			NSPoint pos = [lastComponent pos];
			NSPoint newControlVector = NSMakePoint(point.x - pos.x, point.y - pos.y);
			[lastComponent setControlvector:newControlVector];
		} else if (controlPoint==2) {
			printf("Got control point %d\n", controlPoint);
			NSPoint pos2 = [lastComponent pos2];
			NSPoint newControlVector = NSMakePoint(-point.x + pos2.x, -point.y + pos2.y);
			[lastComponent setControlvector2:newControlVector];
		} else if (controlPoint==3) {
			//	Start point: must be a flow/connector?
			printf("Got control point %d\n", controlPoint);
			EXPFlowComponent *component = (EXPFlowComponent *)lastComponent;
			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 *)lastComponent;
			EXPComponent *endComponent = [component end];
			NSPoint nearestPoint = [endComponent closestSurfacePointToPoint:point];
			[component setPosition2:nearestPoint];
		} else {
		} */
		[lastComponent moveComponentTo:point inView:_mainView];
		//		}
		
//	} else if ([mode isEqualToString:@"Flow"]) {
//		NSLog(@"Dragging Flow to %@", NSStringFromPoint(startPoint));
	}

	if (lastComponent!=nil) {
		EXPInspectorController *inspectorControler = [EXPInspectorController sharedInspectorController];
		[inspectorControler refreshSelection];
	}

	[_mainView setNeedsDisplay:YES];
//	[_mainView drawLineToPoint:point];

}

- (void) setCurrentTool:(id)currentTool
{
	[currentTool retain];
	[_currentTool release];
	_currentTool = currentTool;
}

- (id) currentTool
{
	return _currentTool;
}

- (void) setModelObject:(id)model
{
	[model retain];
	[_model release];
	_model = model;
}

- (id) modelObject
{
	return _model;
}

- (id) mainview
{
	return _mainView;
}

- (void) exportDiagramToFile:(NSString *)fileName
{
//	NSString *fileName = [savePanel filename];
	NSString *ext = [fileName pathExtension];
	NSBitmapImageFileType imageFileType;
	if ([ext caseInsensitiveCompare:@"png"]==NSOrderedSame) {
		imageFileType = NSPNGFileType;
	} else if (([ext caseInsensitiveCompare:@"jpeg"]==NSOrderedSame) || ([ext caseInsensitiveCompare:@"jpg"]==NSOrderedSame)) {
		imageFileType = NSJPEGFileType;
	} else if (([ext caseInsensitiveCompare:@"tiff"]==NSOrderedSame) || ([ext caseInsensitiveCompare:@"tif"]==NSOrderedSame)) {
		imageFileType = NSTIFFFileType;
	} else if ([ext caseInsensitiveCompare:@"gif"]==NSOrderedSame) {
		imageFileType = NSGIFFileType;
	} else if ([ext caseInsensitiveCompare:@"bmp"]==NSOrderedSame) {
		imageFileType = NSBMPFileType;
	} else {
		(void)NSRunAlertPanel(@"DDESolve", @"Invalid image file type.", @"Dismiss", nil, nil);
		return;
	}

// 1121, 763
	NSRect bounds;
	EXPModelObject *modelObject = [self modelObject];
	bounds = [modelObject drawingBounds];
//	bounds = NSMakeRect(0.0, 0.0, 1121.0, 763.0);
//	bounds = [modelObject drawingBounds]; 
	if (NSIsEmptyRect(bounds)) {
		return;
	}
	
	BOOL grid = [modelObject doesDrawGrid];
	[modelObject setDoesDrawGrid:NO];
	
	EXPModelView *view = [[EXPModelView alloc] initWithFrame:bounds];
	[view setDelegate:self];
	NSWindow* offscreenWindow = [[NSWindow alloc]
									initWithContentRect:NSMakeRect(0.0, 0.0, bounds.size.width + bounds.origin.x, bounds.size.height + bounds.origin.y)
//									initWithContentRect:bounds
									styleMask:NSBorderlessWindowMask
									backing:NSBackingStoreRetained
									defer:NO];
 
	[offscreenWindow setContentView:view];
	[[offscreenWindow contentView] display];
	
	[view lockFocus];
 
	NSBitmapImageRep *imageRep = [[NSBitmapImageRep alloc] initWithFocusedViewRect:bounds];
	[view unlockFocus];
	
	NSArray *keys = [[NSArray alloc] initWithObjects:NSImageCompressionFactor, nil];
	NSNumber *compressionFactor = [[NSNumber alloc] initWithFloat:1.0];
	NSArray *attribValues = [[NSArray alloc] initWithObjects:compressionFactor, nil];
	[compressionFactor release];
	NSDictionary *attribs = [[NSDictionary alloc] initWithObjects:attribValues forKeys:keys];
	[keys release];
	[attribValues release];
	NSData *dataRepresentation = [imageRep representationUsingType:imageFileType properties:attribs];
	
	[dataRepresentation writeToFile:fileName atomically:YES];
	
	[imageRep release];
	[offscreenWindow release];
	[view release];

	[modelObject setDoesDrawGrid:grid];

}

- (void) dealloc
{
	[_model release];
	[_currentTool release]; 
	[super dealloc];
}

@end