
/* Generated by Interface Builder */

#import "Controller.h"
#import "NewWindow.h"
#import <streams/streams.h>
#import <objc/typedstream.h>
#import <objc/NXStringTable.h>
#import <strings.h>

#define SAVE NX_ALERTDEFAULT
#define CLOSE NX_ALERTALTERNATE
#define CANCEL NX_ALERTOTHER


@implementation Controller

/*=================
 * load InfoPanel
 *=================*/

- infoPanel:sender
{
    if (infoPanel == nil) {
		[NXApp loadNibSection:"InfoPanel.nib" owner:self];
    }
    [infoPanel orderFront:sender];
    return self;
}

/*==================================================
 * create a newWindow, or better said a new insert
 *==================================================*/

- newWindow:sender
{	
	id win;
	
	if ([NXApp loadNibSection:"NewWindow.nib" owner:self] == nil) {
		return nil;
	}
	
	if ([newInsert setUp]) {
		win = [newInsert window];
		if (win) {
			NXRect frame;
			char buf[256];
			[win getFrame: &frame];
			NX_X(&frame) += offset;
			NX_Y(&frame) -= offset;
			if ((offset += 24.0) > 100.0) {
				offset = 0.0;
			}
			sprintf(buf, [win title], ++calcNum);
			[win setTitle: buf];
			[win placeWindowAndDisplay: &frame];
			[win makeKeyAndOrderFront:nil];

			return newInsert;
		}
  }
  return nil;
}

/*============================
 * manages the service stuff
 *============================*/
 
// This probably should be broken up into two funcs. One for an RTF message 
// and one for an ASCII message.  Oh well, it works...

- servicesMessage:(id)pasteboard
    userData:(const char *)sortArgs
    error:(char **)errorMessage
{
    int length, currentType;
    const char *data;
    const char *const *ptypes;
	  NXStream	*stream;
    
    id contf = [newInsert contentfield];   
    ptypes=[pasteboard types];
    
    //Look for RTF first...
    for (currentType=0; ptypes[currentType] ; currentType++ ){
		  if (!strcmp(ptypes[currentType],NXRTFPboardType)){
			  [pasteboard readType:ptypes[currentType] data:&data length:&length];
			  stream = NXOpenMemory(data, length, NX_READONLY);
			  [[contf docView] readRichText:stream];
			  NXCloseMemory(stream, NX_FREEBUFFER);
			  return self;
		  }
	  }
   	for (currentType=0; ptypes[currentType] ; currentType++ ){
		  if (!strcmp(ptypes[currentType],NXAsciiPboardType))  {
			  [pasteboard readType:ptypes[currentType] data:&data length:&length];
			  stream = NXOpenMemory(data, length, NX_READONLY);
			  [[contf docView] readText:stream];
			  NXCloseMemory(stream, NX_FREEBUFFER);
			  return self;
			
		  }
	  }
	  return self;	//should never be reached....
}

/*==============================
 * printing and fieldtext copy
 *==============================*/
 
- doPrint:sender
{
	id insert = [[NXApp mainWindow] delegate];
	id gr = [insert group];
	[gr printPSCode:self];
  return self;
}

- copyText:sender
{	
  NXStream	*stream;
	char			*buffer;
	int			buttontag, length, maxlength;
	id outp;	// var to hold the main windows outputtitlefield
	
	// The next statement "id insert = [[NXApp mainWindow] delegate];"
	// is needed so we can access the actual (main) window's outlets, 
	// otherwise if we would use "newInsert" the last created insert window
	// (which might not be the actual (main) window would receive the copied
	// string. Why? - The reason is that the "newInsert" instance var will be 
	// overwritten each time we create a new insert window and so doesn't
	// remember the earlier created ones. Thus if we would use it, we were
	// only able to copy to the latest created window in the window list, even
	// if some earlier one's were on top of it.
	
	id insert = [[NXApp mainWindow] delegate];
	outp = [insert outputtitlefield];
	buttontag = [[sender selectedCell] tag];
	
	stream = NXOpenMemory(NULL, 0, NX_WRITEONLY);
	   
	if (buttontag == 0)
	    [[inputTitleField docView] writeRichText:stream];
	else
	    [[outp docView] writeRichText:stream];
		
	NXGetMemoryBuffer(stream, &buffer, &length, &maxlength);
	NXCloseMemory(stream, NX_SAVEBUFFER);
	stream = NXOpenMemory(buffer, length, NX_READONLY);

	// access the main windows outputtitlefield, see the above comments
	if (buttontag == 0)
	    [[outp docView] readRichText:stream];
	else
	    [[inputTitleField docView] readRichText:stream];
		
	NXCloseMemory(stream, NX_FREEBUFFER);

  return self;
}


/*========================
 * load/save panel stuff
 *========================*/

- showError: (const char *)errorMessage
{
  NXRunAlertPanel(NULL, errorMessage,
  		  [stringSet valueForStringKey:"OK"], NULL, NULL);
  return self;
}


- openRequest:sender
{
	const char *const types[2] = {[stringSet valueForStringKey:"extension"],
    				  NULL};

	if ([ [OpenPanel new] runModalForTypes:types]) {
		if ([self newWindow:self]) {
			[newInsert loadFile:[ [OpenPanel new]
																		filename] ];
		}
	}
	return self;
}


- (int) countEditedWindows
{
	id winList;
	int i;
	int count = 0;
	
	winList = [NXApp windowList];
	for (i=0; i<[winList count]; i++) {
		if ([ [winList objectAt: i] isDocEdited])
			count++;
	}
	return count;
}


- saveAll:sender
{
	id winList;
	int i;
	
	winList = [NXApp windowList];
	for (i=0; i<[winList count]; i++) {
		id win = [winList objectAt: i];
		id delegate = [win delegate];
		
		if ([delegate isKindOf:[NewWindow class]]) {
			[win makeKeyAndOrderFront:nil];
			[delegate save:win];
		}
	}
	return self;
}


- (BOOL)menuActive:menuCell
{
	BOOL shouldBeEnabled;

	shouldBeEnabled = [[[NXApp mainWindow] delegate]
									 isKindOf:[NewWindow class]];

	if([menuCell isEnabled] != shouldBeEnabled) {
	
		// Menu cell is either enabled and shouldn't be,
		// or it is not enabled and should be.
		// In any event, set the correct state.

		[menuCell setEnabled:shouldBeEnabled];
		return YES;						/* redisplay */
	}
	return NO;							/* no change */
}

@end

@implementation Controller(ApplicationDelegate)

/*=============================
 * Application delegate stuff
 *=============================*/
 
- appDidInit:sender
{
	id docMenu = [insertSubmenuCell target];
	[saveMenuCell setUpdateAction: @selector(menuActive:) forMenu: docMenu];
	[saveAsMenuCell setUpdateAction: @selector(menuActive:) forMenu: docMenu];
	[saveAllMenuCell setUpdateAction: @selector(menuActive:) forMenu: docMenu];
	[[NXApp appListener] setServicesDelegate:self];
	opanel = [OpenPanel new];
	[opanel allowMultipleFiles:YES];
	
  /* if you always want an empty insertwindow at startup, 
     un-comment the following line */

	// [self newWindow:self];
	
	[NXApp setAutoupdate: YES];
  return self;    
}


// appAcceptsAnotherFile: is an application delegate method which 
// returns whether it is OK for the application to try to open more files
// with the "app:openFile:type:" method.
 
- (BOOL) appAcceptsAnotherFile:sender
{
  return (YES);
}


// app:openFile:type: is called to open the specified file. It is called
// by the Application object in response to open requests from the Workspace.

- (int) app:sender openFile:(const char *)filename 
        type:(const char *)aType
{
	if ([self newWindow:self]) {
		if ([newInsert loadFile:filename]) {
			return YES;
		}
	}
	return NO;
}


// appWillTerminate: is called by the Application object when the 'quit'  
// button is pressed. It checks for edited Windows which haven't be saved.
 
- appWillTerminate:sender
{
	if ([self countEditedWindows]>0) {
		int q = NXRunAlertPanel("Quit",
						"There are edited windows.",
						"Review Unsaved", 
						"Quit Anyway", "Cancel");
		if (q==1) {									/* Review */
			int i;
			id winList;

			winList = [NXApp windowList];
			for(i=0; i<[winList count]; i++){
				id win = [winList objectAt: i];

				if([ [win delegate] 
						 isKindOf:[NewWindow class] ]){
						 [win performClose:nil];
				}
			}
			return self;
		}
		if (q==-1) {							/* cancel */
			return nil;
		}
	}
	return self;								/* quit */
}

@end
