//
//  main.m
//  OpQueueTest
//
//
//

#import <Foundation/Foundation.h>


@interface OpQueueTest : NSObject {
    unsigned             _pass;
    unsigned             _numOperations;
    
    NSMutableArray      *_operationQueue;
    NSConditionLock     *_queueLock;
    NSConditionLock     *_workLock;
}
@end


@interface TheOperation : NSOperation
@end


@implementation TheOperation
- (void)main
{
}
@end


@implementation OpQueueTest

- (id)init
{
    if ((self = [super init]) != nil) {
        _operationQueue = [NSMutableArray new];
        _queueLock = [NSConditionLock new];
        _workLock = [NSConditionLock new];
        
        _numOperations = 3000;
    }
    return self;
}

- (void)runTest1
{
    NSDate *start = [NSDate date];
    unsigned i;
    NSOperationQueue *q = [NSOperationQueue new];

    NSLog(@"Frobnicating, pass %u...", _pass);

    for (i = 0; i < _numOperations; i++) {
        TheOperation *op = [TheOperation new];
        [q addOperation:op];
        [op release];
    }
    [q waitUntilAllOperationsAreFinished];
    NSLog(@"Frobnication took %.3f sec", -[start timeIntervalSinceNow]);
    _pass++;
}

- (void)thread:(id)ignored
{
    NSAutoreleasePool *pool = [NSAutoreleasePool new];
    
    //NSLog(@"%@ starting", [NSThread currentThread]);
    while (1) {
        NSAutoreleasePool *pool = [NSAutoreleasePool new];
        NSDate *when = [NSDate dateWithTimeIntervalSinceNow:1.0];
        TheOperation *p;
        if (![_queueLock lockWhenCondition:1 beforeDate:when]) {
            [pool release];
            break;
        }
        p = [[[_operationQueue objectAtIndex:0] retain] autorelease];
        [_operationQueue removeObjectAtIndex:0];
        if ([_operationQueue count] == 0)
            [_queueLock unlockWithCondition:0];
        else
            [_queueLock unlockWithCondition:1];
        [p main];
        [pool release];
    }
    //NSLog(@"%@ ending", [NSThread currentThread]);
    [_workLock lock];
    [_workLock unlockWithCondition:[_workLock condition]-1];
    [pool release];
}

- (void)addProperty:(TheOperation *)p
{
    const unsigned maxThreads = 8;
    [_workLock lock];
    [_queueLock lock];
    [_operationQueue addObject:p];
    [_queueLock unlockWithCondition:1];
    if ([_workLock condition] < maxThreads) {
        [_workLock unlockWithCondition:[_workLock condition]+1];
        [NSThread detachNewThreadSelector:@selector(thread:) toTarget:self withObject:nil];
    } else {
        [_workLock unlock];
    }
}

- (void)dealloc
{
    [_operationQueue release];
    [_queueLock release];
    [_workLock release];
    [super dealloc];
}
@end

void usage(const char *argv[])
{
    fprintf(stderr, "usage: %s { 1 | 2 }\n", argv[0]);
    exit(1);
}

int main(int argc, const char * argv[])
{
    NSAutoreleasePool *pool = [NSAutoreleasePool new];
    OpQueueTest *t= [OpQueueTest new];
    
    while (1) {
        NSAutoreleasePool *pool = [NSAutoreleasePool new];
        [t runTest1];
        [pool release];
    }

    [t release];

    [pool release];
    return 0;
}

