#import "BWOverworld.h"
#import "BWMainObject.h"
#import "Variables.h"

@implementation BWOverWorld : NSMatrix

# pragma mark -

- (void)awakeFromNib
{
	tiles = [[NSMutableArray alloc] initWithCapacity:16];
	
	sr = 1;
	[matrixTools setRefusesFirstResponder:YES];
	[self setRefusesFirstResponder:YES];
	[scrollView setLineScroll:(sr * 16)];
	[self setCellSize:NSMakeSize( (16 * sr) , (16 * sr) )];
	[self sizeToCells];
	
	sel = -1;
	selColor = 0;
	useDefaultTiles = YES;
	showGrid = YES;
}

- (void)open:(NSMutableData *)theRom
{
	rom = theRom;
	
	cr = 0;
	int i,j;
	
	for (i=0; i<16; i++) {
		[[matrixTiles cellWithTag:i] setBordered:NO];
	}
	
	for (i=0; i<[self numberOfRows]; i++) {
		for (j=0; j<[self numberOfColumns]; j++) {
			[[self cellAtRow:i column:j] setBordered:NO];
		}
	}
	
	for (i=0; i<4; i++) {
		for (j=0; j<0x10000; j++) {
			brackets[i][j] = 0;
		}
	}
	
	[[matrixTools cellWithTag:0] setBordered:NO];
	[[matrixTools cellWithTag:1] setBordered:NO];
	
	[menuArea removeAllItems];
	[menuArea addItemWithTitle:@"Show All"];
	[[menuArea itemAtIndex:0] setTag:(-1)];
	[[menuArea menu] addItem:[NSMenuItem separatorItem]];
	
	for (i=0; i<0x40; i++) {
		if (i > 0xF) [menuArea addItemWithTitle:[NSString stringWithFormat:@"Area %X",i]];
		else [menuArea addItemWithTitle:[NSString stringWithFormat:@"Area 0%X",i]];
		[[menuArea itemAtIndex:([menuArea numberOfItems]-1)] setTag:i];
	}
	
	maxGroups[0] = 801;
	maxGroups[1] = 1024;
	maxGroups[2] = 794;
	maxGroups[3] = 1024;
	
	currentTool = 0;	// 0 = Selection Tool // 1 = Groups Tool
	currentTile = -1;
	
	[self loadPalettes];
	[self loadTiles];
	[self loadPalettesWindow];
	[self loadRegions];
	[self loadAreas];
	[self changeRegion:nil];
	
	//testimg = [[NSImage alloc] initWithContentsOfFile:@"/Users/sim/Desktop/z2pit1024.png"];
}

- (void)save
{
	int i = NSOKButton;
	int j;
	
	if (g[cr] > maxGroups[cr]) {
		i = NSRunAlertPanel(@"You exceed the number of groups allowed in one or more regions. Save anyway?",
							@"You will lose some data at the end in the process.",
							@"Yes",@"No",nil);
	} else if (g[cr] < maxGroups[cr]) {
		i = NSRunAlertPanel(@"You did not use all the allowed bytes in one or more regions. Save anyway?",
							@"The unused bytes will be set to FF.",
							@"Yes",@"No",nil);
	}
	
	unsigned short list[4] = { 0x462F , 0x610C , 0x862F , 0xA10C };
	
	if (i != NSOKButton) return;
	
	//[self palacePointers];
	[rom replaceBytesInRange:NSMakeRange( 0x506C , 801 ) withBytes:&(overworldData[0][0])];
	[rom replaceBytesInRange:NSMakeRange( 0x665C , 1024 ) withBytes:&(overworldData[1][0])];
	[rom replaceBytesInRange:NSMakeRange( 0x9056 , 794 ) withBytes:&(overworldData[2][0])];
	[rom replaceBytesInRange:NSMakeRange( 0xA65C , 1024 ) withBytes:&(overworldData[3][0])];
	
	// Save Key Areas
	for (i=0; i<4; i++) {
		for (j=0; j<0x3F; j++) {
			[rom replaceBytesInRange:NSMakeRange( list[i] + j , 1 ) withBytes:&(keyAreas[j][i].y)];
			[rom replaceBytesInRange:NSMakeRange( list[i] + j + 0x3F , 1 ) withBytes:&(keyAreas[j][i].x)];
			[rom replaceBytesInRange:NSMakeRange( list[i] + j + 0x7E , 1 ) withBytes:&(keyAreas[j][i].z)];
			[rom replaceBytesInRange:NSMakeRange( list[i] + j + 0xBD , 1 ) withBytes:&(keyAreas[j][i].w)];
		}
	}
}

# pragma mark -

/*- (void)loadTiles
{
	if (tiles != nil) [tiles release];
	tiles = [[NSMutableArray alloc] initWithCapacity:16];
	
	NSImage *tt;
	
	int sr = sr;		// Scale Ratio
	int wh = sr * 8 * 2;
	
	NSImage *tileFinal;
	NSBitmapImageRep *tileRep;
	
	unsigned char *pf;
	const unsigned char *ptr;
	const unsigned char *tm = [rom bytes];
	
	tm += 0x07B3;
	
	int os;		// Town offSet = 0x315D0
	
	unsigned char palCode;
	const unsigned char *palPtr;
	
	int i,j,k;
	int x,y,z;
	for (i=0; i<0x10; i++) {
		
		tileFinal = [[NSImage alloc] initWithSize:NSMakeSize(wh,wh)];
		tileRep = [[NSBitmapImageRep alloc] 
				   initWithBitmapDataPlanes:nil
				   pixelsWide:wh
				   pixelsHigh:wh
				   bitsPerSample:8
				   samplesPerPixel:3
				   hasAlpha:NO
				   isPlanar:NO
				   colorSpaceName:NSCalibratedRGBColorSpace
				   bytesPerRow:(wh * 3)
				   bitsPerPixel:24];
		
		pf = [tileRep bitmapData];
		//NSLog(@"OK! - pforig = %X",pf);
		//NSLog(@"Tile %d",i);
		
		palPtr = [rom bytes];
		palPtr += 0x07F3;
		palCode = *(palPtr + i);
		//NSLog(@"palCode = %X",palCode);
		
		palPtr = [rom bytes];
		palPtr += 0x1C46B;
		palPtr += (palCode * 4);
		
		struct sCol tp[4];		// = { nesPal[0x0F] , nesPal[0x30] , nesPal[0x27] , nesPal[0x2A] };
		for (x=0; x<4; x++) {
			tp[x] = nesPal[*(palPtr + x)];
			//NSLog(@"Color %d = %X",x,*(palPtr + x));
		}
		
		for (j=0; j<2; j++) {
			for (k=0; k<2; k++) {
				
				os = (0x2000 * 8) + 0x20010 + 0x1000 + ((*tm) * 0x10);
				tt = [self tileWithOffset:os palette:tp];
				ptr = [[[tt representations] lastObject] bitmapData];
				
				tm++;
				
				for (y=0; y<(8 * sr); y++) {
					for (z=0; z<(8 * 3 * sr); z++) {
						*pf++ = *ptr++;
					}
					pf += (8 * 3 * sr);
				}
			}
			
			pf = [tileRep bitmapData] + (8 * 3 * sr);
			
		}
		
		[tileFinal addRepresentation:tileRep];
		if (i == 9) [tiles addObject:[NSImage imageNamed:@"Null.gif"]];
		else if (i == 0xD) [tiles addObject:[NSImage imageNamed:@"BubbleGenerator.gif"]];
		else [tiles addObject:tileFinal];
		//[tt release];
		
		[tileFinal release];
		[tileRep release];
		
		[[matrixTools cellWithTag:i] setImage:[tiles objectAtIndex:i]];
	}
	NSLog(@"Tiles Loaded");
}
*/

- (void)loadPalettes
{
	// Load Overworld Palettes //
	
	int i;
	ptr = [rom bytes] + 0x1C45B + 0x10;
	for (i=0; i<16; i++) {
		palettes[i] = *ptr++;
	}
	
	// Load Overworld Palettes Codes //
	
	ptr = [rom bytes] + 0x07E3 + 0x10;
	for (i=0; i<0x10 ; i++) {
		palettesCodes[i] = *ptr++;
	}
}

- (void)loadTiles
{
	int i,x;
	struct sCol tp[4];
	unsigned char palCode;
	NSImage *img;
	
	[tiles removeAllObjects];
	
	if (!useDefaultTiles) {
		
		NSMutableArray *tlist = [NSMutableArray arrayWithCapacity:4];
		NSImage *tsaBlock;
		
		for (i=0; i<0x10; i++) {
			
			[tlist removeAllObjects];
			
			palCode = palettesCodes[i];
			for (x=0; x<4; x++) {
				tp[x] = nesPal[palettes[(palCode*4)+x]];
			}
			
			ptr = [rom bytes] + 0x07A3 + (i*4) + 0x10;
			[tlist addObject:[self tileWithOffset:((*(ptr+0)) * 0x10) palette:tp data:0]];
			[tlist addObject:[self tileWithOffset:((*(ptr+2)) * 0x10) palette:tp data:0]];
			[tlist addObject:[self tileWithOffset:((*(ptr+1)) * 0x10) palette:tp data:0]];
			[tlist addObject:[self tileWithOffset:((*(ptr+3)) * 0x10) palette:tp data:0]];
						
			tsaBlock = [self graphicWithTiles:tlist type:0x22];
			[tiles addObject:tsaBlock];
			[[matrixTiles cellWithTag:i] setImage:tsaBlock];
		}
		
	} else {
		
		for (i=0; i<16; i++) {
			NSString *imageName = [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:@"tile%x",i] ofType:@"png"];
			img = [[NSImage alloc] initWithContentsOfFile:imageName];
			[tiles addObject:img];
			[[matrixTiles cellWithTag:i] setImage:img];
			[img release];
		}
	}
}

- (void)loadPalettesWindow
{
	int i,j,t;
	
	ptr = [rom bytes] + 0x07E3 + 0x10;
	for (i=0; i<0x10; i++) {
		
		[[matrixPalettesTiles cellAtRow:i column:0] setBordered:NO];
		[[matrixPalettesTiles cellAtRow:i column:0] setImage:[tiles objectAtIndex:i]];
		for (j=0; j<4; j++) {
			[[matrixPalettesTiles cellAtRow:i column:j+1] setHighlighted:NO];
			if (j == (*ptr)) [[matrixPalettesTiles cellAtRow:i column:j+1] setHighlighted:YES];
		}
		ptr++;
	}
	
	NSColor *pal;
	ptr = &palettes[0];
	
	t = 0;
	for (i=0; i<19; i++) {
		if ((i % 5) == 4) continue;
		
		[[matrixPalettes cellAtRow:0 column:i] setBordered:NO];
		pal = [objMain colorForCode:*ptr++];
		[[matrixPalettes cellAtRow:0 column:i] setBackgroundColor:pal];
		[[matrixPalettes cellAtRow:0 column:i] setTag:t++];
	}
	
	// Colors Window //
	
	t = 0;
	for (i=0; i<4; i++) {
		for (j=0; j<0x10; j++) {
			[[matrixColors cellAtRow:i column:j] setBordered:NO];
			[[matrixColors cellAtRow:i column:j] setTag:t];
			[[matrixColors cellAtRow:i column:j] setBackgroundColor:[objMain colorForCode:t]];
			t++;
		}
	}
}

// Possibility to move regions to unused space in the ROM, and access the maximum 1024 bytes for each
// Location of pointers : 4508 and 8508

- (void)loadRegions
{
	int i,j,k;
	int r,n;
	int max;
	unsigned char tp;
	unsigned int list[8] = { 0x506C , 801 , 0x665C , 1024 , 0x9056 , 794 , 0xA65C , 1024 };
	
	for (i=0; i<4; i++) {
		
		ptr = [rom bytes] + list[i*2];
		max = list[((i*2)+1)];
		n = 0;
		
		for (j=0; j<max; j++) {
			
			overworldData[i][j] = *ptr++;
			r = (overworldData[i][j] & 0xF0) >> 4;
			
			for (k=0; k<=r; k++) {
				overworldGrid[i][n] = overworldData[i][j] & 0x0F;
				n++;
			}
			
			if (j == 0) continue;
			if ((n % 0x40) == 0) continue;
			tp = overworldData[i][j-1];
			//if ( ((overworldData[i][j] & 0x0F) == (tp & 0x0F)) && ((tp & 0xF0) < 0xF0) && ((overworldGrid[i][n] % 0x40) != 0) )
			if ( ((overworldData[i][j] & 0x0F) == (tp & 0x0F)) && ((tp & 0xF0) < 0xF0) ) {
				if (((n-r-1) % 0x40) != 0) {
					brackets[i][n-r-1] = 1;
					//NSLog(@"Bracket (%X) (%X) (%X,%X) %X %X",j,(n-r-1),((n-r-1)%0x40),((n-r-1)/0x40),tp,overworldData[i][j]);
				}
			}
		}
	}
	NSLog(@"Regions loaded");
}

/*

West Hyrule
offSet = 0x506C; maxGroups = 801;
offSetPalaces = 0x479F; maxPalaces = 4;

East Hyrule
offSet = 0x9056; maxGroups = 794;

Death Mountain
offSet = 0x665C; maxGroups = 668;
668 is the default number of groups used

Maze Island
offSet = 0xA65C; maxGroups = 668;
668 is the default number of groups used

*/

- (void)loadAreas
{
	unsigned short os[4] = { 0x462F , 0x610C , 0x862F , 0xA10C };
	int i,j;
	
	for (i=0; i<4; i++) {
		
		ptr = [rom bytes] + os[i];
		
		for (j=0; j<0x3F; j++) {
			//NSLog(@"Val (%X) : %X,%X",j,*(ptr + 0x3F),*ptr);
			keyAreas[j][i].y = *ptr;
			keyAreas[j][i].x = *(ptr + 0x3F);
			keyAreas[j][i].z = *(ptr + 0x3F + 0x3F);
			keyAreas[j][i].w = *(ptr + 0x3F + 0x3F + 0x3F);
			ptr++;
		}
	}
	NSLog(@"Areas Loaded");
}

# pragma mark -

- (IBAction)changeRegion:(id)sender
{
	if (sender == nil) cr = 0;
	else cr = [sender indexOfSelectedItem];
	
	[fieldGroupsMax setStringValue:[self hexToString:maxGroups[cr]]];
	
	[self renewRows:1 columns:0x40];
	
	unsigned char b1,b2;	// b1 : High Byte   b2 : Low Byte
	int c = 0;
	int r = 0;
	int i,j;
	
	for (i=0; i<maxGroups[cr]; i++) {
		
		b1 = overworldData[cr][i] >> 4;
		b2 = overworldData[cr][i] & 0x0F;
		
		for (j=0; j<=b1; j++) {
			
			[[self cellAtRow:r column:c] setImage:[tiles objectAtIndex:b2]];
			c++;
			
			if (c == [self numberOfColumns] && (i < (maxGroups[cr]-1))) {
				c = 0; r++;
				if (overworldData[cr][i+1] == 0xFF) break;
				[self addRow];
			}
		}
		
		if (overworldData[cr][i] == 0xFF) break;
	}
	
	//NSString *str = [[NSBundle mainBundle] pathForResource:@"KeyAreas" ofType:@"plist"];
	//NSMutableArray *file = [[NSMutableArray alloc] initWithContentsOfFile:str];
	//NSMutableArray *areas = [file objectAtIndex:cr];
	//[menuArea addItemsWithTitles:areas];
	
	c = 0;
	for (i=0; i<[self numberOfRows]; i++) {
		for (j=0; j<[self numberOfColumns]; j++) {
			[[self cellAtRow:i column:j] setBordered:NO];
			[[self cellAtRow:i column:j] setTag:c++];
		}
	}
	
	[self changeArea:menuArea];
	[self sizeToCells];
	[self recalculate];
}

// West Hyrule		palace 1, skip, palace 2, palace 3		maxPalaces = 4, skip = 1
// East Hyrule		palace 5, skip, palace 6 hidden			maxPalaces = 3, skip = 1, check hidden (?)
// DM				nothing
// MI				palace 4

// Offset Palace + 7C00
// (5084 - 506C) + 7C00 = 7C18 = 31768
// (51E2 - 506C) + 7C00 = 7D76 = 32118
// (5356 - 506C) + 7C00 = 7EEA = 32490

- (IBAction)changeArea:(id)sender
{
	int s = [sender indexOfSelectedItem];
	
	if (s == 0) {
		[[matrixTools cellWithTag:0] setBordered:YES];
		currentTool = 0;
		sel = -1;
		[fieldMap setStringValue:@""]; [fieldMap setEnabled:NO];
		[fieldWorld setStringValue:@""]; [fieldWorld setEnabled:NO];
		[fieldEnter setStringValue:@""]; [fieldEnter setEnabled:NO];
		for (s=0; s<4; s++) { [[matrixFlags cellAtRow:s column:0] setState:0]; }
		[matrixFlags setEnabled:NO];
	} else {
		[[matrixTools cellWithTag:currentTool] setBordered:NO];
		currentTool = 17;
		sel = s - 2;
		[fieldMap setEnabled:YES]; [fieldMap setStringValue:[self hexToString:(keyAreas[sel][cr].z & 0x3F)]];
		[fieldWorld setEnabled:YES]; [fieldWorld setStringValue:[self hexToString:(keyAreas[sel][cr].w & 0x1F)]];
		[fieldEnter setEnabled:YES]; [fieldEnter setStringValue:[self hexToString:((keyAreas[sel][cr].z & 0xC0) >> 6)]];
		[matrixFlags setEnabled:YES];
		[[matrixFlags cellAtRow:0 column:0] setState:((keyAreas[sel][cr].y & 0x80) >> 7)];
		[[matrixFlags cellAtRow:1 column:0] setState:((keyAreas[sel][cr].x & 0x40) >> 6)];
		[[matrixFlags cellAtRow:2 column:0] setState:((keyAreas[sel][cr].w & 0x40) >> 6)];
		[[matrixFlags cellAtRow:3 column:0] setState:((keyAreas[sel][cr].w & 0x80) >> 7)];
	}
	
	//NSLog(@"sel : %d",sel);
	[self setNeedsDisplay:YES];
}

- (IBAction)changeTile:(id)sender
{
	int i;
	for (i=0; i<16; i++) {
		[[matrixTiles cellWithTag:i] setBordered:NO];
	}
	[[matrixTools cellWithTag:0] setBordered:NO];
	[[matrixTools cellWithTag:1] setBordered:NO];
	[[matrixTiles selectedCell] setBordered:YES];
	
	currentTile = [[matrixTiles selectedCell] tag];
	currentTool = -1;
	
	[self setNeedsDisplay:YES];
}

- (IBAction)changeTool:(id)sender
{
	int i;
	for (i=0; i<16; i++) {
		[[matrixTiles cellWithTag:i] setBordered:NO];
	}
	
	[menuArea selectItemAtIndex:0];
	[[matrixTools cellWithTag:currentTool] setBordered:NO];
	[[matrixTools selectedCell] setBordered:YES];
	
	currentTool = [[matrixTools selectedCell] tag];		NSLog(@"Current Tool : %d",currentTool);
	currentTile = -1;
	
	[self setNeedsDisplay:YES];
}

- (IBAction)actionMaxGroups:(id)sender
{
	int i;
	int n = 0;
	maxGroups[cr] = [self stringToHex:[sender stringValue]]; NSLog(@"mg : %X",maxGroups[cr]);
	[sender setStringValue:[self hexToString:maxGroups[cr]]];
	
	for (i=0; i<maxGroups[cr]; i++) {
		n += ((overworldData[cr][i] & 0xF0) >> 4) + 1;
	}
	
	[self renewRows:(n / 0x40) columns:0x40];
	[self sizeToCells];
	[self recalculate];
}

- (IBAction)changeSelectedPalette:(id)sender
{
	selPalette = [[sender selectedCell] tag];
	[windowColors makeKeyAndOrderFront:nil];
	
	int row = (palettes[selPalette] & 0xF0) >> 4;
	int col = palettes[selPalette] & 0x0F;
	
	NSRect nc = [boxColor frame];
	nc.origin.x = 2 + (col * [matrixColors cellSize].width) + (col * [matrixColors intercellSpacing].width);
	nc.origin.y = 2 + ((3-row) * [matrixColors cellSize].height) + ((3-row) * [matrixColors intercellSpacing].height);
	[boxColor setFrame:nc];
}

- (IBAction)changeColor:(id)sender
{
	palettes[selPalette] = [[sender selectedCell] tag];
	
	int row = [sender selectedRow];
	int col = [sender selectedColumn];
	
	NSRect nc = [boxColor frame];
	nc.origin.x = 2 + (col * [matrixColors cellSize].width) + (col * [matrixColors intercellSpacing].width);
	nc.origin.y = 2 + ((3-row) * [matrixColors cellSize].height) + ((3-row) * [matrixColors intercellSpacing].height);
	[boxColor setFrame:nc];
	
	[[matrixPalettes cellWithTag:selPalette] setBackgroundColor:[objMain colorForCode:palettes[selPalette]]];
	[self loadTiles];
	
	int i;
	for (i=0; i<0x10; i++) {
		[[matrixPalettesTiles cellAtRow:i column:0] setImage:[tiles objectAtIndex:i]];
	}
	
	int c = [self numberOfRows] * [self numberOfColumns];
	for (i=0; i<c; i++) {
		[[self cellWithTag:i] setImage:[tiles objectAtIndex:overworldGrid[cr][i]]];
	}
	
	[self setNeedsDisplay:YES];
}

- (IBAction)changePaletteCode:(id)sender
{
	int i;
	int r = [sender selectedRow];	NSLog(@"Row : %X",r);
	int c = [sender selectedColumn];
	if (c <= 0) return;
	
	for (i=1; i<5; i++) {
		[[matrixPalettesTiles cellAtRow:r column:i] setHighlighted:NO];
	}
	[[matrixPalettesTiles cellAtRow:r column:c] setHighlighted:YES];
	
	c--;
	palettesCodes[r] = c;
	
	[self loadTiles];
	[[matrixPalettesTiles cellAtRow:r column:0] setImage:[tiles objectAtIndex:r]];
	
	c = [self numberOfRows] * [self numberOfColumns];
	for (i=0; i<c; i++) {
		if (overworldGrid[cr][i] == r)
		[[self cellWithTag:i] setImage:[tiles objectAtIndex:overworldGrid[cr][i]]];
	}
	
	[self setNeedsDisplay:YES];
}

# pragma mark -

// 0 = Map		..xxxxxx (Z) 3F
// 1 = World	...xxxxx (W) 1F
// 2 = Enter	xx...... (Z) C0

- (IBAction)actionFields:(id)sender
{
	int f = [sender tag];
	unsigned char v = [sender intValue];
	
	switch (f) {
		case 0: keyAreas[sel][cr].z = (keyAreas[sel][cr].z & 0xC0) | (v & 0x3F); break;
		case 1: keyAreas[sel][cr].w = (keyAreas[sel][cr].w & 0xE0) | (v & 0x1F); break;
		case 2: keyAreas[sel][cr].z = ((v << 6) & 0xC0) | (keyAreas[sel][cr].z & 0x3F);
	}
}

// 0 = External			x....... (Y) 80
// 1 = Second Part		.x...... (X) 40
// 2 = Pass Through		.x...... (W) 40
// 3 = Fall				x....... (W) 80

- (IBAction)actionFlags:(id)sender
{
	int r = [sender selectedRow];
	unsigned char v = [[sender selectedCell] state];
	
	switch (r) {
		case 0: keyAreas[sel][cr].y = (v << 7) | (keyAreas[sel][cr].y & 0x7F); break;
		case 1: keyAreas[sel][cr].x = (keyAreas[sel][cr].x & 0x80) | (v << 6) | (keyAreas[sel][cr].x & 0x3F); break;
		case 2: keyAreas[sel][cr].w = (keyAreas[sel][cr].w & 0x80) | (v << 6) | (keyAreas[sel][cr].w & 0x3F); break;
		case 3: keyAreas[sel][cr].w = (v << 7) | (keyAreas[sel][cr].w & 0x7F);
	}
}

# pragma mark -

- (void)rightMouseDown:(NSEvent *)event
{
	[self mouseDown:event];
}

- (void)mouseDown:(NSEvent *)event
{
	int x,y;	//NSLog(@"Overworld Click Map");
	int tag;
	unsigned char t;
	NSPoint mc = [self convertPoint:[[self window] mouseLocationOutsideOfEventStream] fromView:[[self window] contentView]];
	[self getRow:&y column:&x forPoint:mc];		//NSLog(@"%X , %X",x,y);
	
	[textPosition setStringValue:[NSString stringWithFormat:@"%X , %X",x,y]];
	
	if (([event type] == NSRightMouseDown) && (currentTile != -1)) {
		t = overworldGrid[cr][((y*0x40)+x)] & 0x0F;
		currentTile = [matrixTiles selectCellWithTag:t];
		[self changeTile:matrixTiles];
		return;
	}
	
	if (currentTool == 0) {
		
		keyAreas[sel][cr].x = (keyAreas[sel][cr].x & 0xC0) | (x & 0x3F);
		keyAreas[sel][cr].y = (keyAreas[sel][cr].y & 0x80) | ((y + 0x1E) & 0x7F);
		[self setNeedsDisplay:YES];
		
	} else if (currentTool == 1) {
		
		tag = [[self cellAtRow:y column:x] tag];
		if ((tag % 0x40) == 0) return;
		brackets[cr][tag] = !(brackets[cr][tag]);
		
	} else {
		
		[self changeTileWithTag:[[self cellAtRow:y column:x] tag]];
		[super mouseDown:event];
	}
	
	[self recalculate];
	[self setNeedsDisplay:YES];
}

- (void)changeTileWithTag:(int)tag
{
	[[self cellWithTag:tag] setImage:[tiles objectAtIndex:currentTile]];
	overworldGrid[cr][tag] = currentTile;
	[self recalculate];
}

- (void)recalculate
{
	int i,j;
	int r = 0;
	g[cr] = 0;
	int rows = [self numberOfRows];
	int cols = [self numberOfColumns];
	unsigned char ct;
	unsigned char ima;
	
	//NSLog(@"--- Start Calc ---");
	
	for (i=0; i<rows; i++) {
		
		ima = overworldGrid[cr][i*0x40];
		for (j=1; j<cols; j++) {
			
			ct = overworldGrid[cr][(i*0x40)+j];
			
			if ((ct != ima) || (brackets[cr][((i*0x40)+j)] == 1)) {
				
				//if (ct == nil) break;
				
				overworldData[cr][g[cr]] = (r*0x10) + ima; //if (i < 7) NSLog(@"Data : %X",overworldData[cr][g[cr]]);
				g[cr]++; r = 0;
				ima = ct;
				
			} else {
				
				r++;
				if (r == 16) {
					overworldData[cr][g[cr]] = 0xF0 + ima; //if (i < 7) NSLog(@"Data : %X",overworldData[cr][g[cr]]);
					g[cr]++; r = 0;
				}
			}
		}
		
		overworldData[cr][g[cr]] = (r << 4) + ima;
		g[cr]++; r = 0;
	}
	
	[textGroups setStringValue:[NSString stringWithFormat:@"%X / %X",g[cr],maxGroups]];
	
	if (g[cr] <= maxGroups[cr]) [textGroups setTextColor:[NSColor blueColor]];
	if (g[cr] > maxGroups[cr]) [textGroups setTextColor:[NSColor redColor]];
	else {
		[textGroups setTextColor:[NSColor blackColor]];
		for (i=g[cr]; i<maxGroups[cr]; i++) {
			overworldData[cr][i] = 0xFF;
		}
	}
}

- (void)drawRect:(NSRect)theRect
{
	//[testimg drawAtPoint:NSMakePoint(0,0) fromRect:NSZeroRect operation:2 fraction:1.0];
	
	int rc;
	const NSRect *rects;
	[self getRectsBeingDrawn:&rects count:&rc];
	
	//if (rc > 1) NSLog(@"Number of Rects : %d",rc);
	//NSLog(@"Rects : %4.1f,%4.1f,%4.1f,%4.1f",rects[0].origin.x,rects[0].origin.y,rects[0].size.width,rects[0].size.height);
	
	while (rc-- >= 0) {
		[super drawRect:rects[rc]];
	}
	
	// Draw Grid //
	
	NSBezierPath *grid = [NSBezierPath bezierPath];
	NSRect rect;
	int i;
	
	[[NSGraphicsContext currentContext] setShouldAntialias:NO];
	
	if (showGrid) {
		
		for (i=1; i<[self numberOfColumns]; i++) {
			[grid moveToPoint:NSMakePoint( i * [self cellSize].width , 0 )];
			[grid lineToPoint:NSMakePoint( i * [self cellSize].width , [self bounds].size.height )];
		}
		
		for (i=1; i<[self numberOfRows]; i++) {
			[grid moveToPoint:NSMakePoint( 0 , i * [self cellSize].height )];
			[grid lineToPoint:NSMakePoint( [self bounds].size.width , i * [self cellSize].height )];
		}
		
		[[NSColor colorWithDeviceWhite:0.0 alpha:0.7] set];
		[grid stroke];
	}
	
	// Draw Key Area Markers //
	
	char p1,p2;
	NSBezierPath *kam;
	
	if (sel == -1) { p1 = 0; p2 = 0x3F; }
	else { p1 = sel; p2 = sel+1; }
	
	//[[NSColor colorWithDeviceRed:0.8 green:0.0 blue:0.8 alpha:0.5] set];
	
	for (i=p1; i<p2; i++) {
		
		rect.origin.x = (keyAreas[i][cr].x & 0x3F) * 16; rect.origin.x += 1;
		rect.origin.y = ((keyAreas[i][cr].y - 0x1E) & 0x7F) * 16;
		rect.size.width = 15;
		rect.size.height = 15;
		kam = [NSBezierPath bezierPathWithRect:rect];
		
		if (sel != -1) {
			[[NSColor colorWithDeviceWhite:1.0 alpha:0.9] set];
			[kam setLineWidth:2];
			[kam stroke];
		} else {
			//[kam fill];
			[[NSColor colorWithDeviceWhite:1.0 alpha:0.9] set];
			[kam setLineWidth:2];
			[kam stroke];
		}
	}
	
	// Draw Brackets //
	
	NSPoint loc;
	NSBezierPath *bck = [NSBezierPath bezierPath];
	[bck setLineWidth:2];
	for (i=0; i<0x10000; i++) {
		
		if (brackets[cr][i] == 0) continue;
		
		loc.x = (i % 0x40) * [self cellSize].width; loc.x += 1;
		loc.y = (i / 0x40) * [self cellSize].height;
		
		[bck moveToPoint:loc];
		[bck lineToPoint:NSMakePoint( loc.x , loc.y += [self cellSize].height )];
		
		[bck moveToPoint:NSMakePoint( loc.x - ([self cellSize].width / 4) , loc.y - 1 )];
		[bck lineToPoint:NSMakePoint( loc.x + ([self cellSize].width / 4) , loc.y - 1 )];
		[bck moveToPoint:NSMakePoint( loc.x - ([self cellSize].width / 4) , loc.y - [self cellSize].height )];
		[bck lineToPoint:NSMakePoint( loc.x + ([self cellSize].width / 4) , loc.y - [self cellSize].height )];
		
		[[NSColor colorWithDeviceHue:0 saturation:0.8 brightness:0.8 alpha:1.0] set];
		[bck stroke];
	}
}

# pragma mark -

- (NSImage *)tileWithOffset:(int)os palette:(struct sCol *)pal data:(NSData *)data
{
	const char *p1;
	unsigned char *p2;
	
	p1 = [rom bytes] + 0x20000 + (8 * 0x2000) + 0x1000 + os + 0x10;
	
	int wh = sr * 8;
	
	NSImage *tileImage = [[[NSImage alloc] initWithSize:NSMakeSize(wh,wh)] autorelease];
	NSBitmapImageRep *tileRep = [[NSBitmapImageRep alloc] 
				initWithBitmapDataPlanes:NULL
							  pixelsWide:wh
							  pixelsHigh:wh
						   bitsPerSample:8
						 samplesPerPixel:4
								hasAlpha:YES
								isPlanar:NO
						  colorSpaceName:NSDeviceRGBColorSpace
							 bytesPerRow:(wh * 4)
							bitsPerPixel:32];
	
	p2 = [tileRep bitmapData];
	
	int i,j,k1,k2;
	unsigned char b1,b2,cp;
	
	for (i=0; i<8; i++) {
		
		b1 = *p1;
		b2 = *(p1 + 8);
		
		for (j=7; j>=0; j--) {
			
			cp = ((b1 >> j) & 0x01) + (((b2 >> j) & 0x01) * 2);		// Bit Weight (0 1 2 3)
			
			for (k1=0; k1<sr*4; k1+=4) {
				for (k2=0; k2<sr*4; k2+=4) {
					
					if (pal[cp].r == 0xEF) {
						*( ( p2 + (wh * k1) ) + k2) = 0;
						*( ( p2 + (wh * k1) ) + k2 + 1) = 0;
						*( ( p2 + (wh * k1) ) + k2 + 2) = 0;
						*( ( p2 + (wh * k1) ) + k2 + 3) = 0;
					} else {
						*( ( p2 + (wh * k1) ) + k2) = pal[cp].r;
						*( ( p2 + (wh * k1) ) + k2 + 1) = pal[cp].g;
						*( ( p2 + (wh * k1) ) + k2 + 2) = pal[cp].b;
						*( ( p2 + (wh * k1) ) + k2 + 3) = 0xFF;
					}
					
				}
			}
			
			p2 += (sr * 4);
			
		}
		
		p2 += sr * (sr - 1) * 8 * 4;
		p1++;
		
	}
	
	[tileImage addRepresentation:tileRep];
	return tileImage;
}

/*- (NSImage *)tileWithOffset:(int)os palette:(struct sCol *)pal
{
	const char *p1;
	unsigned char *p2;
	
	p1 = [rom bytes] + os;
	int wh = sr * 8;
	
	NSImage *tileImage = [[NSImage alloc] initWithSize:NSMakeSize(wh,wh)];
	NSBitmapImageRep *tileRep = [[NSBitmapImageRep alloc] 
				initWithBitmapDataPlanes:NULL
							  pixelsWide:wh
							  pixelsHigh:wh
						   bitsPerSample:8
						 samplesPerPixel:3
								hasAlpha:NO
								isPlanar:NO
						  colorSpaceName:NSCalibratedRGBColorSpace
							 bytesPerRow:(wh * 3)
							bitsPerPixel:24];
	
	p2 = [tileRep bitmapData];
	
	int i,j,k1,k2;
	unsigned char b1,b2,cp;
	
	for (i=0; i<8; i++) {
		b1 = *p1;
		b2 = *(p1 + 8);
		for (j=7; j>=0; j--) {
			cp = ((b1 >> j) & 0x01) + (((b2 >> j) & 0x01) * 2);
			for (k1=0; k1<sr*3; k1+=3) {
				for (k2=0; k2<sr*3; k2+=3) {
					*( ( p2 + (wh * k1) ) + k2) = pal[cp].r;
					*( ( p2 + (wh * k1) ) + k2 + 1) = pal[cp].g;
					*( ( p2 + (wh * k1) ) + k2 + 2) = pal[cp].b;
				}
			}
			p2 += (sr * 3);
		}
		p2 += sr * (sr - 1) * 8 * 3;
		p1++;
	}
	
	[tileImage addRepresentation:tileRep];
	return tileImage;
}*/

- (NSImage *)graphicWithTiles:(NSArray *)tilesList type:(unsigned char)size
{
	int h = size & 0x0F;
	int w = (size & 0xF0) >> 4;
	
	if (size == 0) { h = 0x10; w = 0x10; }
	
	int width = w * 8 * sr;
	int height = h * 8 * sr;
	
	NSImage *tileGraphic = [[[NSImage alloc] initWithSize:NSMakeSize(width,height)] autorelease];
	NSBitmapImageRep *tileRep = [[NSBitmapImageRep alloc] 
				initWithBitmapDataPlanes:NULL
							  pixelsWide:width
							  pixelsHigh:height
						   bitsPerSample:8
						 samplesPerPixel:4
								hasAlpha:YES
								isPlanar:NO
						  colorSpaceName:NSDeviceRGBColorSpace
							 bytesPerRow:(width * 4)
							bitsPerPixel:32];
	
	[tileGraphic addRepresentation:tileRep];
	
	NSImage *imageToDraw;
	NSPoint pt;
	
	[tileGraphic lockFocus];
	int i,j;
	for (i=0; i<h; i++) {
		for (j=0; j<w; j++) {
			imageToDraw = [tilesList objectAtIndex:j+(i*w)];
			pt.y = (h - i - 1) * [imageToDraw size].height;
			pt.x = j * [imageToDraw size].width;
			[imageToDraw drawAtPoint:pt fromRect:NSZeroRect operation:1 fraction:1.0];
		}
	}
	[tileGraphic unlockFocus];
	
	return tileGraphic;
}

# pragma mark -

- (void)palacePointers
{
	int c = 0;
	unsigned short i,f,r;
	unsigned short s[3];
	unsigned short *palacePtr;
	palacePtr = &s[0];
	
	for (i=0; i<maxGroups[cr]; i++) {
		if (overworldData[cr][i] == 0x02) {
			f = (i + 0x7C00);
			r = ( (f << 8) | (f >> 8) );
			//NSLog(@"f : %X",f);
			//NSLog(@"r : %X",r);
			if ( (offSet == 0x506C) && (c != 1) ) {
				*palacePtr = r;
				//NSLog(@"*ptr : %X",*ptr);
				palacePtr++;
			}
			c++;
		}
		//if (c == maxPalaces) break;
	}
	palacePtr -= 3;
	offSetPalaces = 0x7C18;
	NSRange rn = { offSetPalaces , 6 };
	[rom replaceBytesInRange:rn withBytes:palacePtr];
}

- (IBAction)exportRegion:(id)sender
{
	int i,j;
	int rows = [self numberOfRows];
	int cols = [self numberOfColumns];
	
	int res;
	NSSavePanel *sp = [NSSavePanel savePanel];
	[sp setRequiredFileType:@"tiff"];
	res = [sp runModalForDirectory:nil file:nil];
	
	if (res == NSOKButton) {
		
		NSImage *image = [[NSImage alloc] initWithSize:[self bounds].size];
		
		[image lockFocus];
		for (i=0; i<rows; i++) {
			for (j=0; j<cols; j++) {
				[[self cellAtRow:i column:j] drawInteriorWithFrame:NSMakeRect(j*16,(rows-i-1)*16,16,16) inView:nil];
			}
		}
		[image unlockFocus];
		
		NSArray *ar = [image representations];
		[[ar lastObject] setAlpha:NO];
		
		NSData *ddd = [image TIFFRepresentationUsingCompression:NSTIFFCompressionLZW factor:1.0];
		[ddd writeToFile:[sp filename] atomically:YES];
		
	}
}

# pragma mark -

- (unsigned int)stringToHex:(NSString *)str
{
	unsigned int res = 0;
	unsigned short temp;
	unsigned char move = 0x00000000000000000000000000000000;	// Why not?
	
	int i;
	for (i=[str length]-1; i>=0; i--) {
		temp = [[str uppercaseString] characterAtIndex:i];
		if ((temp >= 'A') && (temp <= 'F')) temp -= 0x37;
		else temp -= 0x30;
		res |= temp <<= move;
		move += 4;
	}
	
	return res;
}

- (NSString *)hexToString:(unsigned int)hex
{
	NSMutableString *res = [NSMutableString stringWithCapacity:4];
	[res setString:[NSString stringWithFormat:@"%X",hex]];
	
	while ([res length] < 2) {
		[res insertString:@"0" atIndex:0];
	}
	
	return res;
}

# pragma mark -

- (BOOL)acceptsFirstMouse:(NSEvent *)ev
{
	return NO;
}

/*
- (NSRect)adjustScroll:(NSRect)proposedVisibleRect		// To be reviewed...
{
	NSRect modifiedRect = proposedVisibleRect;
	modifiedRect.origin.x = (int)(modifiedRect.origin.x/16.0) * 16.0;
	modifiedRect.origin.y = (int)(modifiedRect.origin.y/16.0) * 16.0;
	return modifiedRect;
}
*/

- (void)updateTrackingAreas
{
	// Nothing...
}

@end
