#import "Document.h"
#import "TextController.h"
#import <appkit/appkit.h>

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

@implementation Document

// initialize a new document
- init
{
	[super init];
	[NXApp loadNibSection:"Document.nib"
		owner:self withNames:NO];
	// make the document the delegate of the text
	// every time a key is pressed, the delegate
	// of the text object will receive a
	// textDidGetKeys: isEmpty: message
	// this allows us to update the window from
	// a clean state to a dirty state
	[window setDelegate:self];
	// make the document the delegate of the window
	// allows us to determine the current document
	// in displaySavePanel:
	[theText setDelegate:self];
	return self;
}

// load a document from a file
- (BOOL)initDocumentFromFile:
	(const char *)fullPathName
{
	NXStream *stream;
    
	// obtain a stream for an existing file
	printf("in initDocumentFromFile:\n");
	if (stream =
		NXMapFile(fullPathName, NX_READONLY))
		{
		[self init];
		// read text from stream
		[theText readText:stream];
		//update the window's title
		[window setTitle:fullPathName];
		// display the document
		[self showDocument];
		// free memory associated with stream
		NXCloseMemory(stream, NX_FREEBUFFER);
		return YES;
		}
	else
		{
		[self showError:"Can't open file"];
		return NO;
		}
}

// display the document -- one improvement
// is to stagger the window rather than display
// each one on top of each other
- showDocument
{
	// set the text selection to 1st char
	[theText setSel:0 :0];
	[window setTitle:"Untitled"];
	[window makeKeyAndOrderFront:self];
	return self;
}

- setFilename:(const char *)fullPathName
{
	filename = fullPathName;
	[window setTitle:fullPathName];
	return self;
}

- (const char *)filename
{
	return filename;
}

// write the document to file
- saveDocumentToFile:(const char*)fullPathName
{
	int fd;
	NXStream *stream = NULL;

	// obtain a file descriptor first
	if ((fd = open (fullPathName,
		O_WRONLY|O_CREAT|O_TRUNC, 0644)) != -1)
		{
		// get a stream
		stream = NXOpenFile(fd, NX_WRITEONLY);
		// write text to stream
		[theText writeText:stream];
		// close stream to save stream to file
		NXClose(stream);
		// Release file descriptor
		close(fd);
		// set the name of the document
		[self setFilename:fullPathName];
		// update window to clean state
		[window setDocEdited:NO];
		}
	else
		[self showError:"Cant Write file"];
	return self;
}

// use an Alert panel to display error messages
- showError:(const char *)errorMessage
{
	NXRunAlertPanel(NULL,
		errorMessage, "OK", NULL, NULL);
	return self;
}

// called every time a key is pressed
// if the window is dirty, we don't do
// anything -- if it's not dirty, we set
// it to dirty
- textDidGetKeys:sender isEmpty:(BOOL)flag
{
	// if window is not edited, then set
	// it to edited
	if ([window isDocEdited] == NO)
		[window setDocEdited:YES];
	return self;
}

- free
{
	// free the window since it's
	// dynamically allocated
	[window free];
	// free everything allocated
	// by the superclasses
	return [super free];
}

// since the document object is the delegate of
// the window, the window will, before closing,
// send a windowWillClose: message to
// the document
- windowWillClose:sender
{
	int result;
	id savePanel = [textController savePanel];
	
	// display alert panel only if window
	// is dirty
	if ([window isDocEdited])
		{
		result = NXRunAlertPanel
			([NXApp appName],
			"Unsaved changes. Close Anyway?\n",
			"Save",
			"Close anyway",
			"Cancel");

		switch(result)
			{
			case SAVE:
				[self saveDocumentToFile:
					[savePanel filename]];
				break;
			case CLOSE:
				// delay freeing the object until
				// we are done with the current
				// event (close:)
				return [NXApp delayedFree:self];
			case CANCEL:
				return nil;
			}
		}
	return self;
}

@end