//
//  BatchExample.m
//
//  Created by Daniel Vollmer on 05.01.07.
//  Copyright [maven] heavy industries 2007 . All rights reserved.
//

#import <Foundation/Foundation.h>
#import "BatchExample.h"
#import "SIWorkUnit.h"
#import "SIWorkManager.h"

@implementation BatchExample

- (id)init
{
	self = [super init];
	if (self)
	{
//		NSLog(@"init: %@", self);
		// There should only be one SIWorkManager in your application.
		// You could for example create it in your NSDocumentController...
		_workManager = [[SIWorkManager alloc] init]; // create as many worker threads as cores
		// this lock is used for batch processing
		_processingLock = [[NSConditionLock alloc] initWithCondition:0];
	}
	return self;
}

- (void)dealloc
{
//	NSLog(@"dealloc: %@", self);	
	[_processingLock release];
	[_workManager release];
	[super dealloc];
}


// this will be called from another thread
- (id)doSomethingSimple:(id)argument
{
	NSNumber *expensiveToCreateObject;

	// NSLog is thread-safe
	NSLog(@"Got %@ as argument in thread %@.", argument, [NSThread currentThread]);

	// do work here
	expensiveToCreateObject = [[NSNumber alloc] initWithDouble:1.0];

	return expensiveToCreateObject; // return work done
}

// this is called in the main-thread again
- (id)finishedSomethingSimple:(id)result
{
	NSLog(@"Received result %@.", result);
	[result release]; // usually, we add it to our UI
}

- (void)demonstrateSimple
{
	int i;

	for (i = 0; i < 10; i++)
	{
		SIWorkUnit *wu = [[SIWorkUnit alloc] initWithTarget:self withSelector:@selector(doSomethingSimple:) withArgument:self withDidEndSelector:@selector(finishedSomethingSimple:)];

		if (wu)
		{
			[_workManager addWorkUnit:wu isHighPriority:NO];
			[wu release];
		}
	}
	NSLog(@"Queued all jobs.");
}


// this will be called from another thread
- (id)doSomethingBatch:(id)argument
{
	// NSLog is thread-safe
	NSLog(@"Got %@ as argument in thread %@.", argument, [NSThread currentThread]);

	// do work here
//	[argument performThreadsafeExpensiveJob];

	// notify main-thread that one more batch entry is done
	[_processingLock lock];	
	[_processingLock unlockWithCondition:[_processingLock condition] + 1];
	return nil; // return work done
}

- (void)demonstrateBatch
{
	const int numBatch = 10;
	int i;

	for (i = 0; i < numBatch; i++)
	{
		// didEndSelector would only be called after we unblock the main-thread and its NSRunLoop is called again
		SIWorkUnit *wu = [[SIWorkUnit alloc] initWithTarget:self withSelector:@selector(doSomethingBatch:) withArgument:self withDidEndSelector:NULL];

		if (wu)
		{
			[_workManager addWorkUnit:wu isHighPriority:NO];
			[wu release];
		}
	}
	NSLog(@"Queued all jobs.");
	[_processingLock lockWhenCondition:numBatch];
	[_processingLock unlockWithCondition:0]; // and reset to 0 for the next time
	NSLog(@"All jobs done.");
}

@end


// run it
int main (int argc, char** argv, char** env)
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    NSArray *args = [[NSProcessInfo processInfo] arguments];

	BatchExample *b = [[BatchExample alloc] init];
	[b demonstrateSimple];
	[b demonstrateBatch];
	[b release];

    [pool release];
	return 0;
}
