// Copyright 1998-1999 Omni Development, Inc.  All rights reserved.
//
// This software may only be used and reproduced according to the
// terms in the file OmniSourceLicense.html, which should be
// distributed with this project and can also be found at
// http://www.omnigroup.com/DeveloperResources/OmniSourceLicense.html.

#import "OFRunLoopQueueProcessor.h"

#import <Foundation/Foundation.h>
#import <OmniBase/OmniBase.h>
#import "OFMessageQueue.h"

RCS_ID("$Header: /Network/Developer/Source/CVS/OmniGroup/OmniFoundation/Scheduling.subproj/OFRunLoopQueueProcessor.m,v 1.3 1999/03/30 21:25:49 kc Exp $")

@implementation OFRunLoopQueueProcessor

- initForQueue:(OFMessageQueue *)aQueue
{
    if (![super initForQueue:aQueue])
        return nil;

    [messageQueue setDelegate:self];

    notificationPort = [[NSPort port] retain];
    [notificationPort setDelegate:self];

    portMessage = [[NSPortMessage alloc] initWithSendPort:notificationPort receivePort:notificationPort components:nil];

    return self;
}

- (void)dealloc
{
    [notificationPort setDelegate:nil];
    [notificationPort release];
    [portMessage release];
    [super dealloc];
}

- (void)runFromCurrentRunLoopInModes:(NSArray *)modes
{
    unsigned int modeIndex, modeCount;
    NSRunLoop *runLoop = [NSRunLoop currentRunLoop];

    modeCount = [modes count];
    for (modeIndex = 0; modeIndex < modeCount; modeIndex++)
        [runLoop addPort:notificationPort forMode:[modes objectAtIndex:modeIndex]];

    [self processQueueUntilEmpty];
}

// OFMessageQueueDelegate protocol --- called in whatever thread enqueues the message

- (void)queueHasInvocations:(OFMessageQueue *)aQueue;
{
   if (disableCount > 0)
       return;

   if (![portMessage sendBeforeDate:[NSDate distantPast]]) {
       // If this fails, then the port is probably full, meaning that we've already notified
   }
}

// NSPort delegate method --- called by our registered runloop in its thread

- (void)handlePortMessage:(NSPortMessage *)message;
{
    if (disableCount > 0)
        return;
    [self processQueueUntilEmpty];
}

// Disallow recursive queue processing.

- (void)processQueueUntilEmpty;
{
    [self disable];
    NS_DURING {
        [super processQueueUntilEmpty];
    } NS_HANDLER {
        [self enable];
        [localException raise];
    } NS_ENDHANDLER;
    [self enable];
}


- (void)enable
{
    if (disableCount > 0)
        disableCount --;
    if (disableCount == 0 && [messageQueue hasInvocations])
        [self queueHasInvocations:messageQueue];
}

- (void)disable
{
    disableCount ++;
}


@end
