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

*/

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

@implementation MANumber

/* Allocate the correct class for the type.  I wouldn't have to do
   this with GNUstep. Blaa!. */
#ifndef GNUSTEP
+ (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 GNUSTEP */

+ (NSValue *)value:(const void *)value
      withObjCType:(const char *)type
{
#ifndef GNUSTEP
    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];
}

#ifndef GNUSTEP
/* OSX doesn't allow creation of a concrete class from a subclass of NSNumber */
+ (NSNumber *)numberWithChar:(char)value
{
  return [NSNumber numberWithChar: value];
}

+ (NSNumber *)numberWithUnsignedChar:(unsigned char)value
{
  return [NSNumber numberWithUnsignedChar: value];
}

+ (NSNumber *)numberWithShort:(short)value
{
  return [NSNumber numberWithShort: value];
}

+ (NSNumber *)numberWithUnsignedShort:(unsigned short)value
{
  return [NSNumber numberWithUnsignedShort: value];
}

+ (NSNumber *)numberWithInt:(int)value
{
  return [NSNumber numberWithInt: value];
}

+ (NSNumber *)numberWithUnsignedInt:(unsigned int)value
{
  return [NSNumber numberWithUnsignedInt: value];
}

+ (NSNumber *)numberWithLong:(long)value
{
  return [NSNumber numberWithLong: value];
}

+ (NSNumber *)numberWithUnsignedLong:(unsigned long)value
{
  return [NSNumber numberWithUnsignedLong: value];
}

+ (NSNumber *)numberWithLongLong:(long long)value
{
  return [NSNumber numberWithLongLong: value];
}

+ (NSNumber *)numberWithUnsignedLongLong:(unsigned long long)value
{
  return [NSNumber numberWithUnsignedLongLong: value];
}

+ (NSNumber *)numberWithFloat:(float)value
{
  return [NSNumber numberWithFloat: value];
}

+ (NSNumber *)numberWithDouble:(double)value
{
  return [NSNumber numberWithDouble: value];
}

+ (NSNumber *)numberWithBool:(BOOL)value
{
  return [NSNumber numberWithBool: value];
}
#endif
		
+ (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

