
#import "Controller.h"
#import <appkit/Application.h>
#import <appkit/OpenPanel.h>
#import <appkit/SavePanel.h>
#import <objc/List.h>
#import <appkit/Form.h>
#import <appkit/Matrix.h>
#import <appkit/Panel.h>
#import "FooObject.h"
#import "CellScrollView.h"
#import "FooCell.h"
#import <fcntl.h>
#import <strings.h>
#import <libc.h>

#import "VISCA.h"
#import "ViscaController.h"

@implementation Controller

- appDidInit:sender
{
/*
  [self addFooObject:self];
  [cellScrollView loadCellsFrom:fooObjects];
  cellMatrix = [cellScrollView cellMatrix];
 */
 	[viscaController appDidInit: sender];
  return self;
}

- initVars
{
	fprintf(stderr,"App did init\n");
  fooObjects = [[List alloc] init];
  didInit = NO;
  return self;
}

- free
{
  [fooObjects free];
  return [super free];
}

- addFooObject:sender
{
	struct ct_hmsf start, end;
	const char *buf1, *buf2;
	FooObject *fooObject;
	int count1, count2;
	int h, m, s, f;
	
	
	buf1 = [framePositionMatrix stringValueAt: 0];
	fprintf( stderr, "Pos1 string = <%s>\n", buf1);
	count1 = sscanf( buf1, "%x:%x:%x:%x", &h,
		&m, &s, &f);
	start.hh = h;
	start.mm = m;
	start.ss = s;
	start.ff = 0;
	buf2 = [framePositionMatrix stringValueAt: 1];
	fprintf( stderr, "Pos2 string = <%s>\n", buf2);
	count2 = sscanf( buf2, "%x:%x:%x:%x",&h,
		&m, &s, &f);
	end.hh = h;
	end.mm = m;
	end.ss = s;
	end.ff = 0;

	fprintf(stderr,"Start (%d) %02X:%02X:%02X:%02X "
		"->End (%d) %02X:%02X:%02X:%02X\n\n", 
  		count1, start.hh, start.mm, start.ss, start.ff,
		count2, end.hh, end.mm, end.ss, end.ff);
	
	if( count1 < 2 || count2 < 2)
		{
		NXRunAlertPanel("Improper Format", "The start or "
			"end frames have not been filled out.",
			"OK", NULL, NULL);
		return nil;
		}
	
  fooObject = [[FooObject alloc] init];
  [fooObject setStartFrame: &start];
  [fooObject setEndFrame: &end];
  [fooObject setComment: [commentText stringValue]];
 
  [fooObjects addObject:fooObject];
  [cellScrollView loadCellsFrom:fooObjects];
  /*
   * Assumptions in this next line:
   *	There are as many fooCells as there are fooObjects
   *	We've added the new fooObject at the end of the list.
   *	We want to display the fooObject we just added and highlight it.
   * In short, this is a hack.
   */
  [cellMatrix scrollCellToVisible:[fooObjects count]-1 :0];
  [cellMatrix selectCellAt:[fooObjects count]-1:0];
  
  if( didInit == NO )
  	{
	[cellScrollView loadCellsFrom:fooObjects];
	cellMatrix = [cellScrollView cellMatrix];
	didInit = YES;
	}

  return self;
}

- deleteFooObjects:sender
/*
 * Delete all selected fooObjects.
 */
{
  int i;

  for (i=[cellMatrix cellCount]-1; i>=0; i--) {
    FooCell *cell = [cellMatrix cellAt:i:0];
    if ([cell isHighlighted]) {
      /*
       * If a cell is highlighted, remove (and free) the corresponding item
       * from the list of fooObjects.
       */
      [[fooObjects removeObject:[cell fooObject]] free];
    }
  }
  [cellScrollView loadCellsFrom:fooObjects];
  return self;
}

- deleteAllFooObjects:sender
/*
 * Delete all fooObjects.
 */
{
  int i;

  for (i=[cellMatrix cellCount]-1; i>=0; i--) 
  	{
	FooCell *cell = [cellMatrix cellAt:i:0];
	[[fooObjects removeObject:[cell fooObject]] free];
	}
  [cellScrollView loadCellsFrom:fooObjects];
  return self;
}


- moveUpObject: sender
{
	int i;

	for (i=1; i <= [cellMatrix cellCount]-1; i++) 
		{
		FooCell *cell = [cellMatrix cellAt:i:0];
		if ([cell isHighlighted]) 
			{
			[fooObjects insertObject: [fooObjects 
				removeObject:[cell fooObject]] 			
      				at: i - 1];
			break;
		
			}
  		}
	[cellScrollView loadCellsFrom:fooObjects];

	return self;
}

- moveDownObject: sender
{
	int i;

	for (i=0; i <= [cellMatrix cellCount]-2; i++) 
		{
		FooCell *cell = [cellMatrix cellAt:i:0];
		if ([cell isHighlighted]) 
			{
			[fooObjects insertObject: 
				[fooObjects  removeObject:[cell fooObject]] 			
      				at: i + 1];
			break;
		
			}
  		}
	[cellScrollView loadCellsFrom:fooObjects];

	return self;
}


- setFrame: sender
{
	[framePositionMatrix setStringValue: 
			[frameCounter stringValueAt: 0]
		at: [sender tag]];
	return self;
}


- searchFrame: sender
{
	struct ct_hmsf search;
	const char *buf;
	int count, h, m, s, f;

	buf = [framePositionMatrix stringValueAt: [sender tag]];
	fprintf( stderr, "Search string = <%s>\n", buf);
	count = sscanf( buf, "%x:%x:%x:%x", &h, &m, &s, &f);
	search.hh = h;
	search.mm = m;
	search.ss = s;
	search.ff = f;

	if( count == 3 )  search.ff = 0;
	if( count < 3 ) 
		{
		NXRunAlertPanel("Invalid field", "Invalid search field",
			"OK", NULL, NULL);
		return nil;
		}
		
	fprintf(stderr,"Searching (step 1) %02x:%02x:%02x:%02x\n",
		search.hh, search.mm, search.ss, search.ff);
	
		
	if( ([viscaController search: &search]) == CMD_ERROR )
		{
		NXRunAlertPanel( "Command error", "Command could "
			"not execute for some reason.", "OK", NULL, NULL);
		return nil;
		}

	return self;
}

- playFrames: sender
{
	int i;
	FooObject *fooObject;
	struct ct_hmsf startFrame, endFrame;	
	
	fprintf(stderr, "Playing frames (%d).\n", [fooObjects count]);

	[viscaController stop: sender];
	
	for( i = 0; ; i++ )
		{
		fooObject = [fooObjects objectAt: i];
		if( fooObject == nil)
			break;

		startFrame = *[fooObject startFrame];
		endFrame = *[fooObject endFrame];	

		[viscaController search: &startFrame];
		[viscaController waitUntil: &startFrame];
		[viscaController play: sender];
		[viscaController waitUntil: &endFrame];
		[viscaController pause: sender];
		
	
		fprintf(stderr, "Object %d:\n"
				"\tStart frame %02x:%02x:%02x:%02x\n"
				"\tEnd frame   %02x:%02x:%02x:%02x\n\n",
				i,
				startFrame.hh, startFrame.mm, 
				startFrame.ss, startFrame.ff,
				endFrame.hh, endFrame.mm, 
				endFrame.ss, endFrame.ff);				
				
		}

	return self;
}

- openFile: sender
{
	OpenPanel *openPanel;
	const char *fileTypes[] = {"vbox", NULL};
	const char *dir;
	const char * const *filenames;
	int counter;
	
	openPanel = [OpenPanel new];
	
	[openPanel allowMultipleFiles: NO];
	if( ![openPanel runModalForTypes: fileTypes] )
		return nil;
	
	dir = [openPanel directory];
	filenames =  [openPanel filenames];
	#ifdef DEBUG
		fprintf(stderr, "Opening in directory <%s>:\n", dir);
	#endif
	
	for( counter = 0; filenames[counter] != NULL; counter ++)
		{
		char temp[1024];
		const char *type;
		
		#ifdef DEBUG
			fprintf(stderr, "\t\t<%s>\n", filenames[counter]);
		#endif
		
		type = strrchr(filenames[counter], '.') + 1;
		sprintf(temp, "%s/%s", dir, filenames[counter] );
		[self app: self openFile: temp type: type];
		}
	return self;
}
- (BOOL) appAcceptsAnotherFile: sender
{
	return YES;
}

- (int) app: sender openFile: (const char *) fname type: (const char *) ftype
{
	struct ct_hmsf start, end;
	FooObject *fooObject;


		fprintf(stderr, "Opening file %s, type %s.\n",
			fname, ftype);
		
	
	if( strncmp( ftype, "vbox", 4 ) == 0 )
		{
		FILE *fp;
		char input[256];
		int count;
		int h1, m1, s1, f1, h2, m2, s2, f2;
		char comment[256];
		
		[self deleteAllFooObjects: self];
		
		fp = fopen( fname, "r" );
		
		while( fgets( input, 255, fp) != NULL )
			{
			count = sscanf( input, "%x:%x:%x:%x %x:%x:%x:%x "
				"%[^\n]s", 
				&h1, &m1, &s1, &f1,
				&h2, &m2, &s2, &f2, comment);
	
			fprintf(stderr,"Read %s: %02x:%02x:%02x:%02x "
				"%02x:%02x:%02x:%02x %s\n\n",
				fname,
				h1, m1, s1, f1, h2, m2, s2, f2, comment);
				
			start.hh = h1;
			start.mm = m1;
			start.ss = s1;
			start.ff = f1;
			end.hh = h2;
			end.mm = m2;
			end.ss = s2;
			end.ff = f2;

			fprintf(stderr,"Start %02X:%02X:%02X:%02X "
				"->End %02X:%02X:%02X:%02X\n\n", 
  				start.hh, start.mm, start.ss, start.ff,
				end.hh, end.mm, end.ss, end.ff);
	
		
			fooObject = [[FooObject alloc] init];
			[fooObject setStartFrame: &start];
			[fooObject setEndFrame: &end];
			[fooObject setComment: comment];
 
 			[fooObjects addObject:fooObject];
			[cellScrollView loadCellsFrom:fooObjects];
			[cellMatrix scrollCellToVisible:
				[fooObjects count]-1 :0];
			[cellMatrix selectCellAt:[fooObjects count]-1:0];
  
			if( didInit == NO )
  				{
				[cellScrollView loadCellsFrom:fooObjects];
				cellMatrix = [cellScrollView cellMatrix];
				didInit = YES;
				}
			}
		return YES;
		}
		
	return NO;
}

- saveFile: sender
{
	int i;
	SavePanel *savePanel;
	char d[1024], f[1024], *comment;
	FILE *fp;
	FooObject *fooObject;
	struct ct_hmsf startFrame, endFrame;	
	
		
	if( savePanel != nil )
		savePanel = [SavePanel new];

	if (![savePanel runModalForDirectory: "~" 
		file: "Untitled" ] )
    			return nil;

	strcpy( d, [savePanel directory] );
	strcpy( f, [savePanel filename] );
	
	
	fprintf(stderr, "Saving at dir %s, file %s.\n\n", d, f);
	
	if( (access(d, F_OK) == 0) &&  (access( d, W_OK) == -1 ))
		{
		NXRunAlertPanel(
			 "Directory not writable",
			"You do not have the proper write "
			"permission for this directory.",   
			"OK",   NULL, NULL );
		return NO;
		}

	if( (fp = fopen( f, "w")) == NULL ) 
		{
		NXRunAlertPanel(
			 "File not writable",
			"You do not have the proper write "
			"permission for this file.",   "OK",   NULL, NULL );
		return NO;
		}
		
	for( i = 0; ; i++ )
		{
		fooObject = [fooObjects objectAt: i];
		if( fooObject == nil)
			break;

		startFrame = *[fooObject startFrame];
		endFrame = *[fooObject endFrame];	
		comment = [fooObject comment];
		
		fprintf(fp, "%x:%x:%x:%x %x:%x:%x:%x %s\n",
				startFrame.hh, startFrame.mm, 
				startFrame.ss, startFrame.ff,
				endFrame.hh, endFrame.mm, 
				endFrame.ss, endFrame.ff,
				comment);
		}

	fclose(fp);
	
	[cellScrollView loadCellsFrom:fooObjects];
	return self;
}
@end
