/*
	Copyright (C) 1994 Sean Luke

	COWSUserController.m
	Version 1.4
	Sean Luke
	
	Allows easy hookup to libraries and control nib and interpreter
	
*/

#import "COWSUserController.h"
#import "COWSInterpreter.h"
#import "COWSStringNode.h"
#import "COWSControlPanel.h"
#import <string.h>
#import <stdlib.h>

@implementation COWSUserController

- init
	{
	id returnval=[super init];
	autostart=COWSCONTROLLER_NOAUTOLOAD;
	return returnval;
	}

- awakeFromNib
	{
	[controlPanel connect:self];
	if (interpreter&&[interpreter conformsTo:@protocol(InterpreterControl)])
		{
		[interpreter printErrors:NO];
		[interpreter setTimedEntrySpeed:timed_entry_speed];
		[interpreter setRepeats:pulses_per_timed_entry];
		[interpreter setLocked:locked];
		[interpreter setForeground:foreground];
		[[controlPanel lockedButton] setIntValue:locked];
		[[controlPanel foregroundButton] setIntValue:foreground];
		}
	else
		{
		printf 
		    ("COWS User Controller ERROR:  no interpreter to load and run!\n");
		return NULL;
		}
	return self;
	}
	
- load:sender	
	{
	char* prog;
	
	if (program&&[program isKindOf:[Text class]])
		{
		int length=[program textLength];
		prog=malloc(length + 1);
		[program getSubstring:prog start:0 length:length];
		prog[length]='\0';					// some bug in Text object
		}
	else
		{
		printf ("COWS User Controller Warning:  no program\n");
		prog=malloc(1);
		prog[0]='\0';
		}
	
	if (interpreter&&[interpreter conformsTo:@protocol(InterpreterControl)])
		{
		[interpreter clearLibraryFunctions];
		if (library1)	[interpreter addLibrary:library1];
		if (library2)	[interpreter addLibrary:library2];
		if (library3)	[interpreter addLibrary:library3];
		if (library4)	[interpreter addLibrary:library4];
		if (library5)	[interpreter addLibrary:library5];
		if (library6)	[interpreter addLibrary:library6];
		if (library7)	[interpreter addLibrary:library7];
		if (library8)	[interpreter addLibrary:library8];
		//if (delegate&&[delegate respondsTo:@selector(loadLibraries)])
		//	[delegate loadlibraries];
		if ([interpreter setProgram:prog]<0)
			{
			NXRunAlertPanel
				("Load","Syntax Error in Program Load","Oops",NULL, NULL);
			free(prog);
			return NULL;
			}
		}
	else 
		{
		printf ("COWS User Controller ERROR:  no interpreter to load!\n");
		free(prog);
		return NULL;
		}
	free(prog);
	return self;
	}
	
	
- run:sender		
	{
	id args, new_args;

	if (interpreter&&[interpreter conformsTo:@protocol(InterpreterControl)])
		{
		if ([interpreter working])
			{
			printf 
			  ("COWS User Controller ERROR:  interpreter already working!\n");
			return NULL;
			}
		args=[[COWSArgumentList alloc] init];
		if (strlen([[controlPanel arg1] stringValue]))
			{
			id temp=[[COWSStringNode alloc] init];
			[temp setString:[[controlPanel arg1] stringValue]];
			[args push:temp];
			if (strlen([[controlPanel arg2] stringValue]))
				{
				id temp=[[COWSStringNode alloc] init];
				[temp setString:[[controlPanel arg2] stringValue]];
				[args push:temp];
				if (strlen([[controlPanel arg3] stringValue]))
					{
					id temp=[[COWSStringNode alloc] init];
					[temp setString:[[controlPanel arg3] stringValue]];
					[args push:temp];
					if (strlen([[controlPanel arg4] stringValue]))
						{
						id temp=[[COWSStringNode alloc] init];
						[temp setString:[[controlPanel arg4] stringValue]];
						[args push:temp];
						}	
					}	
				}	
			}	
	
		// this is in wrong order...so reverse it...
	
		new_args=[[COWSArgumentList alloc] init];
		while([args top]!=NULL)
			{
			[new_args push:[args pop]];
			}
		[args free];

		[interpreter interpretFunction:[[controlPanel function] stringValue]
					arguments:new_args];
		[new_args free];
		}
	else
		{
		printf ("COWS User Controller ERROR:  no interpreter to run!\n");
		return NULL;
		}
	return self;
	}
	

- loadAndRunOrStop:sender		
	{
	if (interpreter&&[interpreter conformsTo:@protocol(InterpreterControl)])
		{
		[interpreter printErrors:NO];
		if ([interpreter working])
			{
			[interpreter stopInterpreting];
			[controlPanel disableDisplay];
			[[controlPanel loadAndRunButton] setState:0];
			[[controlPanel lockedButton] setEnabled:YES];
			[[controlPanel foregroundButton] setEnabled:YES];
			[[controlPanel loadButton] setEnabled:YES];
			[[controlPanel runButton] setEnabled:YES];
			[controlPanel reenableDisplay];
			[controlPanel displayIfNeeded];
			}
		else if ([self load:self]) [self run:self];
		}
	else
		{
		printf 
		    ("COWS User Controller ERROR:  no interpreter to load and run!\n");
		return NULL;
		}
	return self;
	}
	

- setLockedToMe:sender		// assumes that sender is the lockedButton
	{
	if (interpreter&&[interpreter conformsTo:@protocol(InterpreterControl)])
		{
		[interpreter setLocked:(BOOL) [sender intValue]];
		}
	else
		{
		printf
		    ("COWS User Controller ERROR:  no interpreter to toggle lock!\n");
		return NULL;
		}
	return self;
	}
	

- setForegroundToMe:sender		// assumes that sender is the foregroundButton
	{
	if (interpreter&&[interpreter conformsTo:@protocol(InterpreterControl)])
		{
		[interpreter setForeground:(BOOL) [sender intValue]];
		}
	else
		{
		printf
	("COWS User Controller ERROR:  no interpreter to toggle foreground!\n");
		return NULL;
		}
	return self;
	}
	

- finishedInterpreting:(const char*)returnValue:(int)thisMessage:sender		
	{
	[super finishedInterpreting:returnValue:thisMessage:sender];
	return self;
	}
	

- errorInterpreting:(int) thisError:(const char*)thisFunction:
	(int)thisPosition:(const char*)thisString:sender		
	{
	char error[COWSUSERCONTROLLER_MAXERRSTRINGLENGTH];
	char msg[COWSUSERCONTROLLER_MAXERRSTRINGLENGTH];
	
	switch (thisError)
		{
		case COWSLIBRARYFUNCTIONERROR : 
			strcpy(msg,thisString); break;
		case COWSERRORNOSUCHFUNCTION : 
			strcpy(msg,"No Such Function"); break;
		case COWSERRORNOTENOUGHARGUMENTS : 
			strcpy(msg,"Not Enough Arguments"); break;
		case COWSERRORTOOMANYARGUMENTS : 
			strcpy(msg,"Too Many Arguments"); break;
		case COWSERRORNOSUCHVARIABLE : 
			strcpy(msg,"No Such Variable"); break;
		case COWSERRORNOMORETOKENS : 
			strcpy(msg,"No More Tokens"); break;
		case COWSERRORNOFUNCTIONNAME : 
			strcpy(msg,"No Function Name"); break;
		case COWSERRORSETNOTVARIABLE : 
			strcpy(msg,"Set: Not a Variable"); break;
		case COWSERRORSETTOOMANYVALUES : 
			strcpy(msg,"Set: Too Many Values"); break;
		case COWSERRORSETNOVALUE : 
			strcpy(msg,"Set: No Value to Set"); break;
		case COWSERRORSETNOSUCHVARIABLE : 
			strcpy(msg,"Set: No Such Variable"); break;
		case COWSERRORIFNOTHENCLAUSE : 
			strcpy(msg,"If: No Then Clause"); break;
		case COWSERRORIFTOOMANYVALUES : 
			strcpy(msg,"If: Too Many Values"); break;
		case COWSERRORIFNOTENOUGHVALUES : 
			strcpy(msg,"If: Not Enough Values"); break;
		case COWSERRORWHILETOOMANYVALUES : 
			strcpy(msg,"While: Too Many Values"); break;
		case COWSERRORWHILENOTENOUGHVALUES : 
			strcpy(msg,"While: Not Enough Values"); break;
		case COWSERRORFORNOTAVARIABLE : 
			strcpy(msg,"For: Not a Variable"); break;
		case COWSERRORFORSTARTNOTNUMBER : 
			strcpy(msg,"For: Start Value Not a Number"); break;
		case COWSERRORFORSTOPNOTNUMBER : 
			strcpy(msg,"For: Stop Value Not a Number"); break;
		case COWSERRORFORSTEPNOTNUMBER : 
			strcpy(msg,"For: Step Value Not a Number"); break;
		case COWSERRORFORNOSUCHVARIABLE : 
			strcpy(msg,"For: No Such Variable"); break;
		case COWSERRORFORTOOMANYVALUES : 
			strcpy(msg,"For: Too Many Values"); break;
		case COWSERRORFORNOTENOUGHVALUES : 
			strcpy(msg,"For: Not Enough Values"); break;
		case COWSINTERNALERROR : 
			strcpy(msg,"Interpreter Internal Error"); break;
		default : 
			strcpy(msg,"Unknown Error"); break;
		}
	
	if (thisError==COWSLIBRARYFUNCTIONERROR)
		{
		sprintf (error,"%s",msg);
		NXRunAlertPanel("Library Error",error,"Oops",NULL,NULL);
		}
	else
		{
		sprintf(error,"%s (%s, %d)",msg,thisString,thisPosition);
		NXRunAlertPanel("Interpreter Error",error,"Oops",NULL,NULL);
		}
		
	[super errorInterpreting:
			 thisError:thisFunction:thisPosition:thisString:sender];
	return self;
	}

- interpreterStarted:sender
	{
	[[controlPanel loadAndRunButton] setState:1];
	[[controlPanel lockedButton] setEnabled:NO];
	[[controlPanel foregroundButton] setEnabled:NO];
	[[controlPanel loadButton] setEnabled:NO];
	[[controlPanel runButton] setEnabled:NO];
	[controlPanel reenableDisplay];
	[super interpreterStarted:sender];
	return self;
	}

- interpreterStopped:sender
	{
	[[controlPanel loadAndRunButton] setState:0];
	[[controlPanel lockedButton] setEnabled:YES];
	[[controlPanel foregroundButton] setEnabled:YES];
	[[controlPanel loadButton] setEnabled:YES];
	[[controlPanel runButton] setEnabled:YES];
	[controlPanel reenableDisplay];
	[super interpreterStopped:sender];
	return self;
	}

	
@end
