/* 
   Copyright (C) 1996 
	Ovidiu Predescu <ovidiu@bx.logicnet.ro>
	Mircea Oancea <mircea@jupiter.elcom.pub.ro>

   Author: Ovidiu Predescu <ovidiu@bx.logicnet.ro>

   This file is part of the FoundationExtensions library.

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public
   License along with this library; see the file COPYING.LIB.
   If not, write to the Free Software Foundation,
   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/

#include "MissingMethods.h"
#include <extensions/common.h>
#include <extensions/objc-runtime.h>
#include <extensions/exceptions/GeneralExceptions.h>

void __MissingMethods_dummy_function_for_stupid_linkers()
{
}

#if NeXT_foundation_LIBRARY

@implementation NSArray (MissingMethods)
- (NSArray*)arrayByAddingObject:(id)anObject
{
    int i, count = [self count];
    id *objects = Malloc(sizeof(id)*(count+1));
    id array;

    for (i = 0; i < count; i++)
	objects[i] = [self objectAtIndex:i];
    objects[i] = anObject;

    array = [[[isa allocWithZone:NULL] 
		    initWithObjects:objects count:count+1]
		    autorelease];

    Free(objects);
    return array;
}

- (NSArray *)arrayByAddingObjectsFromArray:(NSArray *)anotherArray
{
    unsigned int i, count = [self count], another = [anotherArray count];
    id array;
    id *objects = Malloc(sizeof(id)*(count+another));
    
    for (i=0; i<count; i++)
	objects[i] = [self objectAtIndex:i];
    for (i=0; i<another; i++)
	objects[i+count] = [anotherArray objectAtIndex:i];

    array = [[[NSArray allocWithZone:NULL] 
			initWithObjects:objects count:count+another]
			autorelease];
    
    Free(objects);
    return array;
}

- (NSString *)componentsJoinedByString:(NSString *)separator
{
    unsigned int index, count = [self count];

    if(count) {
	id string = [[[self objectAtIndex:0] description] mutableCopy];

	for (index = 1; index < count; index++) {
	    [string appendString:separator];
	    [string appendString:[[self objectAtIndex:index] description]];
	}
	return [string autorelease];
    }

    return nil;
}

@end /* NSArray (MissingMethods) */


@implementation NSMutableArray (MissingMethods)
- (void)setArray:(NSArray *)otherArray
{
    [self removeAllObjects];
    [self addObjectsFromArray:otherArray];
}
@end /* NSMutableArray (MissingMethods) */

#endif /* NeXT_foundation_LIBRARY */


@implementation NSDictionary (MissingMethods)

- (id)initWithObjectsAndKeys:(id)firstObject arguments:(va_list)argList
{
    id object;
    id *ka, *oa;
    va_list va = argList;
    int count = 0;
    
    for (object = firstObject; object; object = va_arg(va,id)) {
	if (!va_arg(va,id))
	    THROW([[InvalidArgumentException alloc] 
		    initWithReason:@"Nil key to be added in dictionary"]);
	count++;
    }
    
    ka = Malloc(sizeof(id)*count);
    oa = Malloc(sizeof(id)*count);
    
    for (count=0, object=firstObject; object; object=va_arg(argList,id)) {
	ka[count] = va_arg(argList,id);
	oa[count] = object;
	count++;
    }

    [self initWithObjects:oa forKeys:ka count:count];

    Free(ka);
    Free(oa);
    return self;
}

#ifndef GNUSTEP_BASE_LIBRARY

+ (id)dictionaryWithObjectsAndKeys:(id)firstObject, ...
{
    id dict = [self alloc];
    va_list va;
    va_start(va, firstObject);
    [dict initWithObjectsAndKeys:firstObject arguments:va];
    va_end(va);
    return [dict autorelease];
}

#endif

#if NeXT_foundation_LIBRARY

- (id)initWithObjects:(NSArray*)objects forKeys:(NSArray*)keys
{
    unsigned int i, count = [objects count];
    id *mkeys;
    id *mobjs;

    if (count != [keys count])
	THROW([[InvalidArgumentException alloc] initWithReason:
		@"NSDictionary initWithObjects:forKeys must \
		    have both arguments of the same size"]);

    mkeys = Malloc(sizeof(id)*count);
    mobjs = Malloc(sizeof(id)*count);

    for (i=0; i<count; i++) {
	mkeys[i] = [keys objectAtIndex:i];
	mobjs[i] = [objects objectAtIndex:i];
    }

    [self initWithObjects:mobjs forKeys:mkeys count:count];
    
    Free(mkeys);
    Free(mobjs);
    return self;
}

#endif

@end /* NSDictionary (MissingMethods) */


@implementation NSMutableDictionary (MissingMethods)
- (void)setDictionary:(NSDictionary*)otherDictionary
{
    [self removeAllObjects];
    [self addEntriesFromDictionary:otherDictionary];
}
@end /* NSMutableDictionary (MissingMethods) */


#if NeXT_foundation_LIBRARY || Sun_Foundation_LIBRARY

@implementation NSObject (MissingMethods)
/* Not really missing, but these methods are useful at least in the earliear
    stages of development :-) */
- subclassResponsibility:(SEL)aSel
{
    id exception = [[ObjcRuntimeException alloc]
			    initWithFormat:@"subclass should override %s",
			    sel_get_name(aSel)];
    THROW(exception);
    return self;
}

- notImplemented:(SEL)aSel
{
    id reason = [NSString stringWithFormat:@"%s does not implement %s",
			    object_get_class_name(self), sel_get_name(aSel)];
    id exception = [[ObjcRuntimeException alloc]
			initWithName:@"ObjcRuntimeException"
			reason:reason userInfo:nil];
    THROW(exception);
    return self;
}
@end /* NSObject (MissingMethods) */

#endif /* NeXT_foundation_LIBRARY || Sun_Foundation_LIBRARY */


#if NeXT_foundation_LIBRARY || GNUSTEP_BASE_LIBRARY

@implementation NSString (MissingMethods)
- (NSString *)substringWithRange:(NSRange)range
{
    return [self substringFromRange:range];
}
@end

#endif /* NeXT_foundation_LIBRARY */

#if NeXT_foundation_LIBRARY

@implementation NSNumber(MissingMethods)

+ (NSNumber*)numberWithBool:(BOOL)value
{
    return [[[NSBoolNumber alloc] 
		initValue:&value withObjCType:NULL] 
		autorelease];
}

+ (NSNumber*)numberWithChar:(char)value
{
    return [[[NSCharNumber alloc] 
		initValue:&value withObjCType:NULL] 
		autorelease];
}

+ (NSNumber*)numberWithUnsignedChar:(unsigned char)value
{
    return [[[NSUCharNumber alloc] 
		initValue:&value withObjCType:NULL] 
		autorelease];
}

+ (NSNumber*)numberWithShort:(short)value
{
    return [[[NSShortNumber alloc] 
		initValue:&value withObjCType:NULL] 
		autorelease];
}

+ (NSNumber*)numberWithUnsignedShort:(unsigned short)value
{
    return [[[NSUShortNumber alloc] 
		initValue:&value withObjCType:NULL] 
		autorelease];
}

+ (NSNumber*)numberWithInt:(int)value
{
    return [[[NSIntNumber alloc] 
		initValue:&value withObjCType:NULL] 
		autorelease];
}

+ (NSNumber*)numberWithUnsignedInt:(unsigned int)value
{
    return [[[NSUIntNumber alloc] 
		initValue:&value withObjCType:NULL] 
		autorelease];
}

+ (NSNumber*)numberWithLong:(long)value
{
    return [[[NSLongNumber alloc] 
		initValue:&value withObjCType:NULL] 
		autorelease];
}

+ (NSNumber*)numberWithUnsignedLong:(unsigned long)value
{
    return [[[NSULongNumber alloc] 
		initValue:&value withObjCType:NULL] 
		autorelease];
}

+ (NSNumber*)numberWithLongLong:(long long)value
{
    return [[[NSLongLongNumber alloc] 
		initValue:&value withObjCType:NULL] 
		autorelease];
}

+ (NSNumber*)numberWithUnsignedLongLong:(unsigned long long)value
{
    return [[[NSULongLongNumber alloc] 
		initValue:&value withObjCType:NULL] 
		autorelease];
}

+ (NSNumber*)numberWithFloat:(float)value
{
    return [[[NSFloatNumber alloc] 
		initValue:&value withObjCType:NULL] 
		autorelease];
}

+ (NSNumber*)numberWithDouble:(double)value
{
    return [[[NSDoubleNumber alloc] 
		initValue:&value withObjCType:NULL] 
		autorelease];
}

/* These methods are not written in concrete subclassses */

- (unsigned)hash
{
	return [self unsignedIntValue];
}

- (BOOL)isEqual:(id)anObject
{
    if (self == anObject)
	return YES;
    else
	return  ([anObject isKindOfClass:[NSNumber class]]
			&& [self compare:anObject] == NSOrderedSame);
}

- (NSComparisonResult)compare:(NSNumber*)otherNumber
{
    [self subclassResponsibility:_cmd];
    return 0;
}

- (int)generality
{
    [self subclassResponsibility:_cmd];
    return 0;
}

- initValue:(const void*)value withObjCType:(const char*)type
{
    [self subclassResponsibility:_cmd];
    return self;
}

- (NSString*)description
{
    return [self stringValue];
}

@end

#endif /* NeXT_foundation_LIBRARY */

