/*
*	L o t u s   I m p r o v
*
*	Filename:				imxMenuServer.m
*	Created:				Oct 16, 1990
*	Author:   				Curt Gridley
*	Description:			public  API menu server 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/publicWraps.h>
#import <appkit/Matrix.h>
#import	<strings.h>
#import <imxMenuServer.h>

#define	MINIMXMENUTAG		10000
#define	BBMENUHOOK			"Services"
#define	IMXMENU				"Tools"

//-----------------------------------------------------------------------------
//	Implementation: imxMenuServer
//-----------------------------------------------------------------------------

@implementation imxMenuServer

static struct mach_header *imxMenuServerHdr = NULL;
static id imxMainMenu = NULL;

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

+ finishLoading:(struct mach_header *)header
{
	imxMenuServerHdr = header;
	printf("FinishLoading class: imxMenuServer (header = 0x%x)\n", header);
	[self new];
	return self;
}

//-----------------------------------------------------------------------------
//	Proc: startUnloading
//-----------------------------------------------------------------------------

+ startUnloading;
{
	printf("StartUnloading class: imxMainMenu\n");
	return self;
}

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

+ new
{
	// id myApp = NXApp;		// snatch for access from debugger
	id topMenu = [NXApp mainMenu];		
	id topMatrix = [topMenu itemList];
	id topCell = NULL;
	int newRow, ncells;

  // Only keep one instance of this bugger around
	if (imxMainMenu)
		return imxMainMenu;

  // Create Tools submenu
	imxMainMenu = self = [super newTitle:IMXMENU];
	[self setDelegate:self];		// to handle menuItemUpdate: messages
	printf("[imxMainMenu new] => 0x%x\n", self);

  // Add Tools menu to main menu.
	for (newRow = 0, ncells = [topMatrix cellCount]; newRow < ncells; newRow++) {
		if (!strcmp(BBMENUHOOK, [[topMatrix cellAt:newRow :0] title])) {
			[topMatrix insertRowAt:newRow];
			[topMatrix setTitle: IMXMENU at:newRow :0];
			topCell = [topMatrix cellAt:newRow :0];
			break;
		}
	}

	if (newRow >= ncells) {
		printf("Can't find \"Services\" menu as anchor for Tools menu\n");
		return self;
	}

  // resize menus
	[topMenu setSubmenu:self forItem:topCell];
	[topMenu sizeToFit];
	[self sizeToFit];

	return self;	
}

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

- (BOOL)menuItemUpdate:menuCell
{
	BOOL enabled = YES;
	id target = [menuCell target];

	//printf("[imxMenuServer menuItemUpdate: 0x%x]\n", menuCell);

	if (![target respondsTo:@selector(menuItemUpdate:)])
		return NO;

  // Handle user added menuItems here
  // (check to avoid infinite recursion).
	if (target != self)
		return [target menuItemUpdate:menuCell];

	if (enabled != [menuCell isEnabled]) {
		[menuCell setEnabled:enabled];
		return YES;
	}

	return NO;
}

//-----------------------------------------------------------------------------
//	Proc: addMenuItem:target:action:key:update:
//-----------------------------------------------------------------------------

- (int)addMenuItem:(const char *)name target:targ
		action:(SEL)aSelector key:(unsigned short)key
		update:(BOOL)doUpdate
{
	static int stag = MINIMXMENUTAG;	// all imx menu items >= MINIMXMENUTAG
	id newCell;

	printf("addMenuItem: \"%s\", 0x%x, %d, %d, %d\n",
			name, targ, aSelector, key, doUpdate);

  // Validate arguments
	if (!name || strlen(name) <= 0)
		return -1;
	if (!targ || ![targ respondsTo:aSelector])
		return -2;
	if (doUpdate && ![targ respondsTo:@selector(menuItemUpdate:)])
		return -3;

  // Should deal with multi-level names here
	newCell = [self addItem:name action:aSelector keyEquivalent:key];
	if (doUpdate) {
		[newCell setUpdateAction:@selector(menuItemUpdate:) forMenu:self];
		[newCell setEnabled:YES];
	}
	[newCell setTarget: targ];
	[newCell setTag: stag++];
	[self sizeToFit];
	[self display];
	
	return [newCell tag];
}

//-----------------------------------------------------------------------------
//	Proc: deleteMenuItemWithTag:
//-----------------------------------------------------------------------------

- (int)deleteMenuItemWithTag:(int)aTag
{
	id menuCell;
	id menu;
	id mat;
	int status;
	int row, col;

	if (aTag < MINIMXMENUTAG)
		return -1;
	if ((status = [self getMenu:&menu andCell:&menuCell forTag:aTag]) < 0)
		return status;
	mat = [menu itemList];
	[mat getRow:&row andCol:&col ofCell:menuCell];
	if (row >= 0) {
		[mat removeRowAt:row andFree:YES];
		[mat sizeToCells];
		[menu setItemList:mat];
	} else
		return -1;
	[menu sizeToFit];
	return 0;
}

//-----------------------------------------------------------------------------
//	Proc: setEnabled:forMenuItemWithTag:
//-----------------------------------------------------------------------------

- (int)setEnabled:(BOOL)enabled forMenuItemWithTag:(int)aTag
{
	id menuCell;
	id menu;
	int status;

	if (aTag < MINIMXMENUTAG)
		return -1;
	if ((status = [self getMenu:&menu andCell:&menuCell forTag:aTag]) < 0)
		return status;
	[menuCell setEnabled:enabled];
	return 0;
}

//-----------------------------------------------------------------------------
//	Proc: getMenu:andCell:forTag:inMenu:
//-----------------------------------------------------------------------------

- (int)getMenu:(id *)menuP andCell:(id *)menuCellP forTag:(int)aTag
		inMenu:(id)thisMenu
{
	id thisMatrix = [thisMenu itemList];
	int maxRow = [thisMatrix cellCount];
	int row;

    for (row = 0; row < maxRow; row++) {
		id thisCell = [thisMatrix cellAt:row :0];
		//printf("cell: 0x%x, tag:%d\n", thisCell, [thisCell tag]);
		if ([thisCell tag] == aTag) {
			*menuP = thisMenu;
			*menuCellP = thisCell;
			//printf("found it!!\n");
			return 0;
		}
		else if ([thisCell hasSubmenu]) {
			//printf("submenu:0x%x\n", [thisCell target]);
	 		if (![self getMenu:menuP andCell:menuCellP forTag:aTag
						inMenu:[thisCell target]])
				return 0;
			//printf("end submenu\n");
		}
	}

	return -1;
}

//-----------------------------------------------------------------------------
//	Proc: getMenu:andCell:forTag:
//-----------------------------------------------------------------------------

- (int)getMenu:(id *)menuP andCell:(id *)menuCellP forTag:(int)aTag
{
	*menuP = nil;
	*menuCellP = nil;
	 return [self getMenu:menuP andCell:menuCellP forTag:aTag
	 			inMenu:[NXApp mainMenu]];
}

@end

