/*
	batchZillionJob.m
	Mon Dec  9 18:55:08 CET 2002
 */

#import	"NSFileManager+directories.h"
#import "batchZillionJob.h"
#import	<base/GSCategories.h>


/*
	Example specification file:

{
	jobName = "Superb command line job";
	resultIsConcatenatedOutputFiles = YES;
	commandDescriptions = (
		"R < job1.R > ZILLION_JOB_OUTPUT_FILE",
		"R < job2.R > ZILLION_JOB_OUTPUT_FILE"
	);
}

 */

#define SIMPLE_JOBS_COUNT	10

@interface BatchJobEnumerator : NSEnumerator
{
	int	number;
	int	count;
}
- initWithSeed:seed countOfJobs:(int)jobCount;
@end
@implementation BatchJobEnumerator
- initWithSeed:seed countOfJobs:(int)jobCount {
	if (!(self = [super init])) return self;
	number = seed? [(NSNumber *)seed intValue]: 0;
	count = jobCount;
	return self;
}
- nextObject {
	NSLog(@"Enum number %d", number);
	return number < count? [NSNumber numberWithInt:number++]: nil;
}
@end

@implementation BatchZillionJob

- (NSString *)jobId { return jobId; }
- (void)setJobId:(NSString *)someId {
	[someId retain];
	[jobId release];
	jobId = someId;
}

- (BOOL)storesOutcomesInMemory { return NO; }

- initWithBundle:(NSBundle *)someBundle
	resources:(NSData *)resources
	jobHandler:(id <ZillionJobHandler>)jobHandler
{
	if (!(self = [super init])) return self;
	handler = [jobHandler retain];
	tempDir = [[handler temporaryDirectory] retain];

	[[NSFileManager defaultManager] writeDataRepresentation:resources toPath:tempDir];

	// unpack the file-bundle
	batchSpecification = [[NSDictionary alloc] initWithContentsOfFile:
		[tempDir stringByAppendingPathComponent:@"specification.plist"]];
	[self setJobId:[batchSpecification objectForKey:BATCH_JOB_NAME_KEY]];

	commandDescriptions = [[batchSpecification objectForKey:BATCH_JOB_DESC_NAME] retain];

	//	<!> test for subclass relation
	if (! [commandDescriptions isKindOfClass:[NSArray class]])
		[NSException raise:NSInvalidArgumentException
			format:@"Command descriptions of incorrect format"];

	return self;
}

- (void)dealloc
{
	[handler release];
	[tempDir release];
	[jobId release];

	[commandDescriptions release];
	[batchSpecification release];
	[super dealloc];
}

- (NSEnumerator *)seedEnumeratorWithSeed:(NSData *)dataSeed {
	id	seed = !dataSeed? nil: [NSUnarchiver unarchiveObjectWithData:dataSeed];
	return [[[BatchJobEnumerator alloc] initWithSeed:seed
		countOfJobs:[commandDescriptions count]] autorelease];
}
- (void)startJobUnitWithSeed:seed
{
	int			jobNumber = [seed intValue];
	NSString	*command = [commandDescriptions objectAtIndex:jobNumber];
	NSString	*outputFile = [NSString stringWithFormat:@"%@_%d",
		ZILLION_JOB_FILE_PLACEHOLDER, jobNumber];
	NSString	*processedCommand = [command stringByReplacingString:ZILLION_JOB_FILE_PLACEHOLDER
		withString:outputFile];

	NSLog(@"executing command:%@", processedCommand);

	[handler submitOutcome:[NSArchiver
		archivedDataWithRootObject:[NSData dataWithContentsOfFile:outputFile]]
		ofJob:[self jobId] forSeed:seed storeHints:nil];
	[handler jobUnitDidEndForJobId:[self jobId] seed:seed];
}

- (NSData *)dataRepresentationOfSeed:seed {
	return seed? [NSArchiver archivedDataWithRootObject:seed]: nil;
}
- seedObjectFromDataRepresentation:(NSData *)seed {
	return seed? [NSUnarchiver unarchiveObjectWithData:seed]: nil;
}

- (void)sealJobOutcomes
{
	NSString		*outputDir = [handler outcomeDirectoryForJobId:[self jobId]];
	NSDictionary	*outcomes = [handler outcomeDictionaryForJobId:[self jobId]];

	if ([[batchSpecification objectForKey:ZILLION_BATCH_JOB_RESULT_CONCAT] isEqualToString:@"YES"])
	{
		NSString		*outputFile = [outputDir stringByAppendingPathComponent:
			ZILLION_BATCH_JOB_OUTPUT_FILE_NAME]; 
		NSFileHandle	*fh = [NSFileHandle fileHandleForWritingAtPath:outputFile];
		NSEnumerator	*seedEnum = [self seedEnumeratorWithSeed:nil];
		id				seed;

		while ( (seed = [seedEnum nextObject]) ) {
			NSString	*outcomePath = [outcomes objectForKey:[self dataRepresentationOfSeed:seed]];
			[fh writeData:[NSData dataWithContentsOfFile:outcomePath]];
		}
		[fh closeFile];
	} else {
		NSFileManager	*fm = [NSFileManager defaultManager];
		NSEnumerator	*seedEnum = [self seedEnumeratorWithSeed:nil];
		id				seed;

		while ( (seed = [seedEnum nextObject]) ) {
			[fm copyPath:[outcomes objectForKey:[self dataRepresentationOfSeed:seed]]
				toPath:[outputDir stringByAppendingPathComponent:
						[NSString stringWithFormat:@"%@_%d.txt",
							ZILLION_BATCH_JOB_OUTPUT_FILE_NAME, [seed intValue]]
					]
				handler:nil
			];
		}
	}
	NSLog(@"Did seal %@", [self jobId]);
}

@end
