// Eigen.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 "Eigen.h"

@implementation Eigen

// 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.

	return self;
}

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

- setImprovConnector:anObject
{
	improvConnector = anObject;
	return self;
}

// Implement methods called by the inspector's ok: method.

// Implement methods called by the inspector's revert method.


// ****************************************************************************
// ****************************************************************************
// WBTool protocol methods.
// ****************************************************************************
// ****************************************************************************

- evaluate:sender
{
	double **matrix;
	int row, col, numCols, numRows, type;
	char element[25], *matrixString, *mathCommand, *lastComma;
	BOOL success = NO;
	void *result;

	// Specify that empty or text cells return 0.
	[improvConnector setCellHandlingForEmpty:WB_ZERO text:WB_ZERO];

	// Get the matrix from the Improv spreadsheet, build a Mathematica
	// command, ship it off to Mathematica.
	if([improvConnector doubleData:&matrix fromSelectedColumnsCount:&numCols 	
			byRows:YES dataCount:&numRows])
		NXRunAlertPanel("Error", "Unable to obtain data from Improv.", NULL, 
				NULL, NULL);
	else
	{
		if(numRows != numCols)
			NXRunAlertPanel("Error", "You can only compute eigenvalues of "
					"square matrices.", NULL, NULL, NULL);
		else
		{
			matrixString = (char *)malloc(numRows * numRows * 23); 

			// Build the Mathematica command.
			strcpy(matrixString, "{");
			for(row = 0; row < numRows; row++)
			{
				strcat(matrixString, "{");
				for(col = 0; col < numCols; col++)
				{
					sprintf(element, "%f, ", matrix[row][col]);
					strcat(matrixString, element);
				}
				lastComma = rindex(matrixString, ',');
				*lastComma = ' ';
				strcat(matrixString, "},");
			}
			lastComma = rindex(matrixString, ',');
			*lastComma = ' ';
			strcat(matrixString, "}");

			mathCommand = (char *)malloc(strlen(matrixString) + 25); 
			sprintf(mathCommand, "Chop[Eigenvalues[N[%s]]]", matrixString);	
			free(matrixString);
			type = STRING;

			// Ask Mathematica to execute the command.
			success = [mathConnector evaluateExpression:mathCommand
					resultType:type result:&result];
			free(mathCommand);
		
			// Display the result if Mathematica successfully executed 
			// the command.
			if(success)
			{
				[outputText setText:(char *)result];
				[[outputText window] makeKeyAndOrderFront:self];
				free(result);
			}
			else
				[outputText setText:""];
		}
	}
	return self;
}

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

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

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

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

- setOutputViewBox:box
{
	outputViewBox = box;
	return self;
}

@end
