//
//  MPT_DataRecorder.m
//  AUCoderDemo
//
//  Created by Andrew Salamon on 11/8/06.
//  Copyright 2006 Machine Perception Laboratory, University of California San Diego. All rights reserved.
//

#import "MPT_DataRecorder.h"

#import "MPT_CERT.h"
#import "MPT_PluginController.h"
#import "MPT_FaceView.h"

@interface MPT_DataRecorder(PrivateMethods)
- (void)recordDataFieldNames;
- (void)recordTabbedDataPoint;
- (void)recordFullDataPoint;
- (NSString *)recordDataPoint_NRL;
- (void)setDataPathFilename:(NSString *)ignored;
- (void)warnUserAboutFile:(NSString *)path;
- (void)appendResults:(id)resNum withLabel:(NSString *)label toString:(NSMutableString *)pluginString showLabel:(BOOL)showLabel;
@end

@implementation MPT_DataRecorder
- (id)init
{
	if( self = [super init] )
	{
		NSMutableParagraphStyle *parStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
		[parStyle setTabStops:[NSArray array]];
		[parStyle setDefaultTabInterval:72.0];
		
		dataViewAttributes = [[NSDictionary dictionaryWithObject:parStyle forKey:NSParagraphStyleAttributeName] retain];
		[parStyle release];

		pluginController = [MPT_PluginController defaultController];
	}
	
	return self;
}

- (id)initWithCERT:(MPT_CERT *)_cert
{
	if( self = [self init] )
	{
		cert = [_cert retain];
	}
	
	return self;
}

- (void)awakeFromNib
{
	[self clearDataWindow:self];
}

- (void)dealloc
{
	[cert release];
	[dataViewAttributes release];
	[dataPath release];
	[dataFileHandle release];
	[super dealloc];
}

- (MPT_CERT *)cert
{
    return cert;
}

- (void)setCert:(MPT_CERT *)value
{
    if( cert != value )
    {
        [cert release];
        cert = [value retain];
    }
}

- (BOOL)recording
{
    return recording;
}
- (void)setRecording:(BOOL)value
{
    recording = value;
	if( recording )
	{
		[recordButton setTitle:@"Stop Recording"];
	}
	else
	{
		[recordButton setTitle:@"Start Recording"];
	}
}
- (void)toggleRecording:(id)sender
{
	if( [self recording] )
	{
		[self stopRecording];
	}
	else
	{
		[self startRecording];
	}
}

- (BOOL)recordTabbedData
{
    return recordTabbedData;
}

- (void)setRecordTabbedData:(BOOL)value
{
	if( recordTabbedData != value )
	{
		recordTabbedData = value;
		
		// If we're switching to tab delimited and we're already recording data, then record the field names
		if( value && [self recording] )
			[self recordDataFieldNames];
	}
}

- (BOOL)viewHasData
{
	NSString *data = [dataTextView string];
	if( !data || (0 == [data length]) ) return NO;
	return ![data isEqualToString:@" "];
}
- (void)setViewHasData:(BOOL)_hasData
{
	// Do nothing. This is here so that Bindings will update properly
}


- (NSString *)dataPath
{
    return dataPath;
}

- (void)setDataPath:(NSString *)value
{
    if( dataPath != value )
    {
        [dataPath release];
        dataPath = [value copy];

		[dataFileHandle release];
		dataFileHandle = nil;
		if( dataPath )
		{
			NSFileManager *fileManager = [NSFileManager defaultManager];
			BOOL fileExists = YES;
			BOOL isDir = NO;
			
			if( ![fileManager fileExistsAtPath:dataPath isDirectory:&isDir] )
				fileExists = [fileManager createFileAtPath:dataPath contents:nil attributes:nil];
			
			if( !isDir && fileExists )
				dataFileHandle = [[NSFileHandle fileHandleForWritingAtPath:dataPath] retain];
			
			if( !dataFileHandle )
			{
				// Probably ought to provide an error message
				[dataPath release];
				dataPath = nil;
			}
		}
		else
		{
			dataFileHandle = nil;
		}
		[self setDataPathFilename:[dataPath lastPathComponent]];
	}
}

- (NSString *)dataPathFilename
{
	return [dataPath lastPathComponent];
}
- (void)setDataPathFilename:(NSString *)ignored
{
	
}

- (void)startRecording
{
	[self setRecording:YES];
	[recordedData release];
	recordedData = [[NSMutableArray alloc] init];
	if( [self recordTabbedData] )
		[self recordDataFieldNames];
}
- (void)stopRecording
{
	[self setRecording:NO];
	
	if( dataFileHandle )
	{
		[dataFileHandle closeFile];
		[dataFileHandle release];
		dataFileHandle = nil;
		[self setDataPath:nil];
	}
	else
	{
		NSString *dataString = [recordedData componentsJoinedByString:@"\n"];
		
		NSString *data = [dataTextView string];
		[dataTextView replaceCharactersInRange:NSMakeRange([data length],0) withString:[NSString stringWithFormat:@"\n%@", dataString]];
		[self setViewHasData:YES];
	}
	//	[dataTextView setString:dataString];
	//	[dataWindow makeKeyAndOrderFront:self];
	//	[dataWindow orderWindow:NSWindowBelow relativeTo:0];
	//	[[self window] makeKeyAndOrderFront:self];
}

- (void)addData:(NSString *)dataItem
{
	if( dataFileHandle )
	{
		[dataFileHandle writeData:[[dataItem stringByAppendingString:@"\n"] dataUsingEncoding:NSUTF8StringEncoding]];
	}
	else
	{
		[recordedData addObject:dataItem];	
	}
}

- (void)recordDataFieldNames
{
	NSMutableString *pluginString = [NSMutableString string];
	NSEnumerator *pluginEnum = [[pluginController sortedPlugins] objectEnumerator];
	id<MPT_PluginProtocol> plugin;
	while( plugin = [pluginEnum nextObject] )
	{
		if( [plugin enabled] )
		{
			if( [[plugin labels] count] > 0 )
			{
				NSString *label;
				NSEnumerator *labelEnum = [[plugin labels] objectEnumerator];
				
				while( label = [labelEnum nextObject] )
				{
					[pluginString appendFormat:@"\t%@", label];
				}
			}
			else
			{
				[pluginString appendFormat:@"\t%@", [plugin localizedName]];
			}
		}
	}
	if( ([pluginString length] > 0) && ('\t' == [pluginString characterAtIndex:0]) )
		[pluginString deleteCharactersInRange:NSMakeRange(0,1)];
	
	[self addData:pluginString];
}

- (void)recordDataPoint
{
	if( ![self recording] )
		return;
	
	if( [self recordTabbedData] )
		[self recordTabbedDataPoint];
	else
		[self recordFullDataPoint];
}

- (void)recordTabbedDataPoint
{
	// Walk through all plugins and output results if they are enabled
	NSMutableString *pluginString = [NSMutableString string];
	NSDictionary *pluginResults = [cert pluginResults];
	NSEnumerator *pluginEnum = [[pluginController sortedPlugins] objectEnumerator];
	id<MPT_PluginProtocol> plugin;
	while( plugin = [pluginEnum nextObject] )
	{
		if( [plugin enabled] )
		{
			id resNum = [pluginResults objectForKey:[plugin pluginID]];
			
			if( [[plugin labels] count] > 0 )
			{
				NSString *label;
				NSEnumerator *labelEnum = [[plugin labels] objectEnumerator];
				while( label = [labelEnum nextObject] )
				{
					[self appendResults:resNum withLabel:label toString:pluginString showLabel:NO];
				}
			}
			else
			{
				// No labels, so we just use the plugin's localized name
				[self appendResults:resNum withLabel:[plugin localizedName] toString:pluginString showLabel:NO];
			}
		}
	}
	if( ([pluginString length] > 0) && ('\t' == [pluginString characterAtIndex:0]) )
		[pluginString deleteCharactersInRange:NSMakeRange(0,1)];
	
	NSString *file = @"";
	if( [imageView lastDropPath] )
		file = [NSString stringWithFormat:@"\tFile: %@", [imageView lastDropPath]];
	
	NSString *eyes = [NSString stringWithFormat:@"%@\t%@", NSStringFromPoint( [cert left] ), NSStringFromPoint( [cert right] )];

//	if( (0 == [recordedData count]) && [self recordTabbedData] )
//		[self recordDataFieldNames];
	
	NSString *res = [NSString stringWithFormat:@"%@\t%@\t%@", pluginString, eyes, file];
	//NSString *res = pluginString;
	[self addData:res];
}

- (void)recordFullDataPoint
{
	// Walk through all plugins and output results if they are enabled
	NSMutableString *pluginString = [NSMutableString string];
	NSDictionary *pluginResults = [cert pluginResults];
	NSEnumerator *pluginEnum = [[pluginController sortedPlugins] objectEnumerator];
	id<MPT_PluginProtocol> plugin;
	while( plugin = [pluginEnum nextObject] )
	{
		if( [plugin enabled] )
		{
			id resNum = [pluginResults objectForKey:[plugin pluginID]];
			
			if( [[plugin labels] count] > 0 )
			{
				NSString *label;
				NSEnumerator *labelEnum = [[plugin labels] objectEnumerator];
				
				while( label = [labelEnum nextObject] )
				{
					[self appendResults:resNum withLabel:label toString:pluginString showLabel:YES];
				}
			}
			else
			{
				// No labels, so we just use the plugin's localized name
				[self appendResults:resNum withLabel:[plugin localizedName] toString:pluginString showLabel:YES];
			}
		}
	}
	if( ([pluginString length] > 0) && ('\t' == [pluginString characterAtIndex:0]) )
		[pluginString deleteCharactersInRange:NSMakeRange(0,1)];
	
	// This could easily be made into a plugin
	//		NSString *tilt = @"";
	//	if( [[cert faces] count] > 0 )
	//	{
	//		float headTilt = [[cert largestFace] headTilt];
	//		tilt = [NSString stringWithFormat:@"\tTilt: %f", headTilt ];
	//		
	//	}
	
	NSString *file = @"";
	if( [imageView lastDropPath] )
		file = [NSString stringWithFormat:@"\tFile: %@", [imageView lastDropPath]];
	
	NSString *res = [NSString stringWithFormat:@"%@\tLeft: %@\tRight: %@%@",
		pluginString, NSStringFromPoint( [cert left] ), NSStringFromPoint( [cert right] ), file];
//	NSString *res = [NSString stringWithFormat:@"%@%@", pluginString, file];
	[self addData:res];
}

- (NSString *)recordDataPoint_NRL
{
	NSString *filePath = [imageView lastDropPath]; // D006_S014_face_9.jpg
	NSArray *nameParts = [[[filePath lastPathComponent] stringByDeletingPathExtension] componentsSeparatedByString:@"_"];
	NSString *frame = @"UNK";
	
	if( [nameParts count] >= 4 )
		frame = [nameParts objectAtIndex:3];
	
	NSMutableString *resString = [NSMutableString string];
	[resString appendFormat:@"%@, ", frame];
	
	NSEnumerator *resEnum = [[cert results] objectEnumerator];
	NSNumber *num;
	while( num = [resEnum nextObject] )
	{
		[resString appendFormat:@"%.6lf, ", [num doubleValue]];
	}
	
	[resString deleteCharactersInRange:NSMakeRange( [resString length]-2, 2 )];
	
	return resString;
}

- (IBAction)clearDataWindow:(id)sender
{
	[dataTextView setString:@" "];
	[[dataTextView textStorage] setAttributes:dataViewAttributes range:NSMakeRange(0,1)];
	[self setViewHasData:NO];
}

- (IBAction)saveDataWindow:(id)sender
{
	NSSavePanel *panel = [NSSavePanel savePanel];
	[panel setPrompt:@"Save Data"];
	[panel setTitle:@"Save Data"];
	
	[dataWindow makeKeyAndOrderFront:self];
	[panel beginSheetForDirectory:nil
							 file:@"AU Data.txt"
				   modalForWindow:dataWindow
					modalDelegate:self
				   didEndSelector:@selector(savePanelDidEnd:returnCode:contextInfo:)
					  contextInfo:nil];
}
- (void)savePanelDidEnd:(NSOpenPanel *)panel returnCode:(int)returnCode  contextInfo:(void  *)contextInfo
{
	if( returnCode == NSOKButton )
	{
		NSArray *filenames = [panel filenames];
		if( [filenames count] > 0 )
		{
			NSString *path = [filenames objectAtIndex:0];
			if( [path length] > 0 )
			{
				NSString *dataString = [dataTextView string];
				[dataString writeToFile:path atomically:NO];
				[self clearDataWindow:self];
			}
		}
	}
}

- (IBAction)chooseDataFile:(id)sender
{
	NSSavePanel *panel = [NSSavePanel savePanel];
	[panel setPrompt:@"Choose File"];
	[panel setTitle:@"Choose a file for recording AU data"];
	
	[dataWindow makeKeyAndOrderFront:self];
	[panel beginSheetForDirectory:nil
							 file:@"AU Data.txt"
				   modalForWindow:dataWindow
					modalDelegate:self
				   didEndSelector:@selector(chooseFilePanelDidEnd:returnCode:contextInfo:)
					  contextInfo:nil];
}
- (void)chooseFilePanelDidEnd:(NSOpenPanel *)panel returnCode:(int)returnCode  contextInfo:(void  *)contextInfo
{
	if( returnCode == NSOKButton )
	{
		NSArray *filenames = [panel filenames];
		if( [filenames count] > 0 )
		{
			NSString *path = [filenames objectAtIndex:0];
			if( [path length] > 0 )
			{
				[self setDataPath:path];
				if( !dataFileHandle )
					[self performSelector:@selector(warnUserAboutFile:) withObject:path afterDelay:0.01];
			}
		}
	}
	else
	{
		[self setDataPath:nil];
	}
}
- (void)warnUserAboutFile:(NSString *)path
{
	NSString *msg = @"Unable to open file for reading.";
	[[NSAlert alertWithMessageText:msg
					 defaultButton:@"OK"
				   alternateButton:nil
					   otherButton:nil
		 informativeTextWithFormat:@"You may not have the correct file or folder permissions to write to it: %@.", path] runModal];	
}

- (void)appendResults:(id)resNum withLabel:(NSString *)label toString:(NSMutableString *)pluginString showLabel:(BOOL)showLabel
{
	NSString *labelString = @"";
	if( showLabel )
		labelString = [NSString stringWithFormat:@"%@: ", label];
	
	if( !resNum )
	{
		[pluginString appendFormat:@"\t%@NA", labelString];
	}
	else if( [resNum isKindOfClass:[NSNumber class]] )
	{
		[pluginString appendFormat:@"\t%@%lf", labelString, [resNum doubleValue]];
	}
	else if( [resNum isKindOfClass:[NSDictionary class]] )
	{
		double res = [[(NSDictionary *)resNum objectForKey:label] doubleValue];
		[pluginString appendFormat:@"\t%@%lf", labelString, res];
	}
	else if( [resNum isKindOfClass:[NSString class]] )
	{
		[pluginString appendFormat:@"\t%@%@", labelString, resNum];
	}				
	else
	{
		[pluginString appendFormat:@"\t%@ERR", labelString];
	}
}
@end
