/* MAConcreteNumber - Concrete subclasses of MANumber
    
   Copyright (C) 1995, Adam Fedor.

*/
# line 6 "MAConcreteNumber.m"

#ifndef GNUSTEP
#import <Foundation/Foundation.h>
#else
#include <Foundation/NSString.h>
#include <Foundation/NSException.h>
#include <Foundation/NSCoder.h>
#endif
#include "MAConcreteNumber.h"
#include "MathArray/array_encoding.h"

/* This file should be run through a preprocessor with the macro MATH_ORDER
   defined to a number from 0 to 1 cooresponding to each number type */
#if MATH_ORDER == 0
#  define NumberTemplate	MAComplexFloatNumber
#  define TYPE_METHOD	complexFloatValue
#  define TYPE_FORMAT	@"{%f,%f}"
#elif MATH_ORDER == 1
#  define NumberTemplate	MAComplexDoubleNumber
#  define TYPE_METHOD	complexDoubleValue
#  define TYPE_FORMAT	@"{%g,%g}"
#endif

@implementation NumberTemplate

- initValue:(const void *)value withObjCType:(const char *)type
{
    /* Don't [super init]! This will replace our object with some
       other default object
    self = [super init];
    */
    data = *(__typeof__(data) *)value;
    return self;
}

- (BOOL)boolValue
{
    return data.real;
}

- (char)charValue
{
    return data.real;
}

- (double)doubleValue
{
    return data.real;
}

- (float)floatValue
{
    return data.real;
}

- (int)intValue
{
    return data.real;
}

- (long long)longLongValue
{
    return data.real;
}

- (long)longValue
{
    return data.real;
}

- (short)shortValue
{
    return data.real;
}

- (NSString *)stringValue
{
    return [NSString stringWithFormat:TYPE_FORMAT, data.real, data.imag];
}

- (unsigned char)unsignedCharValue
{
    return data.real;
}

- (unsigned int)unsignedIntValue
{
    return data.real;
}

- (unsigned long long)unsignedLongLongValue
{
    return data.real;
}

- (unsigned long)unsignedLongValue
{
    return data.real;
}

- (unsigned short)unsignedShortValue
{
    return data.real;
}

- (complex_float)complexFloatValue
{
#if MATH_ORDER == 0
    return data;
#else
    complex_float other;
    other.real = data.real; other.imag = data.imag;
    return other;
#endif
}

- (complex_double)complexDoubleValue
{
#if MATH_ORDER == 0
    complex_double other;
    other.real = data.real; other.imag = data.imag;
    return other;
#else
    return data;
#endif
}

- (NSComparisonResult)compare:(NSNumber *)otherNumber
{
    __typeof__(data) other_data = [otherNumber TYPE_METHOD];
    
    if (data.real == other_data.real && data.imag == other_data.imag)
    	return NSOrderedSame;
    else  // FIXME you can't order complex numbers.  What should this do?
    	return NSOrderedAscending;
}

// Override these from NSValue
- (void)getValue:(void *)value
{
    if (!value) {
    	[NSException raise:NSInvalidArgumentException
		format:@"Cannot copy value into NULL pointer"];
	/* NOT REACHED */ 
    }
    memcpy( value, &data, math_sizeof_type([self objCType]) );
}

- (const char *)objCType
{
    return @encode(__typeof__(data));
}

// NSCoding
- (void)encodeWithCoder:(NSCoder *)coder
{
    [super encodeWithCoder:coder];
    [coder encodeValueOfObjCType:[self objCType] at:&data];
}

- (id)initWithCoder:(NSCoder *)coder
{
    self = [super initWithCoder:coder];
    [coder decodeValueOfObjCType:[self objCType] at:&data];
    return self;
}

@end

