/*
 *	Filename: TableSource.m
 *	Created : Wed Nov 27 15:15:58 1996
 *	Author  : Vince DeMarco <vdemarco@bou.shl.com>
 *	LastEditDate Was "Fri Jan 17 10:38:44 1997"
 */

#import "TableSource.h"
#import <objc/objc-class.h>
#import <Foundation/NSException.h>
#import <Foundation/NSInvocation.h>
#import <Foundation/NSMethodSignature.h>

#import <AppKit/NSTableView.h>
#import <AppKit/NSTableColumn.h>

#import "Sorting.h"

@implementation NSArray(NSArray_TableSource)


- (SEL)selectorForGetIdentifier:(NSString *)identifier
{
    SEL ident;

    ident = NSSelectorFromString(identifier);

    if (ident){
	return ident;
    }
    return 0;
}

- (SEL)selectorForSetIdentifier:(NSString *)identifier
{
    SEL       set_ident;
    NSString *string;

    string = [NSString stringWithFormat:@"set%@%@:",[[identifier substringToIndex:1] capitalizedString],
					       [identifier substringFromIndex:1]];

    set_ident = NSSelectorFromString(string);

    if (set_ident){
	return set_ident;
    }
    return 0;
}

- (int)numberOfRowsInTableView:(NSTableView *)tableView
{
    return [self count];
}

- (id)tableView:(NSTableView *)tableView
               objectValueForTableColumn:(NSTableColumn *)tableColumn
	                             row:(int)row
{

    SEL                theSelector;
    NSMethodSignature *signature;
    NSInvocation      *anInvocation;

    NSParameterAssert(row >= 0 && row < [self count]);

    theSelector	= [self selectorForGetIdentifier:[tableColumn identifier]];
    if (![[self objectAtIndex:row] respondsToSelector:theSelector]){
	[NSException raise:NSGenericException
		    format:@"Table Source <tableView:objectValueForTableColumn:row:> object does not implement selector %@",
		             [tableColumn identifier]];
	return self;
    }
    signature	= [[self objectAtIndex:row] methodSignatureForSelector:theSelector];

    NSParameterAssert([signature numberOfArguments] == 2);

    anInvocation = [NSInvocation invocationWithMethodSignature:signature];
    [anInvocation setSelector:theSelector];
    [anInvocation setTarget:[self objectAtIndex:row]];

    switch ([signature methodReturnType][0]){
    case _C_ID:
	{
	    id result;
	    [anInvocation invoke];
	    [anInvocation getReturnValue:&result];
	    return result;
	}
    case _C_CLASS:
	{
	    Class result;
	    [anInvocation invoke];
	    [anInvocation getReturnValue:&result];
	    return result;
	}
    case _C_CHR:
	{
	    char result;
	    [anInvocation invoke];
	    [anInvocation getReturnValue:&result];
	    return [NSNumber numberWithChar:result];
	}
    case _C_UCHR:
	{
	    unsigned char result;
	    [anInvocation invoke];
	    [anInvocation getReturnValue:&result];
	    return [NSNumber numberWithUnsignedChar:result];
	}
    case _C_SHT:
	{
	    short result;
	    [anInvocation invoke];
	    [anInvocation getReturnValue:&result];
	    return [NSNumber numberWithShort:result];
	}
    case _C_USHT:
	{
	    unsigned short result;
	    [anInvocation invoke];
	    [anInvocation getReturnValue:&result];
	    return [NSNumber numberWithUnsignedShort:result];
	}
    case _C_INT:
	{
	    int result;
	    [anInvocation invoke];
	    [anInvocation getReturnValue:&result];
	    return [NSNumber numberWithInt:result];
	}
    case _C_UINT:
	{
	    unsigned int result;
	    [anInvocation invoke];
	    [anInvocation getReturnValue:&result];
	    return [NSNumber numberWithUnsignedInt:result];
	}
    case _C_LNG:
	{
	    long int result;
	    [anInvocation invoke];
	    [anInvocation getReturnValue:&result];
	    return [NSNumber numberWithLong:result];
	}
    case _C_ULNG:
	{
	    unsigned long int result;
	    [anInvocation invoke];
	    [anInvocation getReturnValue:&result];
	    return [NSNumber numberWithUnsignedLong:result];
	}
    case _C_FLT:
	{
	    float result;
	    [anInvocation invoke];
	    [anInvocation getReturnValue:&result];
	    return [NSNumber numberWithFloat:result];
	}
    case _C_DBL:
	{
	    double result;
	    [anInvocation invoke];
	    [anInvocation getReturnValue:&result];
	    return [NSNumber numberWithDouble:result];
	}
    case _C_CHARPTR:
	{
	    char           *result;
	    [anInvocation invoke];
	    [anInvocation getReturnValue:&result];
	    return [NSString stringWithCString:result];
	}
    default:
	return nil;
    }
}

- (void)tableView:(NSTableView *)tableView
   setObjectValue:(id)object
   forTableColumn:(NSTableColumn *)tableColumn
	      row:(int)row
{

    SEL                theSelector;
    NSMethodSignature *signature;
    NSInvocation      *anInvocation;

    NSParameterAssert(row >= 0 && row < [self count]);

    theSelector	= [self selectorForSetIdentifier:[tableColumn identifier]];
    if (![[self objectAtIndex:row] respondsToSelector:theSelector]){
	[NSException raise:NSGenericException
		    format:@"Table Source <tableView:setObjectValue:row:> object does not implement selector %@",
		             [tableColumn identifier]];
	return;
    }
    signature	= [[self objectAtIndex:row] methodSignatureForSelector:theSelector];

    NSParameterAssert([signature numberOfArguments] == 3);

    anInvocation = [NSInvocation invocationWithMethodSignature:signature];
    [anInvocation setSelector:theSelector];
    [anInvocation setTarget:[self objectAtIndex:row]];

    switch ([signature getArgumentTypeAtIndex:2][0]){
    case _C_ID:
    case _C_CLASS:
	{
	    [anInvocation setArgument:&object atIndex:2];
	    [anInvocation invoke];
	    break;
	}
    case _C_CHR:
	{
	    char value;

	    value = [object charValue];
	    [anInvocation setArgument:&value atIndex:2];
	    [anInvocation invoke];
	    break;
	}
    case _C_UCHR:
	{
	    unsigned char value;

	    value = [object unsignedCharValue];
	    [anInvocation setArgument:&value atIndex:2];
	    [anInvocation invoke];
	    break;
	}
    case _C_SHT:
	{
	    short value;

	    value = [object shortValue];
	    [anInvocation setArgument:&value atIndex:2];
	    [anInvocation invoke];
	    break;
	}
    case _C_USHT:
	{
	    unsigned short value;

	    value = [object unsignedShortValue];
	    [anInvocation setArgument:&value atIndex:2];
	    [anInvocation invoke];
	    break;
	}
    case _C_INT:
	{
	    int value;

	    value = [object intValue];
	    [anInvocation setArgument:&value atIndex:2];
	    [anInvocation invoke];
	    break;
	}
    case _C_UINT:
	{
	    unsigned int value;

	    value = [object unsignedIntValue];
	    [anInvocation setArgument:&value atIndex:2];
	    [anInvocation invoke];
	    break;
	}
    case _C_LNG:
	{
	    long int value;

	    value = [object longValue];
	    [anInvocation setArgument:&value atIndex:2];
	    [anInvocation invoke];
	    break;
	}
    case _C_ULNG:
	{
	    unsigned long int value;

	    value = [object unsignedLongValue];
	    [anInvocation setArgument:&value atIndex:2];
	    [anInvocation invoke];
	    break;
	}
    case _C_FLT:
	{
	    float value;

	    value = [object floatValue];
	    [anInvocation setArgument:&value atIndex:2];
	    [anInvocation invoke];
	    break;
	}
    case _C_DBL:
	{
	    double value;

	    value = [object doubleValue];
	    [anInvocation setArgument:&value atIndex:2];
	    [anInvocation invoke];
	    break;
	}
    case _C_CHARPTR:
	{
	    const char *value;

	    value = [object cString];
	    [anInvocation setArgument:(void *)value atIndex:2];
	    [anInvocation invoke];
	    break;
	}
    default:
	break;
    }
}
@end
