/* written by Joe Freeman from Next Computer Inc
 *	Version 2
 *	As with all my code, use at your own risk.
 *
 * Notes:
 *	1)	This objects is very similar to the text object used by Edit
 *		and the one used by Mail, supporting both graphics and attach
 *		
 *		Mail supports embeded graphics in a different format from Edit
 *		with Edit adding height and width parameters to the RTF.
 *
 *		Mail supports attachments using the "attachment" command
 *		that is not supported in edit in Edit.
 *
 *		This program will not interchange attachments with Mail 
 *		because using the "attachment" command in this objec will let
 *		attachments be copied out of this object and into mail but then
 *		no attachments can be pasted or loaded back in from an rtf 
 *		stream.  The use of "attach" means this object works fine but
 *		all attachment interchange with mail is lost.
 *
 *	2)	This object makes all graphics (tiff and eps) embeded graphics
 *		similar to edit.
 *
 *		It also supports other files as attachments, storing just the 
 *		pointers to the files 
 *
 *
 * MMText.[hm]
 *	Multi media text object!
 *
 *	1)	Handles embeded graphics in rtf
 *	2)	Saves and loads from rtfd files
 *	3)	Suports "drag and drop" of tiff and eps files
 *	4)	Supports copy and paste of rtf with embedded graphics
 *	5)	Has methods for open: and saveAs: to simplify programming
 *	6)	Handles attached documents via pointers
 *
 */
 
/* Generated by Interface Builder */

#import "MMText.h"
#import "MMGraphicCell.h"
#import "MMFileCell.h"

#import <appkit/Application.h>  /* ask for app speaker port */
#import <appkit/Cell.h>			  /* where we put our view */
#import <appkit/NXImage.h>		  /* to load the cell */
#import <appkit/Listener.h>
#import <appkit/OpenPanel.h>
#import <appkit/nextstd.h>
#import <appkit/Pasteboard.h>
#import <appkit/publicWraps.h>	/* NXConvertWinNumToGlobal ... */
#import <appkit/SavePanel.h>
#import <appkit/Speaker.h>		/* set send port */

#import <streams/streams.h>

#import	<stdio.h> 

@implementation MMText:Text

static char rcsstring[] = 
	"@(#)Object:MMText.m Developer:Joe Freeman Version:2 July, 1991";

+ initialize
{
	[super initialize];
	[self registerDirective:"NeXTGraphic" forClass: [MMGraphicCell class]];
	[self registerDirective:"attach"  forClass: [MMFileCell class]];
	[self registerDirective:"attachment"  forClass: [MMFileCell class]];
	return self;
}

- initFrame:(NXRect *)r
{
	self = [super initFrame:r];
	[self notifyAncestorWhenFrameChanged:YES];
	[self setMonoFont:NO];
	[self setVertResizable:YES];
	[self setHorizResizable:NO];
	[self setSel:0:0];
	[self setOpaque:YES];
	copyGraphics = YES;
	copyAttachments = NO;
	{ NXSize aSize = {1.0E38,1.0E38};
	  [self setMinSize:&r->size];
	  [self setMaxSize:&aSize];
  }
	return self;
}

- free
{	
	/* un register this window */
	unsigned int windowNum;
	id speaker = [NXApp appSpeaker];

	if (privateListener) {
		[speaker setSendPort:
				NXPortFromName(NX_WORKSPACEREQUEST, NULL)];
		NXConvertWinNumToGlobal([window windowNum], &windowNum);
		[speaker unregisterWindow:windowNum];
		[privateListener free];
    }

	return self; 
}



/*==================================================
 *
 *
 *==================================================*/
 
- (int)iconEntered:(int)windowNum at:(double)x :(double)y
    iconWindow:(int)iconWindowNum iconX:(double)iconX iconY:(double)iconY
    iconWidth:(double)iconWidth iconHeight:(double)iconHeight
    pathList:(char *)pathList
/*
 * Called whenever an icon is dragged from the Workspace over the document
 * window.  At this point, all that is done is to salt away the list of files
 * represented by the icon.  All the real work is done in iconReleasedAt::ok:.
 */
{
#ifdef DEBUG
	fprintf(stderr,"icon Entered\n");
#endif DEBUG
    if (!iconPathList || strcmp(iconPathList, pathList)) {
	if (iconPathList) NX_FREE(iconPathList);
	NX_MALLOC(iconPathList,char, strlen(pathList)+1);
	//iconPathList = NXCopyStringBufferFromZone(pathList, [self zone]);
	strcpy(iconPathList, pathList);
    }
    return 0;
}

- (int)iconReleasedAt:(double)x :(double)y ok:(int *)flag
{
    /* we are blocked by the workspace if we try and get the tiff for a 
     * non graphical file so just return ok and do the stuff after ws is ready
     */
	if (![self isEditable]) {
    	*flag = NO;
	} else {
		*flag = YES;
		[self  perform:@selector(delayIconReleasedAt:) 
	     with:self  
	     afterDelay:5
   	  cancelPrevious:YES];
	}
	return 0;
}

- delayIconReleasedAt:sender
/*
 *	This is where the real work is done.
 *	look for eps and tiff files and pass them off to the MMGraphicCell
 *	all others should be passed to MMFileCell
 *	Insert each one as we find it
 *
 */
{
    /* these are vars that used to come in from iconReleasedAt::ok: */
    int dummy,*flag;
    
    NXPoint p;
    char *file,  *tab, *extension;
    id	newCell;
    int foundOne ;

    flag = &dummy;	/* another dummy statement */
    
    foundOne = NO;
    /* should make sure it is in this text object */
    [window convertScreenToBase:&p];
    [self convertPoint:&p fromView:nil];
#ifdef DEBUG
    fprintf(stderr,"user dragged in files %s\n",iconPathList);
#endif DEBUG
    
	file = iconPathList;
	while (file) {
	    tab = strchr(file, '\t');
	    if (tab) *tab = '\0';
	    extension = strrchr(file, '.');
	    if (extension &&
		( !strcmp(extension, ".ps")  || !strcmp(extension, ".eps") ||
		  !strcmp(extension,".tiff") || !strcmp(extension,".tif")  )) {
		    
		    newCell = 
		    	[[MMGraphicCell alloc] initFromFile: file copy:copyGraphics];
		    [self replaceSelWithCell:newCell];
		    foundOne = YES;
		    
	    } else {
		    newCell = [[MMFileCell alloc] 
		    		initFromFile: file copy:copyAttachments];
		    [self replaceSelWithCell:newCell];
		    foundOne = YES;
	    }
	    	
	    file = tab ? ++tab : NULL;
	}
    
    *flag = foundOne;
    return 0;
}


/*==================================================
 *
 *
 *==================================================*/
 
- write:(NXTypedStream *)stream
{
    [super write:stream];
    NXWriteTypes(stream,"**ii",
    		&iconPathList,&rtfdName,&copyGraphics,&copyAttachments);
    NXWriteObjectReference(stream,privateListener);
    return self;
}

- read:(NXTypedStream *)stream
{
    [super read:stream];
    NXReadTypes(stream,"**ii",
    		&iconPathList,&rtfdName,&copyGraphics,&copyAttachments);
    privateListener = NXReadObject(stream);
    return self;
}


/*==================================================
 *
 *
 *==================================================*/
 
- becomeFirstResponder
{
	unsigned int windowNum;
	id speaker;

	if (!privateListener ) {
#ifdef DEBUG
		fprintf(stderr,"registering private port\n");
#endif DEBUG
		speaker = [NXApp appSpeaker];
		privateListener = [Listener new];
		[privateListener setDelegate:self];
		[privateListener usePrivatePort];
		[privateListener addPort];
		NXConvertWinNumToGlobal([window windowNum], &windowNum);
		[speaker setSendPort:
				NXPortFromName(NX_WORKSPACEREQUEST, NULL)];
		[speaker registerWindow:windowNum 
			 toPort:[privateListener listenPort]];
	}
	[super becomeFirstResponder];
	return self;
}

- (const char *)filename { return (const char *)rtfdName; }
- (BOOL)copyGraphics	 { return copyGraphics; }
- (BOOL)copyAttachments	 { return copyAttachments; }
- setCopyGraphics:sender { copyGraphics = YES; return self; }
- setLinkGraphics:sender { copyGraphics = NO; return self; }
- setCopyAttachments:sender { copyAttachments = YES; return self; }
- setLinkAttachments:sender { copyAttachments = NO; return self; }

/*==================================================
 *
 *	overriden to set stream instance variable 
 *
 *==================================================*/


- paste:sender
{
	id	pb;
	char *const *types;
	char *data;
	int length;
	NXStream *stream;
	id newCell;

	/* for debugging attachments 
   pb = [Pasteboard new];
	types = [pb types];
	while (*types ){
		fprintf(stderr,"pboard %s\n",*types);
		[pb readType:*types data:&data length:&length];
		types++;
	}
	return self;
    */

	if (![super paste:sender]){
    	/* was no ascii or rtf sitting there so lets look for eps and tiff */
		pb = [Pasteboard new];
		types = [pb types];
		while (*types ){
			if (	!strcmp(*types, NXPostScriptPboardType) ||
				 !strcmp(*types, NXTIFFPboardType)) {
					 [pb readType:*types data:&data length:&length];
					 stream = NXOpenMemory(data, length, NX_READONLY);
					 newCell = 
						[[MMGraphicCell alloc] initFromStream: stream copy:YES];
					 NXCloseMemory(stream, NX_SAVEBUFFER);
					 [self replaceSelWithCell:newCell];
					 /* this has to be here otherwise no file name so can't
					  * paste rtf... need pointers for graphics 
					  */
					 [self save:self];
					 break;
				 }
			types++;
		}
	}
	return self;
}


/*==================================================
 *
 *	This is to support save in palette
 *	we want to test graphics being written to streams
 *
 *==================================================*/

- openFileName:(char *)aFile
{
    NXStream *aStream;
    char fileName[MAXPATHLEN+1];

    fprintf(stderr,"opening file %s\n",aFile);
    if (!rtfdName || strcmp(aFile,rtfdName)){ // NULL or current file
		 if (rtfdName) free(rtfdName);
		 rtfdName = malloc((strlen(aFile)+1) * sizeof(char));
		 strcpy(rtfdName,aFile);
    }

    sprintf(fileName,"%s/TXT.rtf",aFile);
    aStream = NXMapFile(fileName, NX_READONLY);

    [self readRichText:aStream];

    //NXCloseMemory(aStream, NX_FREEBUFFER);
    NXClose(aStream);

    return self;
}


- open:sender
{
	id openPanel = [OpenPanel new];
	const char * const  fileTypes[2] = {"rtfd",NULL};
	const char * const * filenames;
	char fullname[MAXPATHLEN+1];

	[openPanel allowMultipleFiles:YES];
	[openPanel setDelegate:self];
	if ([openPanel runModalForTypes:fileTypes]){
		filenames = [openPanel filenames];
		while (filenames && *filenames){
			strcpy(fullname,[openPanel directory]);
			strcat(fullname,"/");
			strcat(fullname,*filenames);
			[self openFileName:fullname];
			filenames++;
		}
	}
	return self;
}


- saveFileName:(char *)aFile
{
	NXStream *aStream;
	char fileName[MAXPATHLEN+1];
	
	
	if (!rtfdName || strcmp(aFile,rtfdName)){
		if (rtfdName) free(rtfdName);
		rtfdName = malloc((strlen(aFile)+1) * sizeof(char));
		strcpy(rtfdName,aFile);
	}
	
	/* make the directory for aFile */
	mkdir(aFile, 0755);
	
	sprintf(fileName,"%s/TXT.rtf",aFile);
	aStream = NXOpenMemory(NULL,0, NX_WRITEONLY);
	
	[self writeRichText:aStream];
	
	NXSaveToFile(aStream, fileName);
	NXCloseMemory(aStream, NX_FREEBUFFER);
	
	return self;
}


- saveAs:sender
{
	id savePanel;

	savePanel = [SavePanel new];
	[savePanel setRequiredFileType:"rtfd"];
	if ([savePanel runModal]) {
		[self saveFileName:(char *)[savePanel filename]];
	}
	return self;
}

- save:sender
{
	if (rtfdName && *rtfdName)
	  [self saveFileName:rtfdName];
	else 
	  [self saveAs:sender];
	return self;
}


@end
