// InformerDispatcher.m
//
// Purpose :
//		This is the main event handler for the entire application.
//
// History :
//     9.20.1992 : created by Max Tardiveau


#import "InformerDispatcher.h"

// theClass is used by the callback function loadModulesCallback to pass
// the just-loaded class.
static id theClass;


@implementation InformerDispatcher


char 	baseDir[256];		// base directory for our stuff


/////////////////////////////////////////////////
// Create a new "document" window

- newWindow:sender
{
id		newWindow;
char	tmpChar[32];
NXRect	tmpRect;

newWindow = [InformerWindow new];
[newWindow setDispatcher:self];
sprintf(tmpChar, "Informer window #%i", ++windowNumber);
[[newWindow window] setTitle:tmpChar];
[[newWindow window] getFrame:&tmpRect];
[[newWindow window] moveTo:tmpRect.origin.x + (((windowNumber-1) % 5)*30)
							:tmpRect.origin.y - (((windowNumber - 1) % 5)*30)];

return self;
}

/////////////////////////////////////////////////
// Pops up an error panel.

- showError:(char *)message
{
[ErrorPanelText setStringValue:message];
[ErrorPanel makeKeyAndOrderFront:self];

return self;
}

//////////////////////////////////////////////////////////////
// This is called every time an Informer window becomes active.
// The sender is NOT the window itself, but the InformerWindow
// responsible for it (which is its delegate).

- newFrontWindow:sender
{
//[closeMenuCell setEnabled:YES];
currentWindow = sender;

return self;
}

//////////////////////////////////////////////////////////////
// This is called every time an Informer window becomes inactive.
// The sender is NOT the window itself, but the InformerWindow
// responsible for it (which is its delegate).

- oldFrontWindow:sender
{
if (currentWindow == sender)	// Only if this was the current window
	{
	//[closeMenuCell setEnabled:NO];
	currentWindow = nil;
	}

return self;
}

/////////////////////////////////////////////////
//

- explode:sender
{
Explode();
[AboutPanel performClose:self];
return self;
}

/////////////////////////////////////////////////
// This is the callback function used in objc_loadModules to get a hold
// of the loaded class.

void loadModulesCallback(Class tmpClass, Category unused)
{
theClass = (id)tmpClass;
}

//////////////////////////////////////////////////////////////////////
// This method loads a class if needed.
// The directories of all loaded classes are stored in a linked
// list, along with the class.

- loadClassFromCell:theCell
{
NXStream	*errorStream;
char		*errorstring;
int 		length, max;
char		tmpchar[512], tmpchar2[512], tmpchar3[512];
char		*char_array[4];
FILE		*libsFile;
struct stat myStat;
struct LoadedClassNode
	{
	char	DirName[256];
	id		Class;
	struct LoadedClassNode *next;
	};
static struct LoadedClassNode *firstNode = NULL;
struct LoadedClassNode *newNodePtr, *tmpNodePtr;

// Search linked list, see if the class is already loaded.
for (tmpNodePtr = firstNode; tmpNodePtr != NULL; tmpNodePtr = tmpNodePtr->next)
	{
	if ( ! strncmp( [theCell getDir], tmpNodePtr->DirName, 255))
		return tmpNodePtr->Class;	// Got it, return the class
	}

// Nope, not loaded yet, add it to the linked list.
newNodePtr = (struct LoadedClassNode *) malloc(sizeof(struct LoadedClassNode));
newNodePtr->next = NULL;
strncpy(newNodePtr->DirName, [theCell getDir], 255);

if (firstNode == NULL)
	firstNode = newNodePtr;
else
	for (tmpNodePtr = firstNode; tmpNodePtr != NULL;
									tmpNodePtr = tmpNodePtr->next)
		if (tmpNodePtr->next == NULL)
			{
			tmpNodePtr->next = newNodePtr;
			break;
			}

sprintf(tmpchar, "%s/Main.o", [theCell getDir]);

char_array[0] = tmpchar;
char_array[1] = NIL;

// Is there a special library to load ?
sprintf(tmpchar2, "%s/Libs", [theCell getDir]);
if (stat(tmpchar2, &myStat) == 0)
	{
	if ((libsFile = fopen(tmpchar2, "r")) == NULL)
		fprintf(stderr, "InformerDispatcher : error in fopen(loadClass).\n");
		
	if (fgets(tmpchar2, 511, libsFile) == NULL)
		fprintf(stderr, "InformerDispatcher : error in fgets().\n");
		
	length = strlen(tmpchar2);
	if (tmpchar2[length - 1] == '\n')	// Get rid of final NL
		tmpchar2[length - 1] = '\0';
	fclose(libsFile);
	
	if (tmpchar2[0] == '/')			// Absolute path
		char_array[1] = tmpchar2;
	else							// Relative path
		{
		sprintf(tmpchar3, "%s/%s", [theCell getDir], tmpchar2);
		char_array[1] = tmpchar3;
		}
	char_array[2] = NIL;
#ifdef DEBUG
	fprintf(stderr, "Loading additional lib : %s\n", tmpchar2);
#endif // DEBUG
	}

// Try loading Main.o alone, then with libsys.a
errorStream = NXOpenMemory(NULL, 0, NX_WRITEONLY);
#ifdef DEBUG
if (objc_loadModules(char_array, errorStream, &loadModulesCallback, NIL, 
														"LoadedClass.debug"))
#else
if (objc_loadModules(char_array, errorStream, &loadModulesCallback, NIL, NIL))
#endif /* DEBUG */
	{
	// Try with the system library : it could be a few missing symbols
	if (char_array[1] != NIL)		// Already an extra library;
		{
		char_array[2] = "/lib/libsys_s.a";
		char_array[3] = NIL;
		}
	else
		{
		char_array[1] = "/lib/libsys_s.a";
		char_array[2] = NIL;
		}
	
	if (objc_loadModules(char_array, errorStream,
										&loadModulesCallback, NIL, NIL))
		{
		NXGetMemoryBuffer(errorStream, &errorstring, &length, &max);
		sprintf(tmpchar, "InformerDispatcher : %s\n", errorstring);
		[currentWindow addMessage:tmpchar];
		[self showError:"Error loading object file."];
		NXClose(errorStream);
		return NIL;
		}
	}
NXClose(errorStream);

newNodePtr->Class = theClass;

return theClass;
}


///////////////////////////////////////////////////////////////////////////////
// Delegate methods
//
//////////////////////////////////////////////////////////////
// Is called after the application has opened.

- appDidInit:sender
{
FILE	*process;
char	command[256];
char	tmpDir[256];
char	*suffix;

strncpy (tmpDir,NXArgv[0], 255);
if (tmpDir[0] == '/')			// if absolute path
	{
	if (suffix = rindex(tmpDir,'/')) 
		*suffix  = '\0';			// remove executable name
	}
else			// pretty ugly, but that's what NeXT recommands
	{
	sprintf(command, "which '%s'\n", NXArgv[0]);
	process = popen(command,"r");
	fscanf(process, "%s", tmpDir);
	pclose(process);
	if (suffix = rindex(tmpDir, '/')) 
		*suffix  = '\0';			// remove executable name
	chdir(tmpDir);
	getwd(tmpDir);
	}  

sprintf(baseDir, "%s/Lib", tmpDir);

[self newWindow:self];

return self;
}

@end
