/* 
   NSException.m

   Object encapsulation of a general exception handler.

   Copyright (C) 1993, 1994, 1996, 1997 Free Software Foundation, Inc.

   Author:	Adam Fedor <fedor@boulder.colorado.edu>
   Date:	Mar 1995

   This file is part of the mySTEP Library and is provided
   under the terms of the GNU Library General Public License.
*/

#import <Foundation/NSException.h>
#import <Foundation/NSString.h>
#import <Foundation/NSArray.h>
#import <Foundation/NSCoder.h>
#import <Foundation/NSThread.h>
#import <Foundation/NSDictionary.h>
#import "NSPrivate.h"


static /*volatile*/ void
_NSFoundationUncaughtExceptionHandler(NSException *exception)
{
    NSLog(@"Uncaught exception %@, reason: %@", [exception name], [exception reason]);
    abort();
}


@implementation NSException

+ (NSException *) exceptionWithName:(NSString *)name
							 reason:(NSString *)reason
							 userInfo:(NSDictionary *)userInfo 
{
    return [[[self alloc] initWithName:name 
						  reason:reason
						  userInfo:userInfo] autorelease];
}

+ (volatile void) raise:(NSString *)name format:(NSString *)format,...
{
	va_list args;
    va_start(args, format);
    [self raise:name format:format arguments:args];
    va_end(args);
	// FIXME: This probably doesn't matter,
	// but va_end won't get called
}

+ (volatile void) raise:(NSString *)name
				  format:(NSString *)format
				  arguments:(va_list)argList
{
	NSString *reason = [[NSString alloc] initWithFormat:format arguments:argList];
	NSException *except = [self exceptionWithName:name reason:reason userInfo:nil];
	[reason release];
    [except raise];
}

- (id) initWithName:(NSString *)name 
			 reason:(NSString *)reason
			 userInfo:(NSDictionary *)userInfo 
{
    if((self = [super init]))
		{
		e_name = [name retain];
		e_reason = [reason retain];
		e_info = [userInfo retain];
		}
    return self;
}

- (void) dealloc
{
	[e_name release];
	e_name = nil;
	[e_reason release];
	e_reason = nil;
	[e_info release];
	e_info = nil;
	[super dealloc];
}

- (NSString *) description;
{
	if(e_info)
		return [NSString stringWithFormat:@"%@ - %@: %@ - %@", NSStringFromClass([self class]), e_name, e_reason, e_info];
	return [NSString stringWithFormat:@"%@ - %@: %@", NSStringFromClass([self class]), e_name, e_reason];
}

- (/*volatile*/ void) raise
{
	NSThread *thread;
	NSHandler2 *handler;
#if 1
	NSLog(@"raise %@", self);
#endif
    if (_NSUncaughtExceptionHandler == NULL)
        _NSUncaughtExceptionHandler = _NSFoundationUncaughtExceptionHandler;
    thread = [NSThread currentThread];
    handler = thread->_exception_handler;
    if (handler == NULL)
    	_NSUncaughtExceptionHandler(self);
	else
		{
		thread->_exception_handler = handler->next;
		handler->exception = self;
		longjmp(handler->jumpState, 1);
		}
}

- (NSString *) name										{ return e_name; }
- (NSString *) reason									{ return e_reason; }
- (NSDictionary *) userInfo								{ return e_info; }
- (Class) classForPortCoder								{ return [self class];}

- (id) replacementObjectForPortCoder:(NSPortCoder*)coder { return self; }	// send exception bycopy

- (void) encodeWithCoder:(NSCoder *) aCoder
{
    [aCoder encodeObject:e_name]; 
    [aCoder encodeObject:e_reason]; 
    [aCoder encodeObject:e_info]; 
}

- (id) initWithCoder:(NSCoder *) aDecoder
{
    e_name = [[aDecoder decodeObject] retain];
    e_reason = [[aDecoder decodeObject] retain];
    e_info = [[aDecoder decodeObject] retain];
    return self;
}

- (id) copyWithZone:(NSZone *) zone	{ return [self retain]; }		// NSCopying

@end

void _NSAddHandler2(NSHandler2 *handler)
{
	NSThread *thread = [NSThread currentThread];
    handler->next = thread->_exception_handler;
    thread->_exception_handler = handler;
}

void _NSRemoveHandler2(NSHandler2 *handler)
{
	NSThread *thread = [NSThread currentThread];
    thread->_exception_handler = thread->_exception_handler->next;
}
