#import "NGSCategories.h"

@implementation NSArray (NGSIndexExtensions)
- (NSArray *)subarrayWithIndicies:(NSIndexSet *)indicies
{
	NSRange range = {0,[self count]};
	unsigned int count = [indicies count];
	unsigned int *buffer = (unsigned int *) calloc(count, sizeof(int));
	NSMutableArray *newArray = [NSMutableArray arrayWithCapacity:count];
	[indicies getIndexes:buffer maxCount:count inIndexRange:&range];
	for(unsigned int i = 0; i < count; i++)
		[newArray addObject:[self objectAtIndex:*(buffer+i)]];
	return [NSArray arrayWithArray:newArray];
}
@end

@implementation NSArray (NGSKeyValueExtensions)
- (int)indexOfFirstObjectReturningValue:(id)value forKey:(id)key
{
	return [[self valueForKey:key] indexOfObject:value];
}
- (id)firstObjectReturningValue:(id)value forKey:(id)key
{
	int index = [[self valueForKey:key] indexOfObject:value];
	if(index != NSNotFound)
		return [self objectAtIndex:index];
	else return nil;
}
- (NSArray *)objectsReturningValue:(id)value forKey:(id)key
{
	id object;
	NSMutableArray *array = [NSMutableArray array];
	NSEnumerator *enumerator = [self objectEnumerator];
	while(object = [enumerator nextObject])
		if([[object valueForKey:key] isEqual:value])
			[array addObject:object];
	return [NSArray arrayWithArray:array];
}
- (NSArray *)arrayByMakingObjectsPerformSelector:(SEL)selector withObject:(id)inObject
{
	id object;
	NSMutableArray *array = [NSMutableArray array];
	NSEnumerator *enumerator = [self objectEnumerator];
	while(object = [enumerator nextObject])
		[array addObject:[object performSelector:selector withObject:inObject]];
	return [NSArray arrayWithArray:array];
}
@end

#pragma mark -

@implementation NSCharacterSet (NGSCharacterSetExtensions)
#if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4
+ (NSCharacterSet *)newlineCharacterSet
{
	unsigned char bitmapRep[8192];
	bitmapRep[0x0A >> 3] |= (((unsigned int)1) << (0x0A & 7));
	bitmapRep[0x0B >> 3] |= (((unsigned int)1) << (0x0B & 7));
	bitmapRep[0x0C >> 3] |= (((unsigned int)1) << (0x0C & 7));
	bitmapRep[0x0D >> 3] |= (((unsigned int)1) << (0x0D & 7));
	bitmapRep[0x85 >> 3] |= (((unsigned int)1) << (0x85 & 7));
	NSData *data = [NSData dataWithBytesNoCopy:bitmapRep length:8192 freeWhenDone:YES];
	return [NSCharacterSet characterSetWithBitmapRepresentation:data];
}
#endif
+ (NSCharacterSet *)tabCharacterSet
{
	unsigned char bitmapRep[8192];
	bitmapRep[0x09 >> 3] |= (((unsigned int)1) << (0x09 & 7));
	bitmapRep[0x0B >> 3] |= (((unsigned int)1) << (0x0B & 7));
	NSData *data = [NSData dataWithBytesNoCopy:bitmapRep length:8192 freeWhenDone:YES];
	return [NSCharacterSet characterSetWithBitmapRepresentation:data];
}
@end

#pragma mark -

@implementation NSIndexSet (NGSIndicies)
+ (id)indexSetWithIndiciesInRange:(NSRange)range
{	return [NSIndexSet indexSetWithIndexesInRange:range]; }
- (id)initWithIndiciesInRange:(NSRange)range
{	return [self initWithIndexesInRange:range]; }
- (unsigned int)getIndicies:(unsigned int *)indexBuffer maxCount:(unsigned int)bufferSize inIndexRange:(NSRangePointer)range
{	return [self getIndexes:indexBuffer maxCount:bufferSize inIndexRange:range]; }
- (BOOL)containsIndiciesInRange:(NSRange)range
{	return [self containsIndexesInRange:range]; }
- (BOOL)containsIndicies:(NSIndexSet *)indexSet
{	return [self containsIndexes:indexSet]; }
- (BOOL)intersectsIndiciesInRange:(NSRange)range
{	return [self intersectsIndexesInRange:range]; }
@end

@implementation NSMutableIndexSet (NGSIndicies)
- (void)addIndicies:(NSIndexSet *)indexSet
{	[self addIndexes:indexSet]; }
- (void)removeIndicies:(NSIndexSet *)indexSet
{	[self removeIndexes:indexSet]; }
- (void)removeAllIndicies
{	[self removeAllIndexes]; }
- (void)addIndiciesInRange:(NSRange)range
{	[self addIndexesInRange:range]; }
- (void)removeIndiciesInRange:(NSRange)range
{	[self removeIndexesInRange:range]; }
- (void)shiftIndiciesStartingAtIndex:(unsigned int)index by:(int)delta
{	[self shiftIndexesStartingAtIndex:index by:delta]; }   
@end

#pragma mark -

@implementation NSNumber (NGSRangeExtensions)
- (BOOL)isWithinRange:(NSRange)range				// location <= self <= location+length
{
	// e.g. for {6,1} a value of 6.000 will return true, as will 7.000
	return [self compare:[NSNumber numberWithInt:range.location]] != NSOrderedAscending && [self compare:[NSNumber numberWithInt:range.location+range.length]] != NSOrderedDescending;
}
- (BOOL)isExclusivelyWithinRange:(NSRange)range		// location < self < location+length
{
	// e.g. for {6,1} a value of 6.000 will return false, 6.001 will return true, 6.999 will return true, 7.000 false
	return [self compare:[NSNumber numberWithInt:range.location]] == NSOrderedDescending && [self compare:[NSNumber numberWithInt:range.location+range.length]] == NSOrderedAscending;
}
- (BOOL)isBoundedByRange:(NSRange)range				// location <= self < location+length
{
	// e.g. for {6,1} a value of 6.000 will return true, 6.999 will return true, 7.000 will not
	return [self compare:[NSNumber numberWithInt:range.location]] != NSOrderedAscending && [self compare:[NSNumber numberWithInt:range.location+range.length]] == NSOrderedAscending;
}
@end

#pragma mark -

@implementation NSString (NGSFSSpecExtensions)
- (FSRef *)createFSRef
{
	// caller is responsible for disposing of the FSRef (method is a 'create' method)
	FSRef *fsRef = (FSRef *) NewPtrClear(sizeof(FSRef));
	OSStatus error = FSPathMakeRef((const UInt8 *)[self fileSystemRepresentation], fsRef, NULL);
	if(error != noErr) fsRef = NULL;
	return fsRef;
}
- (FSSpec *)createFSSpec
{
	// caller is responsible for disposing of the FSSpec (method is a 'create' method)
	FSRef *fsRef = (FSRef *) NewPtrClear(sizeof(FSRef));
	FSSpec *fsSpec = (FSSpec *) NewPtrClear(sizeof(FSSpec));
	OSStatus error = FSPathMakeRef((const UInt8 *)[self fileSystemRepresentation], fsRef, NULL);
	if(error == noErr)
	{
		error = FSGetCatalogInfo(fsRef, kFSCatInfoNone, NULL, NULL, fsSpec, NULL);
		if(error == noErr)
		{
			DisposePtr((Ptr)fsRef);
			return fsSpec;
		}
	}
	DisposePtr((Ptr)fsRef);
	DisposePtr((Ptr)fsSpec);
	return NULL;
}
@end

@implementation NSString (NGSBooleanExtensions)
#if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4
- (BOOL)boolValue
{
	return ![self isEqualToString:@"NO"];
}
#endif
+ (NSString *)stringWithBool:(BOOL)boolean
{
	return boolean? @"YES" : @"NO";
}
@end

#pragma mark -

#if MAC_OS_X_VERSION_10_3 <= MAC_OS_X_VERSION_MAX_ALLOWED
/*
@implementation NSMatrix (NGSSelectionIndicies)
- (NSIndexSet *)selectedRows
{
	int numRows, numCols;
	NSMutableIndexSet *rows = [[NSMutableIndexSet alloc] init];
	[self getNumberOfRows:&numRows columns:&numCols];
	for(int r = 0; r < numRows; r++)
	{
		for(int c = 0; c < numCols; c++)
		{
			if()
			{
				c = numCols;
				continue;
			}
		}
	}
}
- (NSIndexSet *)selectedColumns
{
	NSMutableIndexSet *columns = [[NSMutableIndexSet alloc] init];
}
@end
*/
#endif

@implementation NSOutlineView (NGSSelectedItemExtensions)
- (id)selectedItem
{
	if([self numberOfSelectedRows] != 1) return nil;
	else return [self itemAtRow:[self selectedRow]];
}
- (NSArray *)selectedItems;
{
	NSNumber *row;
	NSMutableArray *items = [NSMutableArray array];
	NSEnumerator *enumerator = [self selectedRowEnumerator];
	while(row = [enumerator nextObject])
		[items addObject:[self itemAtRow:[row intValue]]];
	return items;
}
@end

#pragma mark -

#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5

@implementation NSGradient (NGSGradientExtensions)
+ (NSGradient *)aquaGradient
{
	NSGradient *gradient = [[NSGradient alloc] initWithColorsAndLocations:
		[NSColor colorWithCalibratedWhite: 0.95 alpha: 1.0], 0.0,
		[NSColor colorWithCalibratedWhite: 0.83 alpha: 1.0], 0.5,
		[NSColor colorWithCalibratedWhite: 0.95 alpha: 1.0], 0.5,
		[NSColor colorWithCalibratedWhite: 0.92 alpha: 1.0], 1.0, nil];
	return [gradient autorelease];
}
+ (NSGradient *)aquaGradientWithAlpha:(CGFloat)alpha
{
	NSGradient *gradient = [[NSGradient alloc] initWithColorsAndLocations:
		[NSColor colorWithCalibratedWhite: 0.95 alpha: alpha], 0.0,
		[NSColor colorWithCalibratedWhite: 0.83 alpha: alpha], 0.5,
		[NSColor colorWithCalibratedWhite: 0.95 alpha: alpha], 0.5,
		[NSColor colorWithCalibratedWhite: 0.92 alpha: alpha], 1.0, nil];
	return [gradient autorelease];
}
- (NSGradient *)gradientWithAlpha:(CGFloat)alpha
{
	NSColor *colour;
	NSInteger stops = [self numberOfColorStops];
	NSMutableArray *colours = [NSMutableArray array];
	CGFloat *locations = (CGFloat *) calloc(sizeof(CGFloat), stops);
	for(NSInteger i = 0; i < stops; i++)
	{
		[self getColor: &colour location: &(locations[i]) atIndex: i];
		[colours addObject: [colour colorWithAlphaComponent: alpha]];
	}
	NSGradient *gradient = [[NSGradient alloc] initWithColors: colours atLocations: locations colorSpace: [self colorSpace]];
	return [gradient autorelease];
}
@end

#endif

#pragma mark -

/* CGLContext access for pre-10.3 */
@implementation NSOpenGLContext (CGLContextAccess)
- (CGLContextObj)cglContext;
{
	if(NSAppKitVersionNumber < 700.0)
		return _contextAuxiliary;
	else return (CGLContextObj) [self CGLContextObj];
}
@end