/*
 * $Source: $
 * $Revision: $
 * $Date: $
 * $State: $
 * $Author: $
 *
 *
 * $Log: $
 * Revision 3.1  3/10/92 wade
 * Added Baylor's changes
 * #include documentRec.h and cmd_read_gif_file()
 *
 */

/*  
 *	Copyright (c) 1991 by the Massachusetts Institute of Technology,
 *	For copying and distribution information, see the file
 *	"mit-copyright.h".
 *
 * 	menuMgr.c  - WADE 8/23/89
 *	
 *	menu_bar_init
 *	menu_adjust
 *	menu_do_command
 *	menu_add
 *	menu_delete
 *
 */
 
#include <Limits.h>
#include <Types.h>
#include <QuickDraw.h>
#include <Fonts.h>
#include <Events.h>
#include <Controls.h>
#include <Windows.h>
#include <Menus.h>
#include <TextEdit.h>
#include <Dialogs.h>
#include <Desk.h>
#include <Scrap.h>
#include <ToolUtils.h>
#include <Memory.h>
#include <SegLoad.h>
#include <Files.h>
#include <OSUtils.h>
#include <Traps.h>
#include <Resources.h>
#include <SysEqu.h>
#include "pips.h" 
#include <stdio.h>
#include "prototype.h"
#include "mit-copyright.h"
#include "documentRec.h"

extern WindowPtr	gTextWindow;

/*     
 *
 * menu_bar_init:
 * 
 *	called from main program during initialization stage.
 *
 */
void
menu_bar_init(menuResource)
short	menuResource;
{
	Handle		menuBar;	
	
	menuBar = GetNewMBar(menuResource);		/* read menus into menu bar */
	if ( menuBar == nil )
				BigBadError(NO_MEMORY);
	SetMenuBar(menuBar);					/* install menus */
	DisposHandle(menuBar);
	AddResMenu(GetMHandle(APPLE), 'DRVR');	/* add DA names to Apple menu */
	DrawMenuBar();
}	/* menu_bar_init */

/*     
 *
 *  menu_adjust:
 *
 *	Enable and disable menus based on the current state.
 *	The user can only select enabled menu items. We set up all the menu items
 *	before calling MenuSelect or MenuKey. 
 */
#pragma segment Main 
void menu_adjust()
{
	long		offset;
	Boolean		cutCopyClear;
	Boolean		paste;
	Boolean		undo;
	TEHandle	te;
	MenuHandle	menuE;
	MenuHandle	menuB;
	MenuHandle	menuF;
	MenuHandle	menuP;
	Boolean		rc;
	Boolean		any_visible;
	Boolean		text_visible;
	Boolean		active_list_item;
	Str255		type;
	Str255		list_buffer;
	Str255		window_title;
	WindowPtr	front_window;
	WindowPtr	next_window;
	WindowPtr	list_window;
	short		ctr;
	short		num_items;
	int			window_type;
	int			item_type;
	short		sections;
	short		section;
	int			text_size;
	short		active;
	Boolean		owner;
	short		item;
	data_edit	undo_flags;
	
	typedef struct {
		WindowPtr	window;
		short		section;
	} wlist;
	wlist	window_list;
	
	enum{store,retrieve};
	
	front_window = FrontWindow();

	menuE = GetMHandle(EDIT);
	menuB = GetMHandle(BROWSER);
	menuF = GetMHandle(FILEM);
	menuP = GetMHandle(PROVIDER);
		
	/* Determine if there is a visible list or text window in the window list */
	any_visible = false;
	text_visible = false;
	next_window = FrontWindow();
	while( next_window != nil && IsAppWindow(next_window) ) {
		if (wind_visible(next_window)) {
			window_type = wind_type(next_window);
			any_visible = true;
			if (window_type == text)
				text_visible = true;
		}
		(WindowPeek)next_window = wind_next_window(next_window);
	}
		
	/* determine how the current menu was created */
	owner = cmd_menu_owner();

	/* close front window (list, or text windows) */
	if (any_visible)
		EnableItem(menuF, CLOSE);
	else
		DisableItem(menuF, CLOSE);

	/* determine if there is a highlighted list item in a visible list window */
	active_list_item = false;
	list_window = wind_find_window(list);
	if (list_window != NULL && wind_visible(list_window) ) {
		active_list_item = list_get_list_select(&item);
		if (active_list_item)
			rc = list_last_click_buffer(list_buffer);
	}
						
	EnableItem(menuB,MAIN);
	
	// mec - twiddled with the following code quite thoroughly, to add support
	//	for saving GIF images
	/* is front window invisible */
	if ( !wind_visible(front_window)) {
		DisableItem(menuF, SAVE_TEXT);
		DisableItem(menuF, USERSTARTUP);
		DisableItem(menuB, WORD);
		DisableItem(menuB, AGAIN);
	} else {									// front window is visible
		switch (wind_type(front_window)) {
			case text:							// is it a text or a list?
			case list:
				EnableItem(menuF, SAVE_TEXT);
				SetItem(menuF, SAVE_TEXT, "\pSave TextÉ");
				EnableItem(menuF, USERSTARTUP);
				EnableItem(menuB, WORD);
				EnableItem(menuB, AGAIN);
				break;
			case gif:							// how about a gif?
				EnableItem(menuF, SAVE_TEXT);
				SetItem(menuF, SAVE_TEXT, "\pSave ImageÉ");
				DisableItem(menuF, USERSTARTUP);
				DisableItem(menuB, WORD);
				DisableItem(menuB, AGAIN);
				break;
			default:
				DisableItem(menuF, SAVE_TEXT);
				SetItem(menuF, SAVE_TEXT, "\pSave TextÉ");	// not necessary, but maintains current behavior
				DisableItem(menuF, USERSTARTUP);
				DisableItem(menuB, WORD);
				DisableItem(menuB, AGAIN);
				break;
		}	// switch
	}	// else

	if ( wind_visible(front_window) && 
		(wind_type(front_window) == text || wind_type(front_window) == list || 
		wind_type(front_window) == getinfo)) {
		EnableItem(menuF, PRINT);

	}
	else
		DisableItem(menuF, PRINT);

		
	/* remove window list in browser menu, then add the current window list */
 	num_items = CountMItems(menuB);
	for (ctr = num_items; ctr != WINDOW_LIST; ctr--)
		DelMenuItem(menuB,ctr);
		
	ctr = -1;
	next_window = *((WindowPtr *) WindowList);
	while(next_window != nil && IsAppWindow(next_window)) {
		if (wind_visible(next_window) || wind_type(next_window) == list) {
			GetWTitle(next_window,&window_title);
			if (window_title[0] > 50) {
				window_title[51] = '.';
				window_title[52] = '.';
				window_title[0] = 52;
			}
		
			window_list.window = next_window;
			if ( wind_type(next_window) == text ) {
			
				data_text_size(retrieve,&text_size);
				data_text_active(retrieve,&active);
				
				/* get the number of text sections */
				if ( text_size > NETWORK_RECEIVE_SIZE )
					/* determine number of sections and change the window name */
					sections = text_size / NETWORK_RECEIVE_SIZE;
				else
					sections = 0;
					
				for (section=0;section<=sections;section++) {
					window_list.section = section;
					AppendMenu(menuB,"\p ");
					if ( sections > 0 )
						sprintf(&window_title[window_title[0]],"%d",section+1);

					SetItem(menuB,CountMItems(menuB),window_title);
					if ((front_window == next_window) && (active == section)) 
						CheckItem(menuB, CountMItems(menuB), true);
					rc = wind_windows_data(store,++ctr,&window_list);
				}
			}
			else {
				window_list.section = 0;	/* not used */
				AppendMenu(menuB,"\p ");
				SetItem(menuB,CountMItems(menuB),window_title);
				rc = wind_windows_data(store,++ctr,&window_list);
			}
				
		}
		
		/* check this menu item if it is this the FrontWindow() */
		if (front_window == next_window && wind_type(next_window) != text)
			CheckItem(menuB, CountMItems(menuB), true);

		(WindowPeek)next_window = wind_next_window(next_window);
	}
				
	if (active_list_item) {
		/* get type of list item */
		item_type = 0;
		rc = get_field(list_buffer,TYPE,type);
		if (rc)
			if (type[0] == 't')
				item_type = text;
			else
				if (type[0] == 's')
					item_type = list;

		EnableItem(menuF, GETINFO);
		
		/* if there is a selected list item, and the list window is active, then ok */
		DisableItem(menuB,OUTLINE);
		if (wind_type(front_window) == list) {
			if (item_type == text) {
				SetItem(menuB,SHOW,"\pShow Selected Document");
				EnableItem(menuB,SHOW);
				EnableItem(menuB,SHOW_PATH);
			}
			else
				if (item_type == list) {
					SetItem(menuB,SHOW,"\pShow Selected Folder");
					EnableItem(menuB,SHOW);
					EnableItem(menuB,OUTLINE);
					EnableItem(menuB,SHOW_PATH);
				}
		}
		
		if ( menuP != NULL ) {
									
			EnableItem(menuP,MODIFY_ITEM);
			EnableItem(menuP,REMOVE_ITEM);
						
			if (item_type == text && text_visible)
				EnableItem(menuP,SEND_DOCUMENT);
			else
				DisableItem(menuP,SEND_DOCUMENT);
		}
		
	}
	else {
		DisableItem(menuF, GETINFO);
		DisableItem(menuB, SHOW);
		DisableItem(menuB, OUTLINE );
		DisableItem(menuB, SHOW_PATH );
		if ( menuP != NULL ) {
			DisableItem(menuP, MODIFY_ITEM);
			DisableItem(menuP, REMOVE_ITEM);
			DisableItem(menuP, SEND_DOCUMENT);
		}
	}
	
	/* enable/disable provider menu functions which don't depend on a selected cell */
	if ( menuP != NULL ) {
		DisableItem(menuF, PROVIDER_MENU);
		
		if (owner) 
			EnableItem(menuP,DEFINE_MENU_ITEM);
		else
			DisableItem(menuP,DEFINE_MENU_ITEM);
		
		if (text_visible)
			SetItem(menuP,CLEAR_DOCUMENT,"\pClear Text Window");
		else
			SetItem(menuP,CLEAR_DOCUMENT,"\pNew Text Window");
	}
	else
		EnableItem(menuF, PROVIDER_MENU);
	
	/* is there anything on the "return to previous menu" stack? */
	if (util_check_stack())
		EnableItem(menuB,BACK);
	else
		DisableItem(menuB,BACK);
	
	/* enable/disable undo Edit menu functions */
	cutCopyClear = false;
	paste = false;
	undo = false;
	
	if ( IsDAWindow(front_window) ) {
		/* all editing is enabled for DA windows */
		cutCopyClear = true;
		paste = true;
	} 
	else 
		if ( IsAppWindow(front_window) && ( wind_type(front_window) == text )) {
			te = ((DocumentPeek) front_window)->docTE;
			/* Cut, Copy, and Clear is enabled for app. windows with selections */
			if ( (*te)->selStart < (*te)->selEnd )
				cutCopyClear = true;
			
			/* if thereÕs any text in the clipboard, paste is enabled */
			if ( GetScrap(nil, 'TEXT', &offset) )
				paste = true;			
		}
		else 
			/* enable edit functions for the list window only when in provider mode */
			if (IsAppWindow(front_window) && ( wind_type(front_window) == list ) && menuP) {
				/* is there something to undo? */
				data_edits(retrieve,&undo_flags);
				undo = undo_flags.type; 
				
				if (active_list_item)
					cutCopyClear = true;
					
				/* did we preform a previous copy or paste and is the selected item a folder */
				/* at this point active_list_item and type are already filled in */
				if ((undo_flags.type == edit_copy || undo_flags.type == edit_cut ) &&
					 active_list_item && (type[0] == 's')) 
					paste = true;
			}
		
	/*
	if ( undo ) {
		EnableItem(menuE, UNDO);
		switch (undo) {
			case edit_cut:
				SetItem(menuE,UNDO,"\pUndo Cut");
				break;
			case edit_paste:
				SetItem(menuE,UNDO,"\pUndo Paste");
				break;
			case edit_move:
				SetItem(menuE,UNDO,"\pUndo Move");
				break;
			default:
				undo = 0;
				break;
		}
	}
	*/
	
	/* undo does not work yet */
	undo = false;
	
	if (!undo) {
		DisableItem(menuE, UNDO);
		SetItem(menuE,UNDO,"\pUndo");
	}
	
	/* exceptions - can not cut or paste an item that is the result of a search */
	if ( cutCopyClear ) {
		if (owner)
			EnableItem(menuE, CUT);
		else
			DisableItem(menuE, CUT);
		EnableItem(menuE, COPY);
	} 
	else {
		DisableItem(menuE, CUT);
		DisableItem(menuE, COPY);
	}
	
	if ( paste && owner)
		EnableItem(menuE, PASTE);
	else
		DisableItem(menuE, PASTE);	
	
} /*menu_adjust*/

/*     
 *
 *  menu_do_command:
 *
 *	This is called when an item is chosen from the menu bar (after calling
 *	MenuSelect or MenuKey). It does the right thing for each command. 
 */
#pragma segment Main 
void menu_do_command(menuResult)
	long		menuResult;
{
	short		menuID, menuItem;
	short		daRefNum;
	Str255		daName;
	OSErr		saveErr;
	TEHandle	te;
	WindowPtr	window;
	Handle		aHandle;
	long		oldSize, newSize;
	long		total, contig;
	char		child_node[NODE_LENGTH];
	Boolean		rc;
	MenuHandle	window_handle;
	data_edit	undo_flags;
	
	extern Boolean	gDebug;
	
	window = FrontWindow();
	menuID = HiWord(menuResult);	/* use macros for efficiency to... */
	menuItem = LoWord(menuResult);	/* get menu item number and menu number */
	switch ( menuID ) {
		case APPLE:
			switch ( menuItem ) {
				case ABOUT:		/* bring up alert for About */
					dlog_about();
					break;
				default:			/* all non-About items in this menu are DAs et al */
					GetItem(GetMHandle(APPLE), menuItem, daName);
					daRefNum = OpenDeskAcc(daName);
					break;
			}
			break;
			
		case FILEM:
			switch ( menuItem ) {
				case CLOSE:
					DoCloseWindow(window,hide_window); 
					break;
				case SAVE_TEXT:
					cmd_generic_save(window);
					break;
				case PAGE:
					print_page_dlog();
					break;
				case PRINT:
					print_cmd();
					break;
				case HELP:
					dlog_help();
					break;
				case GETINFO:
					cmd_get_info(NULL);
					break; 
				case PROVIDER_MENU:
					cmd_get_provider();
					break;
				case PREFERENCE:
					PreferenceDialog();
					break;
				case USERSTARTUP:
					cmd_user_startup();
					break;
				case QUIT:
					Terminate();
					break;
			}
			break;
		case EDIT:					/* call SystemEdit for DA editing & MultiFinder */
			if ( !SystemEdit(menuItem-1) ) {
				switch(wind_type(window)) {
					case list:
					 	switch (menuItem) {
							case UNDO:
								data_edits(retrieve,&undo_flags);
								switch (undo_flags.type) { 
									case edit_cut:
										break;
										cmd_cut_undo();
									case edit_paste:
										cmd_paste_undo();
										break;
									case edit_move:
										cmd_reorder_undo();
										break;
								}
								break;
							case CUT:
								cmd_unlink_child();
								break;
							case COPY:
								cmd_copy_edit();
								break;
							case PASTE:
								cmd_link_child_edit();
								break;
						}
						break;
					
					case text:
						te = ((DocumentPeek) FrontWindow())->docTE;
						switch ( menuItem ) {
							case UNDO:
								break;
							case CUT:
								if ( ZeroScrap() == noErr ) {
									PurgeSpace(&total, &contig);
									if ((*te)->selEnd - (*te)->selStart + kTESlop > contig)
										AlertUser(NO_SPACE_CUT);
									else {
										TECut(te);
										if ( TEToScrap() != noErr ) {
											AlertUser(NO_CUT);
											ZeroScrap();
										}
										
									}
								}
								break;
							case COPY:
								if ( ZeroScrap() == noErr ) {
									TECopy(te);	/* after copying, export the TE scrap */
									if ( TEToScrap() != noErr ) {
										AlertUser(NO_COPY);
										ZeroScrap();
									}
								}
								break;
							case PASTE:	/* import the TE scrap before pasting */
								if ( TEFromScrap() == noErr ) {
									if ( TEGetScrapLen() + ((*te)->teLength -
										((*te)->selEnd - (*te)->selStart)) > kMaxTELength )
										AlertUser(EXCEED_PASTE);
									else {
										aHandle = (Handle) TEGetText(te);
										oldSize = GetHandleSize(aHandle);
										newSize = oldSize + TEGetScrapLen() + kTESlop;
										SetHandleSize(aHandle, newSize);
										saveErr = MemError();
										SetHandleSize(aHandle, oldSize);
										if (saveErr != noErr)
											AlertUser(NO_SPACE_PASTE);
										else {
											TEPaste(te);
											untabify(te); /* just in case there were tabs in the paste */
										}
									}
								}
								else
									AlertUser(NO_PASTE);
								break;
							/*
							case CLEAR:
								TEDelete(te);
								break;
							*/
						}
						AdjustScrollbars(window, false);
						AdjustTE(window);
					
						break;
					
				}	/* end of the window switch type  */
			} 		/* end of the if (!SystemEdit ... */
			break;
			
		case BROWSER:
			switch ( menuItem ) {
				case MAIN:
					cmd_main_menu();
					break;
				case BACK:
					cmd_back();
					break;
				case SHOW:
					rc = cmd_show(NULL);
					break;
				case OUTLINE:
					cmd_content();
					break;
				case SHOW_PATH:
					cmd_path();
					break;
				case WORD:
					cmd_select_word(false);
					break;
				case AGAIN:
					cmd_select_word(true);
					break;
				case KEYWORD:
					cmd_find(); 
					break;
				default:
					window_handle = GetMHandle(BROWSER);
				 	cmd_show_window(menuItem - WINDOW_LIST - 1);
			}
			break;
			
		case TOYS:
			switch ( menuItem ) {
				case DEBUG:
					gDebug = !(gDebug);
					CheckItem( GetMHandle(TOYS), DEBUG, gDebug );
					break;
				case CONFIGURE:
					cmd_configure();
					break;
				case SEND:
					cmd_send();
					break;
			}
			break;
								
		case SPECIAL:
			switch ( menuItem ) {
				case DIRECTORY:
					cmd_phone(NULL);
					break;
				case WORLDWIDE:
					cmd_get_other_servers();
					break;
#ifdef GIFSTUFF
				case GIFFILEREAD:
					cmd_read_gif_file(true);
					break;
#endif
			}
			break;
			
		case PROVIDER:
			switch ( menuItem ) {
				case CLOSE_SESSION:
					cmd_close_provider();
					break;
				case DEFINE_MENU_ITEM:
					cmd_define_item();
					break;
				case CLEAR_DOCUMENT:
					/* change banner */
					SetWTitle( gTextWindow,"\pUntitled" );	
					text_show_new_text(gTextWindow);
					break;
				case MODIFY_ITEM:
					cmd_modify_item();
					break;
				case REMOVE_ITEM:
					cmd_remove();
					break;
				case OPEN_DOCUMENT:
					cmd_open_document();
					break;
				case SEND_DOCUMENT:
					child_node[0] = '\0';
					cmd_publish_document(child_node);
					break;
				case PROVIDER_OPTIONS:
					cmd_provider_options();
					break;
				case SOURCE_INFO:
					cmd_source_info();
					break;
			}
			break;
			
	}
									
	HiliteMenu(0);					/* unhighlight what MenuSelect (or MenuKey) hilited */
} /*menu_do_command*/

/*     
 *
 *  menu_add:
 *
 *	This function adds the menu resource provided thru the calling argument
 *	An example of this is adding the provider menu.
 *
 */
void
menu_add( menuRes )
int	menuRes;
{
	MenuHandle		whatMenu;
	
	whatMenu = GetMenu( menuRes );
	
	/* insert the menu before the provider menu (if it exists), else at the end of the list */
	InsertMenu( whatMenu, PROVIDER );
	
	DrawMenuBar();
}	/* menu_add */

/*     
 *
 *  menu_delete:
 *
 *	This function deletes the menu resource provided thru the calling argument
 *	An example of this is adding the provider menu.
 *
 */
void
menu_delete( menuRes )
int	menuRes;
{
	MenuHandle	menuHandle;
	
	DeleteMenu( menuRes );
	menuHandle = GetMHandle(menuRes);
	ReleaseResource((Handle)menuHandle);
	DrawMenuBar();
}	/* menu_delete */

/*     
 *
 *  menu_check:
 *
 *	This function check to see if we have the menu already installed.
 */
Boolean
menu_check( menuRes )
int menuRes;
{

	MenuHandle	menuHandle;
	
	menuHandle = GetMHandle(menuRes);
	
	return (menuHandle ? true : false);
}

/*     
 *
 *  menu_show_popup:
 *
 *	Display a pop-up menu, used for the history function.
 */
menu_show_popup( window )
WindowPtr	window;
{
	MenuHandle		whatMenu;
	long			menuResult;
	Point			top_left;
	Point			bot_right;
	short			menuItem, menuID;
	short			num_items, ctr;
	MenuHandle		menuPopUp;
	int				stack_items;
	int				rc;
	Str255			meta;
	Str255			title;

	whatMenu = GetMenu( POP_UP_MENU );
	
	if (menu_check(POP_UP_MENU) == false)
		InsertMenu(whatMenu, -1);    /* -1 means hierarchical menu */
		
	/* get local coordinates of the window */
	SetPt(&top_left,window->portRect.left,window->portRect.top);
	SetPt(&bot_right,window->portRect.right,window->portRect.bottom);

	/* subtract the banner */
	top_left.v =- (kScrollbarWidth + 1);
	
	/* find start of title in window */
	top_left.h = top_left.h + ((bot_right.h - top_left.h) / 2) - (((WindowPeek) window) -> titleWidth) / 2;

	LocalToGlobal(&top_left);
	LocalToGlobal(&bot_right);

	/* build menu */
	stack_items = util_get_stack_count(0);
	menuPopUp = GetMHandle(POP_UP_MENU);
	for (ctr=stack_items; ctr > 0; ctr--) {
		rc = util_get_stack_item(ctr,meta,title);
		if (rc) {
			AppendMenu(menuPopUp,"\p ");
			c2pstr(title);
			SetItem(menuPopUp,CountMItems(menuPopUp),title);
		}
	}
	
	/* highlight the last item in the list as a default */
	menuResult = PopUpMenuSelect(whatMenu,top_left.v,top_left.h,1);
	menuID = HiWord(menuResult);
	menuItem = LoWord(menuResult);
	
	/* bring up the requested window */
	/* don't do anything if the user selected the first item, since */
	/* we are already here */
	if (menuID > 0 && menuItem > 1) {
		/* since the menuitem numbers are in reverse order than the linked list */
		/* map the menu item to the right stack node item */
		menuItem = CountMItems(menuPopUp) - menuItem + 1;
		rc = util_get_stack_item(menuItem,meta,title);
		if (rc) {
			rc = cmd_new_display( meta, command, list );
			
			/* think of this as a return to previous menu, decrement the stack */
			for (ctr = 1, menuItem = LoWord(menuResult); ctr < menuItem; ctr++)
				rc = util_pop_stack(meta);
		}
	}
	
	/* cleanup menu list for next call */
	num_items = CountMItems(menuPopUp);
	for (ctr = num_items; ctr > 0; ctr--)
		DelMenuItem(menuPopUp,ctr);

}