/* =============================================================================
	FILE:		UKThreadMessenger.m
	PROJECT:	Shovel
    
    COPYRIGHT:  (c) 2004 M. Uli Kusterer, all rights reserved.
    
	AUTHORS:	M. Uli Kusterer - UK
    
    LICENSES:   GPL, Modified BSD

	REVISIONS:
		2004-10-14	UK	Created.
   ========================================================================== */

// -----------------------------------------------------------------------------
//  Headers:
// -----------------------------------------------------------------------------

#import "UKThreadMessenger.h"


@implementation UKThreadMessenger

-(id)	initWithTarget: (id)trg newestFirst: (BOOL)nwf
{
	self = [super init];
	
	if( self )
	{
		messages = [[NSMutableArray alloc] init];
        target = trg;
        newestFirst = nwf;
        [NSThread detachNewThreadSelector: @selector(sendMessages:) toTarget: self withObject: nil];
	}
	
	return self;
}

-(void)	dealloc
{
	[messages release];
	[super dealloc];
    
    //NSLog(@"thread messenger released.");
}

// -----------------------------------------------------------------------------
//	release:
//		Since NSThread retains its target, we need this method to terminate the
//      thread when we reach a retain-count of two.
//
//	REVISIONS:
//		2004-11-12	UK	Created.
// -----------------------------------------------------------------------------

-(void) release
{
    if( [self retainCount] == 2 && threadRunning )
        threadRunning = NO;
    
    [super release];
}

-(void)	sendMessages: (id)sender
{
    threadRunning = YES;
    
    [NSThread setThreadPriority: 0.3];  // Lower this thread's priority.
    
	while( threadRunning )
    {
        while( threadRunning && (!messages || [messages count] <= 0) )
        {
            usleep(1000);
        }
        
        NSAutoreleasePool*  pool = [[NSAutoreleasePool alloc] init];
        NSArray*    msgs = nil;
        
		// FIXME: @synchronized
        //@synchronized( self )
        //{
            msgs = [messages autorelease];
            messages = [[NSMutableArray alloc] init];
        //}
        
        NSEnumerator*   enny;
        if( newestFirst )
            enny = [msgs reverseObjectEnumerator];
        else
            enny = [msgs objectEnumerator];
        NSInvocation*   inv;
        while( (inv = [enny nextObject]) )
        {
            NSAutoreleasePool*  pool2 = [[NSAutoreleasePool alloc] init];
            [inv invoke];
            [pool2 release];
            //usleep(1);
        }
        [pool release];
    }
    
    //NSLog(@"sendMessages terminated.");
}


-(id)	performSelector: (SEL)itemAction withObject: (id)obj
{
	BOOL	does = [super respondsToSelector: itemAction];
	if( does )
		return [super performSelector: itemAction withObject: obj];
	
	if( ![target respondsToSelector: itemAction] )
		[self doesNotRecognizeSelector: itemAction];
	
	NSInvocation*   inv = [NSInvocation invocationWithMethodSignature: [target methodSignatureForSelector: @selector(itemAction)]];
	
    [inv setSelector: itemAction];
    [inv setTarget: target];
    [inv retainArguments];
    
	// FIXME: @synchronized
    //@synchronized( self )
    //{
        [messages addObject: inv];
    //}
    
	return nil;
}

-(BOOL)	respondsToSelector: (SEL)itemAction
{
	BOOL	does = [super respondsToSelector: itemAction];
	
	return( does || [target respondsToSelector: itemAction] );
}


// -----------------------------------------------------------------------------
//	Forwarding unknown methods to the first responder:
// -----------------------------------------------------------------------------

-(NSMethodSignature*)	methodSignatureForSelector: (SEL)itemAction
{
	NSMethodSignature*	sig = [super methodSignatureForSelector: itemAction];

	if( sig )
		return sig;
	
	return [target methodSignatureForSelector: itemAction];
	
	return nil;
}

-(void)	forwardInvocation: (NSInvocation*)invocation
{
    SEL             itemAction = [invocation selector];
    NSInvocation*   inv;

    if( [target respondsToSelector: itemAction] )
	{
        inv = invocation;
		[inv setTarget: target];
        [inv retainArguments];
		// FIXME: @synchronized
        //@synchronized( self )
        //{
            [messages addObject: inv];
        //}
	}
    else
        [self doesNotRecognizeSelector: itemAction];
}



@end
