/*
*	L o t u s   I m p r o v
*
*	Filename:				imxLoader.m
*	Created:				Oct 16, 1990
*	Author:   				Curt Gridley
*	Description:			public API module loader routines
*
*	You may freely copy, distribute and reuse the code in this example.
*	Lotus disclaims any warranty of any kind, expressed or implied, as to its
*	fitness for any particular use.
*
*	Copyright (c) Lotus Development Corporation 1990, 1991
*/

#import <appkit/Application.h>
#import <appkit/OpenPanel.h>
#import <appkit/publicWraps.h>
#import <objc/objc-load.h>
#import <strings.h>
#import <sys/dir.h>
#import <fcntl.h>
#import <libc.h>

#import <imxMenuServer.h>
#import <imxPublicAPI.h>
#import <imxLoader.h>

#define	IMXLOADER		"Load Module..."

#define	DEFAULTOAKDIR	".oakum"


//-----------------------------------------------------------------------------
//	Implementation: imxLoader
//-----------------------------------------------------------------------------

@implementation imxLoader

static id onlyInstance = NULL;
static struct mach_header *iimxLastHeader = NULL;

//-----------------------------------------------------------------------------
//	Proc: loadDefaultModules
//-----------------------------------------------------------------------------

static void loadDefaultModules(void)
{
	DIR *dirp;
	struct direct *dp;
	char namebuff[256];
	char dirname[256];
	imxErrorCode status;
	char *tail = NULL;

  // Save Private Resource Inspector
	sprintf(dirname, "%s/%s", NXHomeDirectory(), DEFAULTOAKDIR);
	if (access(dirname, F_OK) != 0)
		return;

	if (dirp = opendir(dirname))
	{
		while (dp = readdir(dirp))
		{
		  // check suffix
			if (!(tail = rindex(dp->d_name, '.')) || strlen(tail) != 4 ||
					strcmp(tail, ".mod"))
			{
				continue;
			}
			sprintf(namebuff, "%s/%s", dirname, dp->d_name);
			[[imxLoader new] imxLoadModule:namebuff errors:NULL debugFile:NULL
					status:&status];
		}
		closedir(dirp);
	}
}

//-----------------------------------------------------------------------------
//	Proc: finishLoading:
//-----------------------------------------------------------------------------

+ finishLoading:(struct mach_header *)header
{
	printf("FinishLoading class: %s\n", [self name]);
	onlyInstance = [[self alloc] initHeader:header];
	loadDefaultModules();
	return self;
}

//-----------------------------------------------------------------------------
//	Proc: new
//-----------------------------------------------------------------------------

+ new
{
	if (onlyInstance)
		return onlyInstance;

  // This should never really happen since the only instance of the class
  // is allocated when the class is loaded in finishLoading:. 
	onlyInstance = [[self alloc] initHeader:NULL];

	return self;
}

//-----------------------------------------------------------------------------
//	Proc: initHeader:
//-----------------------------------------------------------------------------

- initHeader:(struct mach_header *)header
{
	classHeader = header;

  // install menuItem
	menuTag = [[imxMenuServer new] addMenuItem:IMXLOADER target:self
				action:@selector(menuSelect:) key:0 update:YES];
	
	printf("[%s initHeader:0x%x] => 0x%x\n", [self name], classHeader, self);
	printf("[%s menuTag] => %d\n", [self name], menuTag);

	return self;	
}

//-----------------------------------------------------------------------------
//	Proc: menuItemUpdate:
//-----------------------------------------------------------------------------

- (BOOL)menuItemUpdate:menuCell
{
	BOOL enabled = YES;

  // Determine whether menuCell SHOULD be enabled.
  // Put YOUR code HERE to determine desired "enabled" state...
  
  // Compare desired state with existing state and
  // ask for update if necessary by returning YES.
	if (enabled != [menuCell isEnabled]) {
		[menuCell setEnabled:enabled];
		return YES;
	}

	return NO;
}

//-----------------------------------------------------------------------------
//	Proc: menuSelect:
//-----------------------------------------------------------------------------

- menuSelect:sender
{
  // If you want a panel associated with this class then you should
  // load the panel here the first time the menuItem is selected.
  // The panel is assumed to be in a section named after the class name.
  // For instance if this class is named "Generic", then the nib section
  // should be named "Generic.nib".  The instance variable "nibPanel"
  // should be set as an outlet for the Panel from InterfaceBuilder.

	if (!nibPanel) {
		char sname[128];
		sprintf(sname, "%s.nib", [self name]);

		[NXApp loadNibSection:sname owner:self withNames:YES
				fromHeader:classHeader];
	}

  // This assumes that you want to invoke a modeless panel.
  // You could also invoke a modal panel here using runModalFor:.
  // Or you could simply perform some operation that doesn't
  // require a panel.
	if (nibPanel) {
		[nibPanel makeKeyAndOrderFront:self];	// Modeless panel...
		//[NXApp runModalFor:nibPanel];			// or Modal panel...
	} else
		[self doCalc];				// Put simple operations here...

	return self;
}

//---------------------------------------------------------------------------
//	Proc: iimxLoadHook
//---------------------------------------------------------------------------

void iimxLoadHook(Class cls, Category cat)
{
	if (cat) {
		printf("iimxLoadHook: category=%s, class=%s\n",
			cat->category_name, cat->class_name);
	} else if (cls)
		printf("iimxLoadHook: class=%s\n", cls->name);
}

//---------------------------------------------------------------------------
//	Proc: imxLoadModule
//---------------------------------------------------------------------------

imxErrorCode imxLoadModule(char *moduleName, char **errorText, char *debugfile)
{
	char *errorstring = NULL;
	int length, max;
	char *namevec[4];
	NXStream *errorStream = NXOpenMemory(NULL, 0, NX_WRITEONLY);
	char namebuf[256];
	
	namebuf[0] = '\0';

	debugfile = (debugfile && strlen(debugfile) > 0) ? debugfile : NULL;
	namevec[0] = moduleName;
	namevec[1] = namevec[2] = namevec[3] = NULL;

	if (objc_loadModules(namevec, errorStream, iimxLoadHook,
			&iimxLastHeader, debugfile)) {
	    NXGetMemoryBuffer(errorStream, &errorstring, &length, &max);
		if (length > 0 && errorstring) {
			strncpy(namebuf, errorstring, 255);
	    	printf("imxLoadModule: %s\n", errorstring);
		}
	} else
		printf("imxLoadModule: loaded \"%s\"\n", moduleName);
      
	NXClose(errorStream);
	if (errorText)
		*errorText = namebuf;

	return imxerr_OK;
}

//---------------------------------------------------------------------------
//  Proc: imxLoadModule:errors:debugFile:status:
//---------------------------------------------------------------------------

- (int)imxLoadModule:(char *)moduleName errors:(char **)errorText
	debugFile:(char *)debugfile status:(imxErrorCode *)status
{
	*status = imxLoadModule(moduleName, errorText, debugfile);
	return 0;
}

//-----------------------------------------------------------------------------
//	Proc: doCalc
//-----------------------------------------------------------------------------

- doCalc
{
	const char *fname;
	char *errtext;
	char dfile[128];
	char *lastpt;
	imxErrorCode status;
	char *xftypes[2] = { "mod", NULL };

	[[OpenPanel new] runModalForTypes:xftypes];
	if (fname = [[OpenPanel new] filename]) {
		strcpy(dfile, fname);
		lastpt = rindex(dfile, '.');
		if (lastpt) {
			*(++lastpt) = 'x';
			[self imxLoadModule:(char *)fname errors:&errtext
					debugFile:dfile status:&status];
			if (status != imxerr_OK)
				printf("Load failed for \"%s\"\n", fname);
			if (errtext && strlen(errtext))
				printf("Load Error: %s\n", errtext);
		}
	} else {
		NXBeep();
	}
	return self;
}

@end
