/*	
    MANumber - Complex numbers
   
    Copyright (C) 1995, Adam Fedor

*/

#ifdef GNU_FOUNDATION
#include <objc/objc-api.h>
#else
#import <objc/objc-class.h>
#endif
#ifdef NEXT_FOUNDATION
#import <foundation/NSCoder.h>
#else
#import <Foundation/NSCoder.h>
#endif
#ifdef HAVE_FOUNDATION_NSDECIMAL_H
#import <Foundation/NSDecimalNumber.h>
#endif
#include <string.h>
#include "MathArray/NSObjectExtra.h"
#include "MAConcreteNumber.h"

@implementation MANumber

+ allocWithZone:(NSZone *)zone
{
    return NSAllocateObject(self, 0, zone);
}

/* Allocate the correct class for the type.  I wouldn't have to do
   this with GNU libobjects Foundation. Blaa!. */
#ifndef GNU_FOUNDATION
+ (NSValue *)correctValue:(const void *)value
      withObjCType:(const char *)type
{
    id number = nil;

    switch (*type) {
    case _C_CHR:
        number = [NSNumber numberWithChar:*(char *)value];
	break;
    case _C_UCHR:
        number = [NSNumber numberWithUnsignedChar:*(char *)value];
	break;
    case _C_SHT:
        number = [NSNumber numberWithShort:*(short *)value];
	break;
    case _C_USHT:
        number = [NSNumber numberWithUnsignedShort:*(short *)value];
	break;
    case _C_INT:
        number = [NSNumber numberWithInt:*(int *)value];
	break;
    case _C_UINT:
        number = [NSNumber numberWithUnsignedInt:*(int *)value];
	break;
    case _C_LNG:
        number = [NSNumber numberWithLong:*(long *)value];
	break;
    case _C_ULNG:
        number = [NSNumber numberWithUnsignedLong:*(long *)value];
	break;
    case 'q':
        number = [NSNumber numberWithLongLong:*(long long *)value];
	break;
    case 'Q':
        number = [NSNumber numberWithUnsignedLongLong:*(long long *)value];
	break;
    case _C_FLT:
        number = [NSNumber numberWithFloat:*(float *)value];
	break;
    case _C_DBL:
        number = [NSNumber numberWithDouble:*(double *)value];
	break;
    default:
        break;
    }

    return number;
}
#endif /* not GNU_FOUNDATION */

+ (NSValue *)value:(const void *)value
      withObjCType:(const char *)type
{
#ifndef GNU_FOUNDATION
    id number;
    number = [self correctValue:value withObjCType:type];
    if (number != nil)
    	return number;
#endif
    if (strcmp(type, @encode(complex_float)) == 0)
    	return [self numberWithComplexFloat:*((complex_float *)value)];
    else if (strcmp(type, @encode(complex_double)) == 0)
    	return [self numberWithComplexDouble:*((complex_double *)value)];
#ifdef HAVE_FOUNDATION_NSDECIMAL_H
    else if (strcmp(type, @encode(NSDecimal)) == 0)
    	return [NSDecimalNumber 
	         decimalNumberWithDecimal: *((NSDecimal *)value)];
#endif
    
    return [super value:value withObjCType:type];
}
		
+ (id <NSNumber,ComplexNumber>)numberWithComplexFloat:(complex_float)value
{
    return [[[MAComplexFloatNumber alloc] initValue:&value withObjCType:NULL]
    	autorelease];
}

+ (id <NSNumber,ComplexNumber>)numberWithComplexDouble:(complex_double)value
{
    return [[[MAComplexDoubleNumber alloc] initValue:&value withObjCType:NULL] 
    	autorelease];
}

- (complex_float)complexFloatValue
{
    [self maSubclassResponsibility:_cmd];
    return (complex_float){0,0};
}

- (complex_double)complexDoubleValue
{
    [self maSubclassResponsibility:_cmd];
    return (complex_double){0,0};
}

// NSCopying
- (id)copyWithZone:(NSZone *)zone
{
    if (NSShouldRetainWithZone(self, zone))
    	return [self retain];
    else
    	return [super copyWithZone:zone];
}

// NSCoding (done by subclasses)
- classForCoder
{
    return [self class];
}

- (void)encodeWithCoder:(NSCoder *)coder
{
    [super encodeWithCoder:coder];
}

- (id)initWithCoder:(NSCoder *)coder
{
    return [super initWithCoder:coder];
}

@end

@implementation NSNumber (ComplexExtensions)

/* Implement these for numbers that are NOT complex */
- (complex_float)complexFloatValue
{
    complex_float other;
    other.real = [self floatValue];
    return other;
}

- (complex_double)complexDoubleValue
{
    complex_double other;
    other.real = [self doubleValue];
    return other;
}

@end

