// Differentiator.m
// By Charles G. Fleming, Educational Computing Services, Allegheny College.
// Copyright 1993, Allegheny College.
// You may freely copy, distribute and reuse this code. 
// Allegheny College and the author disclaim any warranty of any kind, 
// expressed or implied, as to its fitness for any particular use.

#import "Differentiator.h"

@implementation Differentiator

// If the object has an inspector, we'll load it here.  Initialize variables
// that will be displayed by the inspector.
- init
{
	NXBundle *bundle;
	char path[MAXPATHLEN+1], inspectorName[MAXPATHLEN+1];
	
	[super init];

	strcpy(inspectorName, [[self class] name]);
	strcat(inspectorName, "Inspector");
	 
	bundle = [NXBundle bundleForClass:[self class]];

	// If the Inspector nib file exists, load it.  Otherwise, free the bundle.	
	if([bundle getPath:path forResource:inspectorName ofType:"nib"])
		[NXApp loadNibFile:path owner:self withNames:NO fromZone:[self zone]];
	else
		[bundle free];

	// Initialize variables that will be used by the inspector.
	order = 1;
	differentiationVariable = (char *)malloc(2);
	strcpy(differentiationVariable, "x");
	inputForm = YES;
	return self;
}

- setMathConnector:anObject
{
	mathConnector = anObject;
	return self;
}

// Implement methods called by the inspector's ok: method.
- setOrder:(int)theOrder
{
	order = theOrder;
	return self;
}

- setDifferentiationVariable:(const char *)variable
{
	differentiationVariable = (char *)realloc(differentiationVariable,
			strlen(variable)+1);
	strcpy(differentiationVariable, variable);
	return self;
}

- setInputForm:(BOOL)flag;
{
	inputForm = flag;
	return self;
}	

// Implement methods called by the inspector's revert method.
- (int)order
{
	return order;
}

- (char *)differentiationVariable
{
	return differentiationVariable;
}

- (BOOL)inputForm
{
	return inputForm;
}
	
// ****************************************************************************
// ****************************************************************************
// WBTool protocol methods.
// ****************************************************************************
// ****************************************************************************

- evaluate:sender
{
	char *commandString, *functionString, *greaterSign;
	void *result;
	BOOL success = NO;
	int type, textLength;

	// Get the function to be differentiated.
	textLength = [inputText textLength];
	if(textLength > 0)
	{
		functionString = (char *)malloc(textLength+1);
		[inputText getSubstring:functionString start:0 length:textLength+1];

		// Build the Mathematica command for computing the derivative.
		commandString = malloc(strlen(functionString) + 
				strlen(differentiationVariable)+ 50); 
		sprintf(commandString, "wbPreviousResult = D[%s, {%s,%d}]",
				functionString, differentiationVariable, order);
		type = STRING;

		free(functionString);

		// Ask Mathematica to execute the command.
		success = [mathConnector evaluateExpression:commandString
				resultType:type result:&result];
		free(commandString);

		// Display the result if Mathematica successfully executed the command.
		if(success)
		{
			// Display the result in OutputForm.
			[outputText setText:(char *)result];
			[[outputText window] makeKeyAndOrderFront:self];
			free(result);

			if(inputForm)
			{
				// Get the InputForm of the result.
				commandString = malloc(30); 
				strcpy(commandString, "InputForm[wbPreviousResult]");
				type = STRING;

				// Ask Mathematica to execute the command.
				success = [mathConnector evaluateExpression:commandString
						resultType:type result:&result];
				free(commandString);

				// Display the InputForm.
				if(success)
				{
					while(greaterSign = index((char *)result, '>'))
						*greaterSign = ' ';
					[inputText setText:(char *)result];
					free(result);
				}	
				else
					[inputText setText:""];
			}
		}	
		else
			[outputText setText:""];
	}		

	return self;
}

// Set up the null terminated list of connectors that the tool will need.
- (char **)requiredConnectors
{
	static char *connectors[] = {"MathConnector", NULL};
	return connectors;
}

// Return the inspector.
- inspector
{
	return inspector;
}

- setInputText:text
{
	inputText = text;
	return self;
}

- setOutputText:text
{
	outputText = text;
	return self;
}

- setOutputView:view
{
	outputView = view;
	return self;
}

@end
