//
//  MPT_DO_Server.m
//  AUCoderDemo
//
//  Created by Andrew Salamon on 6/20/08.
//  Copyright 2008 Machine Perception Laboratory, University of California San Diego.. All rights reserved.
//

#import "MPT_DO_Server.h"
#import "MPT_CERT.h"
#import "MPT_Scheduler.h"
#import <DemoPlugin/MPT_PluginProtocol.h>

@implementation MPT_DO_Server
- (id)initWithScheduler:(MPT_Scheduler *)_scheduler andPC:(id)_pluginController
{
	if( self = [super init] )
	{
		[self setScheduler:_scheduler];
		pluginController = _pluginController;
		lock = [[NSLock alloc] init];
		//cert = [[MPT_CERT alloc] init];
		serverID = @"";
	}
	return self;
}

- (id)init
{
	return [self initWithScheduler:nil andPC:nil];
}

- (void)dealloc
{
	[cert release];
	[clientProxy release];
	[scheduler release];
	[connection release];
	[[NSNotificationCenter defaultCenter] removeObserver:self];
	[super dealloc];
}

- (NSString *)serverID
{
	return serverID;
}

- (BOOL)startWithPort:(unsigned short)_port
{
	NSSocketPort  *port = [[NSSocketPort alloc] initWithTCPPort:_port];
	connection = [[NSConnection alloc] initWithReceivePort:port sendPort:nil];
	[connection setRootObject:self];
	[[NSNotificationCenter defaultCenter] addObserver:self
											 selector:@selector(connectionDidDie:)
												 name:NSConnectionDidDieNotification
											   object:connection];
	return (connection != nil);
//	NSConnection *defaultConnection = [NSConnection defaultConnection];
//	[defaultConnection setRootObject:self];
//	return [defaultConnection registerName:@"CERT"];
}

- (void)end
{
	if( clientProxy )
	{
		NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:@"Server shut down by user.", NSLocalizedDescriptionKey, serverID, @"CERT DO Server ID", nil];
		[clientProxy serverStatus:[NSError errorWithDomain:MPT_DO_ErrorDomain code:MPT_DO_ServerShutDown userInfo:userInfo]];
		[self disconnectClient:clientProxy];
		[connection registerName:nil];
		[connection invalidate];
	}
}


- (MPT_Scheduler *)scheduler
{
    return scheduler;
}
- (void)setScheduler:(MPT_Scheduler *)value
{
    if( scheduler != value )
    {
        [scheduler release];
        scheduler = [value retain];
		[scheduler setDelegate:self];
    }
}

- (id)pluginController
{
    return pluginController;
}
- (void)setPluginController:(id)value
{
    if( pluginController != value )
    {
		// We might need to re-update the config settings
        pluginController = value;
    }
}

- (void)connectionDidDie:(NSNotification *)aNotification
{
	if( connection == [aNotification object] )
		[self disconnectClient:clientProxy];
}

// Server methods
- (BOOL)available
{
	return nil == clientProxy;
}

- (void)setConfig:(NSDictionary *)config forClient:(id<CERTClient>)client
{
	clientProxy = [client retain];
	NSString *myID = [config objectForKey:@"CERT DO Server ID"];
	if( myID )
		serverID = [myID copy];
#ifdef DEBUG
	NSLog( @"DO Server starting with ID: %@", myID );
#endif
	
	// enable/disable plugins based on config
	NSArray *errors = [pluginController setConfig:config];
	if( [errors count] > 0 )
	{
		NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:@"Server configuration errors, probably one or more missing plugins.", NSLocalizedDescriptionKey, errors, @"CERT DO Config Errors", nil];
		[clientProxy serverStatus:[NSError errorWithDomain:MPT_DO_ErrorDomain code:MPT_DO_ServerConfigError userInfo:userInfo]];
	}
}

- (BOOL)canAcceptTask
{
	if( scheduler )
		return [scheduler isAvailable];
	else if( cert )
		return YES;
	return NO;
}

- (void)processTask:(NSDictionary *)task
{
	if( scheduler )
	{
		[scheduler scheduleInput:task];
	}
	else if( cert )
	{
		[lock lock];
//		NSLog( @"Server processing frame: %d", [[task objectForKey:@"CERT.frame"] intValue] );
		[cert process:task];
		NSMutableDictionary *res = [[cert pluginResults] mutableCopy];
		[res removeObjectForKey:@"CERT.image"];
		[res removeObjectForKey:@"CERT.rimage"];
		//	[res removeObjectForKey:@"CERT.faces"];
		
//		NSLog( @"Server returning results for frame: %d", [[res objectForKey:@"CERT.frame"] intValue] );
		
		NSData *data = [NSKeyedArchiver archivedDataWithRootObject:res];
		
		[clientProxy taskFinishedData:data];
		//	[clientProxy taskFinished:res];
		[res release];
		[lock unlock];
	}
	else
	{
		NSLog( @"No CERT processor available." );
	}
}

- (BOOL)processTaskData:(bycopy in NSData *)data
{
	NSDictionary *task = [NSKeyedUnarchiver unarchiveObjectWithData:data];
	[self processTask:task];
	return YES;
}

- (void)processImage:(NSImage *)image asFrame:(int)frame
{
	NSDictionary *task = [NSDictionary dictionaryWithObjectsAndKeys:[[image copy] autorelease], @"CERT.image", [NSNumber numberWithInt:frame], @"CERT.frame", nil];
	[self processTask:task];
}
- (void)disconnectClient:(id<CERTClient>)client
{
	if( client == clientProxy )
	{
		[clientProxy release];
		clientProxy = nil;
	}
}
// End server methods

- (void)handleUnsortedResults:(NSDictionary *)pluginResults
{
	NSMutableDictionary *res = [pluginResults mutableCopy];
	[res removeObjectForKey:@"CERT.image"];
	[res removeObjectForKey:@"CERT.rimage"];
	
//	NSLog( @"Server returning results for frame: %d", [[res objectForKey:@"CERT.frame"] intValue] );
	
	NSData *data = [NSKeyedArchiver archivedDataWithRootObject:res];
	
	[clientProxy taskFinishedData:data];
	//	[clientProxy taskFinished:res];
	[res release];
}

- (void)incrementWeightsProgressBy:(NSNumber *)incNum
{
	
}

- (void)scheduleIsEmpty
{
	
}
@end
