/* 
   NSException.m

   Copyright (C) 1995, 1996, 1997 Ovidiu Predescu and Mircea Oancea.
   All rights reserved.

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

   This file is part of the Foundation Extensions Library.

   Permission to use, copy, modify, and distribute this software and its
   documentation for any purpose and without fee is hereby granted, provided
   that the above copyright notice appear in all copies and that both that
   copyright notice and this permission notice appear in supporting
   documentation.

   We disclaim all warranties with regard to this software, including all
   implied warranties of merchantability and fitness, in no event shall
   we be liable for any special, indirect or consequential damages or any
   damages whatsoever resulting from loss of use, data or profits, whether in
   an action of contract, negligence or other tortious action, arising out of
   or in connection with the use or performance of this software.
*/

#include <extensions/config.h>

#include <stdarg.h>

#if HAVE_STDLIB_H
#include <stdlib.h>
#endif

#import <Foundation/NSString.h>

#include <extensions/NSException.h>
#include <extensions/exceptions/GeneralExceptions.h>
#include <extensions/exceptions/NSCoderExceptions.h>

#import <Foundation/NSArray.h>
#include <extensions/MissingMethods.h>

@implementation NSException (Extensions)

#if GNUSTEP_BASE_LIBRARY
# define name_ivar _e_name
# define reason_ivar _e_reason
# define userInfo_ivar _e_info
#else
# define name_ivar name
# define reason_ivar reason
# define userInfo_ivar userInfo
#endif

void __NSException_dummy_function_for_stupid_linkers()
{
    extern void __MissingMethods_dummy_function_for_stupid_linkers();
    __MissingMethods_dummy_function_for_stupid_linkers();
}

- (BOOL)exceptionIsKindOfClass:(Class)class
{
    return [self isKindOfClass:class];
}

- (BOOL)exceptionIsIn:(NSArray*)exceptions
{
    int i, n = [exceptions count];

    for(i = 0; i < n; i++)
	if([self exceptionIsKindOfClass:[[exceptions objectAtIndex:i] class]])
	    return YES;
    return NO;
}

- (NSString*)errorString
{
    NSString* message;

    if(reason_ivar)
	message = [NSString stringWithFormat:@"%s: caught %s exception "
				@"object.\nReason: %s\n",
				"Error", [[isa description] cString],
				[reason_ivar cString]];
    else message = [NSString stringWithFormat:@"%s: caught %s exception object.\n",
				"Error", [[isa description] cString]];


    return message;
}

- initWithFormat:(NSString*)format, ...
{
    va_list ap;

    va_start(ap, format);
    reason_ivar = [[NSString alloc] initWithFormat:format arguments:ap];
    va_end(ap);
    return self;
}

- setName:(NSString*)_name
{
    [_name retain];
    [name_ivar release];
    name_ivar = _name;
    return self;
}

- setReason:(NSString*)_reason
{
    [_reason retain];
    [reason_ivar release];
    reason_ivar = _reason;
    return self;
}

- setUserInfo:(NSDictionary*)_userInfo
{
    [_userInfo retain];
    [userInfo_ivar release];
    userInfo_ivar = _userInfo;
    return self;
}

@end /* NSException (Extensions) */



@implementation NSException (ExceptionClassesMapping)
#ifndef GNUSTEP_BASE_LIBRARY
- initWithName:(NSString*)_name
    reason:(NSString*)_reason
    userInfo:(NSDictionary*)_userInfo
{
    NSDictionary* exceptionMapping = nil;
    Class exceptionClass;

    if(!exceptionMapping) {
	exceptionMapping = [NSDictionary dictionaryWithObjectsAndKeys:
	    [FoundationException class], NSGenericException,
	    [RangeException class], NSRangeException,
	    [InvalidArgumentException class], NSInvalidArgumentException,
	    [InternalInconsistencyException class], NSInternalInconsistencyException,
#if NeXT_Foundation_LIBRARY
	    [NSException class], NSObjectInaccessibleException,
	    [NSException class], NSObjectNotAvailableException,
	    [NSException class], NSDestinationInvalidException,
	    [NSException class], NSInvalidSendPortException,
	    [NSException class], NSInvalidReceivePortException,
	    [NSException class], NSPortSendException,
	    [NSException class], NSPortReceiveException,
#endif
	    nil];
    }

    [_name retain];
    [_reason retain];
    [_userInfo retain];

    exceptionClass = [exceptionMapping objectForKey:_name];
    if(exceptionClass && ![isa isKindOfClass:exceptionClass]) {
	[self autorelease];
	self = [exceptionClass alloc];
    }

    [self->name_ivar release];
    [self->reason_ivar release];
    [self->userInfo_ivar release];
    self->name_ivar = _name;
    self->reason_ivar = _reason;
    self->userInfo_ivar = _userInfo;

    return self;
}
#endif
@end /* NSException (ExceptionClassesMapping) */
