#import "MapController.h"
#import <appkit/appkit.h>
#import "IcaoMap.h"
#import "IcaoDefinitions.h"
#import "IcaoObjects.h"
#import "mapdraw.h"
#import "mapobjects.h"
#import "router.h"
#import "RouteController.h"
#import "IcaoController.h"


@implementation MapController

extern	FILE *yyin;
extern  void callRestartIfNeeded(FILE *file);
extern	yyparse();

- routeController
{
	return routeController;
}

- mapView
{
	return mapView;
}

- mapWindow
{
	return mapWindow;
}

- displayButton
{
	return displayButton;
}

- scalePopup
{
	return scalePopup;
}

- (NXZone *)mapZone
{
	return mapData.mapZone;
}

- copyDataFromGlobal
{
	if (mapData.mapZone != theZone)
	{
		fprintf(stderr, "MapController: zone pointer does not match.\n");
	}
	mapData.map_origin = map_origin;
	mapData.map_scale = map_scale;
	mapData.map_zeromeridian = map_zeromeridian;
	mapData.top = top;
	mapData.left = left;
	mapData.bottom = bottom;
	mapData.right = right;
	mapData.topleft = topleft;
	mapData.topright = topright;
	mapData.bottomleft = bottomleft;
	mapData.bottomright = bottomright;
	mapData.map_width = map_width;
	mapData.map_height = map_height;
	mapData.mapWidth = mapWidth;
	mapData.mapHeight = mapHeight;
	mapData.mapWidthcm = mapWidthcm;
	mapData.mapHeightcm = mapHeightcm;
	mapData.originx = originx;
	mapData.originy = originy;
	mapData.scalefactor = scalefactor;
	mapData.mercatorscale = mercatorscale;
	mapData.map_projection = map_projection;
	mapData.v1 = v1;
	mapData.v2 = v2;
	mapData.objectlist = objectlist;
	mapData.objectno = objectno;
	mapData.nametable = nametable;
	mapData.tableentries = tableentries;
	mapData.namearray = namearray;
	mapData.db_objects = db_objects;
	mapData.db_visible = db_visible;
	mapData.drawroutenumpoints = drawroutenumpoints;
	mapData.visiblenumber = visiblenumber;
	memcpy(mapData.drawroutepoints, drawroutepoints, 100*sizeof(LOCATION));
	memcpy(mapData.visiblelist, visiblelist, 100*sizeof(int));

	return self;
}

- copyDataToGlobal
{
	theZone = mapData.mapZone;
	map_origin = mapData.map_origin;
	map_scale = mapData.map_scale;
	map_zeromeridian = mapData.map_zeromeridian;
	top = mapData.top;
	left = mapData.left;
	bottom = mapData.bottom;
	right = mapData.right;
	topleft = mapData.topleft;
	topright = mapData.topright;
	bottomleft = mapData.bottomleft;
	bottomright = mapData.bottomright;
	map_width = mapData.map_width;
	map_height = mapData.map_height;
	mapWidth = mapData.mapWidth;
	mapHeight = mapData.mapHeight;
	mapWidthcm = mapData.mapWidthcm;
	mapHeightcm = mapData.mapHeightcm;
	originx = mapData.originx;
	originy = mapData.originy;
	scalefactor = mapData.scalefactor;
	mercatorscale = mapData.mercatorscale;
	map_projection = mapData.map_projection;
	v1 = mapData.v1;
	v2 = mapData.v2;
	objectlist = mapData.objectlist;
	objectno = mapData.objectno;
	nametable = mapData.nametable;
	tableentries = mapData.tableentries;
	namearray = mapData.namearray;
	db_objects = mapData.db_objects;
	db_visible = mapData.db_visible;
	drawroutenumpoints = mapData.drawroutenumpoints;
	visiblenumber = mapData.visiblenumber;
	memcpy(drawroutepoints, mapData.drawroutepoints, 100*sizeof(LOCATION));
	memcpy(visiblelist, mapData.visiblelist, 100*sizeof(int));

	[[NXApp delegate] mapChanged:self];

	return self;
}

- setup
{
	return [self setupFromFile:""];
}


- setupFromFile:(const char*)filename
{
	FILE				*input;
	NXRect			frame;
	int					i;
	id					popup;
	char				scaleString[32];
	char				defaultFile[MAXPATHLEN+1];

	theZone = NXCreateZone(vm_page_size, vm_page_size, NO);
	NXNameZone(theZone, strrchr(filename, '/')?strrchr(filename, '/'):filename);
	input = fopen(filename, "rb");
	if (input && strlen(filename))
		yyin = input;
	else
	{
		printf(NXLS("Could not find input file %s - using AC.iwp!\n"), filename);
		if (![[NXBundle mainBundle] getPath: defaultFile 
				forResource: MC_DEFAULTMAPFILE ofType: NULL])
		{
			NXRunAlertPanel(NXLS("Alert")
					, "Couldn't even find the internal Mapfile %s.\nWill abort now", "OK"
					, NULL, NULL, MC_DEFAULTMAPFILE);
			return nil;
		}
		else
		{
			input = fopen(defaultFile, "rb");
			if (input)
				yyin = input;
			else
			{
				NXRunAlertPanel(NXLS("Alert")
						, "Couldn't even open the internal Mapfile %s.\nWill abort now"
						, "OK", NULL, NULL, defaultFile);
				return nil;
			}
		}
	}

	objects_init();
	
	callRestartIfNeeded(yyin);
	i = yyparse();
	fclose(yyin);
	/* i == 0 means no error */
	
	if (i)
	{
		return nil;
	}
	
	sort_objects();
	
	[mapView getBounds:&frame];
	mapWidth = frame.size.width;
	mapHeight = frame.size.height;
	
	mapWidthcm = [mapView widthCmFrom:mapWidth];
	mapHeightcm = [mapView heightCmFrom:mapHeight];
	
	map_setscale(scales[5]);
	map_projection = atoi(NXGetDefaultValue(APPNAME, IPD_PROJECTIONTYPE));
	[projectionPopup setTitle: [[[[projectionPopup target] itemList]
			findCellWithTag:map_projection] title]];
	
	mapData.mapZone = theZone;
	[self copyDataFromGlobal];

	map_initcoord();
	[self displayMap];
	
	popup = [scalePopup target];
	for (i = 0; i < numscales; i++)
	{
		sprintf(scaleString, "1 : %d", scales[i]);
		[popup addItem:scaleString];
	}
	[popup removeItemAt:0];
	[scalePopup setTitle:[[[popup itemList] cellAt:5:0] title]];
	[popup setTarget:self];
	[popup setAction:@selector(scaleChanged:)];

	popup = [projectionPopup target];
	[popup setTarget:self];
	[popup setAction:@selector(projectionChanged:)];

	[objectBrowser setTarget:self];
	[objectBrowser setAction:@selector(objectClicked:)];
	[objectBrowser setDoubleAction:@selector(objectDoubleClicked:)];
	[objectBrowser acceptArrowKeys:YES andSendActionMessages:YES];
	[objectBrowser loadColumnZero];
	
	return self;
}


- displayMap
{
	/* 
	 * inform someone, that the map has changed 
	 * Has it really ?
	 */
	[mapView display];
	return self;
}


- scaleChanged:sender
{
	/*
	 *	scale popup handling	
	 */
	map_setscale(scales[
		[[[scalePopup cell] target] indexOfItem:
			[[[scalePopup cell] target] selectedItem]]]);
	map_initcoord();
	[self displayMap];
	return self;
}


- projectionChanged:sender
{
	/*
	 *	projection popup handling	
	 */
	map_projection = [[sender selectedCell] tag];
	map_initcoord();
	[self displayMap];
	return self;
}


- selectInBrowser:(const char *)aString
{
	int					pos;
	NXRect			cellFrame, columnFrame;
	id					matrix;
	
	pos = objectThatMatches(aString);
	if (pos == -1)
		pos = 0;
	matrix = [objectBrowser matrixInColumn:0];
	[matrix getCellFrame:&cellFrame at:pos:0];		
	if ([objectBrowser getFrame:&columnFrame ofInsideOfColumn:0])
	{
		[matrix convertRect:&columnFrame fromView:objectBrowser];
		NX_HEIGHT(&cellFrame)= NX_HEIGHT(&columnFrame);
		NX_Y(&cellFrame) -= NX_HEIGHT(&columnFrame)/2;
		[matrix scrollRectToVisible:&cellFrame];
	}
	else
		/* this hopefully never get invoked */
		[matrix scrollCellToVisible:pos:0];
	[matrix selectCellAt:pos:0];
	[objectBrowser display];
	return self;
}


- objectClicked:sender
{
	id				responder = [mapWindow firstResponder];
	
	if ([responder respondsTo:@selector(replaceSel:)])
	{
		[responder setNoWrap];
		[responder selectAll:self];
		if (([[objectBrowser matrixInColumn:0] selectedRow])
				&& ([[objectBrowser matrixInColumn:0] selectedRow] != -1))
		{
			[responder replaceSel:[[objectBrowser selectedCell] stringValue]];
			currentroute[0] = objectfromnamelist(
					[[objectBrowser matrixInColumn:0] selectedRow]);
		}
		else
			[responder replaceSel:""];
		[responder selectAll:self];

		[routeController setNewTakeoff:[routeTO stringValue]];
		[self displayMap];
	}

	return self;
}


- objectDoubleClicked:sender
{
  OBJECT			*object;
	int					pos;

	pos = [[objectBrowser matrixInColumn:0] selectedRow];
  object = objectfromnamelist(pos);
  if (object)
    {
      map_origin = object->location;
      map_initcoord();
			[self displayMap];
    }
	return self;
}


- getNewTypes:sender
{
	int					i;
	
	for (i = 0; i < numvis; i++)
	{
		visobj[i] = [[typeMatrix cellAt:i:0] state];
	}
	[displayButton setEnabled:YES];
	return self;
}


- setNewRoute:(BOOL)redraw TO:(const char*)TO via:(const char*)via1
			via:(const char*)via2 via:(const char*)via3 dest:(const char*)dest
{
	[routeTO setStringValue:TO];
	[[routeVia cellAt:1:0] setStringValue:via1];
	[[routeVia cellAt:2:0] setStringValue:via2];
	[[routeVia cellAt:3:0] setStringValue:via3];
	[routeDest setStringValue:dest];
	[self displayMap:self];
	return self;
}

- displayMap:sender
{	
	if ([sender isEqual:displayButton])
	{
		[displayButton setEnabled:NO];
		[mapView bufferNeedsUpdate];
	}
	map_initcoord();
	[self displayMap];
	return self;
}

- showObjectsPanel:sender
{
	int				i;
	id				doc = [typeScroller docView];
	NXRect		frame;
	
	if (!objectsPanel)
	{
		if ([NXApp loadNibSection:"VisibleObjects.nib" owner:self] == nil)
			return nil;
		else
		{
			[typeScroller setAutoresizeSubviews:YES];
			[[typeMatrix setAutosizeCells:YES] setAutoscroll:YES];
			[[typeMatrix setTarget:self]
				setAction:@selector(getNewTypes:)];
			while ([typeMatrix cellCount])
				[typeMatrix removeRowAt:0 andFree:YES];
			for (i = 0; i < numvis; i++)
			{
				[[typeMatrix addRow] sizeToCells];
				[[typeMatrix cellAt:i:0] setState:visobj[i]];
				[[typeMatrix cellAt:i:0] setTitle:visstring[i]];
			}
			[doc getFrame:&frame];
			frame.size.height = [typeMatrix cellCount] * 17;
			[doc setFrame:&frame];
			[typeScroller display];
		}
	}

	[objectsPanel makeKeyAndOrderFront:sender];

	return self;
}


- showSoaringPanel:sender
{
	[routeController setNewTakeoff:[routeTO stringValue]];
	[[routeController soaringPanel] makeKeyAndOrderFront:sender];
	return self;
}

- routeVia
{
	return routeVia;
}

- (BOOL)canAutoroute
{
	return([routeController canAutoroute]);
}

- tryToAutoroute:sender
{
	return ([routeController tryToAutoroute:sender]);
}

- printMap:sender
{

	/* Just to sure the buffer is uptodate */
	[mapView display];
	
	/* Check if there is a route*/
	if ((drawroutenumpoints >= 2) 
			|| (([routeTO stringValue][0] != '\000') 
					&& ([routeDest stringValue][0] != '\000')))
	{
		[[[NXApp delegate] routeAdjust] setEnabled: YES];
		if ([mapView showsRoute])
			[[[NXApp delegate] routeAdjust] 
					setTitle: [[[[[[NXApp delegate] routeAdjust] target] itemList]
							findCellWithTag:ADJUST_ROUTE] title]];
		else
			[[[NXApp delegate] routeAdjust] 
					setTitle: [[[[[[NXApp delegate] routeAdjust] target] itemList]
							findCellWithTag:KEEP_SCALE] title]];
	}
	else
	{
		[[[[[[NXApp delegate] routeAdjust] setEnabled: NO] target] 
				itemList] selectCellWithTag: KEEP_SCALE];
	}

	[mapView printPSCode:self];
	
	return self;
}

- appWillTerminate:sender
{
	[routeController appWillTerminate:sender];
	return self;
}


- free
{
	theZone = NULL;
	NXDestroyZone(mapData.mapZone);
	return [super free];
}

@end





@implementation MapController(WindowDelegate)

- windowDidBecomeMain:sender
{
	return [mapView setMyTrackingRect: YES];
}

- windowDidResignMain:sender
{
	return [mapView setMyTrackingRect: NO];
}

- windowWillMiniaturize:sender toMiniwindow:miniwindow
{
	/*
	 * Tell Miniwindow to use IcaoIcon
	 */
	[sender setMiniwindowIcon:NXLS("IcaoIcon")];
	/* to remove the InfoPopUp if it is visible */
	[mapView removeInfoPopUp];
	
	/* Clear the trackingRect */
	[mapView setMyTrackingRect: NO];
	/* The return Value is ignored by the sender */
	return self;
}

- windowDidDeminiaturize:sender
{
	[mapView setMyTrackingRect: YES];
	return self;
}

- windowWillClose:sender
{
	[sender setDelegate:nil];
	[self free];
	return sender;
}

@end


@implementation MapController(BrowserDelegate)

- (int)browser:sender getNumRowsInColumn:(int)column
{
	return tableentries;
}

- browser:sender loadCell:cell atRow:(int)row inColumn:(int)column
{
	[cell setStringValue:namearray[row]];
	[cell setLeaf:YES];
	[cell setLoaded:YES];
	return self;
}
@end


@implementation MapController(TextDelegate)

- textDidGetKeys:textObject isEmpty:(BOOL)flag
{
	char					*buf;
	int						len;

	len = [textObject byteLength] + 1;
	buf = malloc(len);
	[textObject getSubstring:buf start:0 length:len];
	[self selectInBrowser:buf];
	free(buf);
	return self;
}

- (BOOL)textWillEnd:textObject
{
	char				*contents;
	
	contents = malloc([textObject byteLength]+1);
	
	/* 
	 * Since getSubstring doesn't always return anything, we need to make sure
	 * that contents equals ""
	 */
	contents[0] = '\000';
	[textObject getSubstring:contents start:0 length:[textObject charLength]];
	
	/* If anything is in the field */
	if (strcmp(contents,""))
	{
		[self selectInBrowser:contents];
		free(contents);
		contents = malloc(strlen([[objectBrowser selectedCell] stringValue])+1);
		strcpy(contents, [[objectBrowser selectedCell] stringValue]);
		if (!strcmp(contents, IO_CLEARENTRY))
			contents[0] = '\000';
		[textObject setText:contents];
		[routeController setNewTakeoff:[routeTO stringValue]];
		[self displayMap];
	}
	free(contents);	
	return NO; // this means Text may End (Why NO ?)
}
@end


@implementation MapController(NXNibNotification)

- awakeFromNib
{
	if (!routeController)
	{
		if ([NXApp loadNibSection: "SuggestTriangle.nib" owner:self] == nil)
			return nil;
	}
		
	return self;
}
@end


