#import "BriefDoc.h"
#import "Briefcase.h"
#import "Utility.h"

#import <appkit/ScrollView.h>
#import <appkit/Text.h>
#import <appkit/Window.h>

@implementation BriefDoc: MultDoc

/* Canon Information Systems is not responsible for anything anyone does with this   */
/* code, nor are they responsible for the correctness of this code.  Basically, this */
/* has very little to do with the company I work for, and you can't blame them.      */

/* This file is best read in a window as wide as this comment, and with tab settings */
/* of 4 spaces and indent setting of 4 spaces (at least, that's what I use).		 */

/* You are welcome to do as you would with this file under the following conditions. */
/* First, I accept no blame for anything that goes wrong no matter how you use it,   */
/* no matter how catastrophic, not even if it stems from a bug in my code.			 */
/* Second, please keep my notices on it when/if you distribute it.					 */
/* Third, if you discover any bugs or have any comments, PLEASE TELL ME!  Code won't */
/* get better without people picking it apart and giving the writer feedback.        */
/* Fourth, if you modify it, please keep a notice that your version is based on mine */
/* in the source files (and keep the notice that mine is based on four other pieces  */
/* of code :<).  Thanks, and have fun.  - Subrata Sircar, ssircar@canon.com			 */

/* Version 0.9b		Apr-19-92		First Public Release	*/
/* Version 0.95		Apr-29-92		Bug Fixes				*/
/* Version 1.0b		Aug-08-92		Minor Bug Fixes			*/
/* Version 1.1b		Jan-20-93		Drag And Drop			*/

/* New creation methods */

+ initialize
/* Class variable initialization.  DO NOT call from subclasses. */
{
    if (self == [BriefDoc class]) {
		[self setVersion:100];
		[self setExtension:LocalString("bc")];
		[self setDefault:LocalString("Untitled%d")];
	}
	return self;
}

+ newFromFile:(const char *)file
{
    NXStream *stream;
    id text;
	int count;
	char tempBuf[8192], fileBuf[16384], *tempPtr, *lastPtr;
	
    stream = NXMapFile(file,NX_READONLY);
    if (stream) {
    	self = [[self class] new];
		text = [view docView];
		[window disableDisplay];
		[text readText:stream];
		[text selectAll:self];
		count = [text textLength];
		[text getSubstring:tempBuf start:0 length:count];
		tempPtr = lastPtr = tempBuf;
		*fileBuf = '\0';
		while (tempPtr = index(tempPtr,'/')) {
			if (*(++tempPtr) == '*') {
				lastPtr = ++tempPtr;
				tempPtr = index(tempPtr,'*');
				count = (int)(tempPtr-lastPtr);
				strncat(fileBuf,lastPtr,count);
				strcat(fileBuf,"\n");
				tempPtr += 2;
			}
    	}
		[text selectAll:self];
		[text replaceSel:fileBuf];
		[text sizeToFit];
		[self setName:file];
		NXCloseMemory(stream,NX_FREEBUFFER);
		[self setSavedDocument:YES];
		[self setEmpty:NO];
		[window reenableDisplay];
		[window display];
		[window makeKeyAndOrderFront:self];
		return self;
    } else {
		Notify(LocalString("BriefDoc: can't open file"),file);
		return nil;
    }
}

- setUpNib
{
	LoadLocalNib(LocalString("BriefDoc.nib"),self,NO,MyZone);
    [[view docView] setDelegate:self];
    [window makeFirstResponder:[view docView]];
	return self;
}

- instanceAwake
{
	[super instanceAwake];
	[window registerForDraggedTypes:&NXFilenamePboardType count:1];
	[window registerForDraggedTypes:&NXAsciiPboardType count:1];
	[window makeKeyAndOrderFront:self];
	return self;
}

- addFiles:(char *)fileList
{
	int length = 0;
	
	id text = [view docView];
	length = [text textLength];
	[text setSel:length :length];
	[text replaceSel:fileList];
	[[text window] display];
/* hack to keep status correct - text object doesn't tell me if this happens */
	if (fileList && *fileList) {
		[self dirty:YES];
		[self setEmpty:NO];
	}
	return self;
}

/* Methods related to naming/saving this document. */

- (const char *)_cname
/*
 * Returns a fully specified file name with ".c" extension.
 */
{
    char *ext;
    static char textnamebuf[MAXPATHLEN+1];

    sprintf(textnamebuf,[self fileName]);
    ext = rindex(textnamebuf,'.');
    *(ext++) = '.';
    *(ext++) = 'c';
    *ext = '\0'; 
    return textnamebuf;
}

- (const char *)_execname
/*
 * Returns a fully specified file name with no extension.
 */
{
    char *ext;
    static char execnamebuf[MAXPATHLEN+1];

    sprintf(execnamebuf,[self fileName]);
    ext = rindex(execnamebuf,'.');
    *ext = '\0'; 
    return execnamebuf;
}

- save
{	
    NXStream *ts = NULL;
    int fd = 0;
    
    fd = open([self fileName], O_CREAT | O_WRONLY | O_TRUNC, 0644);
    ts = NXOpenFile(fd, NX_WRITEONLY);
    if (ts) {
		id text = [view docView];
		int count = [text textLength];
		char tempBuf[count + 8192];
		char fileBuf[count + 8192];
		char quoteBuf[3];
		char *tempPtr, *lastPtr;
		const char *fn = [self fileName], *en = [self _execname], *cn = [self _cname];
		char quote = '"';

		sprintf(quoteBuf,"%c",quote);
		[window disableDisplay];
		[text selectAll:self];
		[text getSubstring:tempBuf start:0 length:count];
		tempPtr = lastPtr = tempBuf;
		*fileBuf = '\0';
		while (tempPtr = index(tempPtr,'\n')) {
			count = (int)(tempPtr-lastPtr);
			strcat(fileBuf,"/*");
			strncat(fileBuf,lastPtr,count);
			strcat(fileBuf,"*/\n");
			tempPtr++;
			lastPtr=tempPtr;
    	}
		tempPtr = lastPtr = tempBuf;
		strcat(fileBuf,"#include <stdlib.h>\n\n");
		strcat(fileBuf,"main()\n{\nsystem(");
		strcat(fileBuf,quoteBuf);
		strcat(fileBuf,"exec open ");
		while (tempPtr = index(tempPtr,'\n')) {
			count = (int)(tempPtr-lastPtr);
			strncat(fileBuf,lastPtr,count);
			strcat(fileBuf," ");
			tempPtr++;
			lastPtr=tempPtr;
    	}
		tempPtr = rindex(fileBuf,' ');
		*tempPtr = '\0';
		strcat(fileBuf,quoteBuf);
		strcat(fileBuf,");\n}\n");
		[text replaceSel:fileBuf];
		[text writeText:ts];
		NXFlush(ts);
		NXClose(ts);
		[text selectAll:self];
		[text replaceSel:tempBuf];
		*tempBuf = '\0';
		sprintf(tempBuf,"mv %s %s",fn,cn);
		system(tempBuf);
		*tempBuf = '\0';
		sprintf(tempBuf,"cc -O -o %s %s",en,cn);
		system(tempBuf);
		*tempBuf = '\0';
		sprintf(tempBuf,"strip %s",en);
		system(tempBuf);
		*tempBuf = '\0';
		sprintf(tempBuf,"mv %s %s",cn,fn);
		system(tempBuf);
		[window reenableDisplay];
		[self dirty:NO];
		[self setSavedDocument:YES];
    } else Notify(LocalString("BriefDoc: save - Unable to create file "),[self fileName]);
    close(fd);
    return self;
}

/* Text Delegate methods */

- textDidGetKeys:sender isEmpty:(BOOL)flag
{
	[self dirty:YES];
	[self setEmpty:flag];
	return self;
}

// IconDragging Stuff, oh boy, oh boy!
static char **filePath = NULL;
static int files = 0;
- _resetForDrag
{
	dragOK = NO;
	if (filePath) {
		freeList(filePath);
		filePath = NULL;
		files = 0;
	}
	return self;
}

- (NXDragOperation)draggingEntered:(id <NXDraggingInfo>)sender
{
	id pboard = [Pasteboard newByFilteringTypesInPasteboard:[sender draggingPasteboard]];
#ifdef DEBUG
	printf("In Method draggingEntered:\n");
#endif
	[self _resetForDrag];
	if ([pboard findAvailableTypeFrom:&NXFilenamePboardType num:1] ||
		[pboard findAvailableTypeFrom:&NXAsciiPboardType num:1]) dragOK = YES;

	if (dragOK && ([sender draggingSourceOperationMask] & NX_DragOperationCopy) && ([sender draggingSource] != self)) {
		return NX_DragOperationCopy;
    } else dragOK = NO;
	return NX_DragOperationNone;
}

- (NXDragOperation)draggingUpdated:(id <NXDraggingInfo>)sender
{
#ifdef DEBUG
	printf("In Method draggingUpdated: - dragOK = %i\n",dragOK);
#endif
	if (dragOK) return NX_DragOperationCopy;
	else return NX_DragOperationNone;
}

- draggingExited:(id <NXDraggingInfo>)sender
{
#ifdef DEBUG
	printf("In Method draggingExited:\n");
#endif
	return [self _resetForDrag];
}

- (BOOL)prepareForDragOperation:(id <NXDraggingInfo>)sender
{
	char *stringPos, *tempPtr, *pathList;
	char tempBuf[MAXPATHLEN+1];
	BOOL			flag			= NO;
	int				length			= 0;
	int				count			= 0;
	id				thePasteBoard	= [Pasteboard newByFilteringTypesInPasteboard:[sender draggingPasteboard]];
	
	[self _resetForDrag];
		
	if ([thePasteBoard findAvailableTypeFrom:&NXFilenamePboardType num:1]) {
		if ([thePasteBoard readType:NXFilenamePboardType data:&pathList length:&length]) flag = YES;
	} else if ([thePasteBoard findAvailableTypeFrom:&NXAsciiPboardType num:1]) {
		if ([thePasteBoard readType:NXAsciiPboardType data:&pathList length:&length]) flag = YES;
	}

	if (!flag) {
		[self _resetForDrag];
		return flag;
	}
	
#ifdef DEBUG
	printf("In Method prepareForDragOperation: building fileList\n");
#endif
	stringPos = tempPtr = pathList;
	files = 0;
	    
	/* This code just parses the pathList for the filenames and explictly */
	/* null-terminates them after copying into a buffer.  It appends that */
	/* buffer to the dynamically-allocated filelist which keeps track of it */

	/* the number of tabs + 1 equals the number of files dragged in */

	while (stringPos = index(stringPos, '\t')) {
		count = (int)(stringPos-tempPtr);
		strncpy(tempBuf,tempPtr,count);
		*(tempBuf+count) = '\0';
		filePath = addFile(tempBuf,filePath,files,MyZone);
		files++;
		stringPos++;
		tempPtr=stringPos;
    }
	count = strlen(tempPtr);
	strncpy(tempBuf,tempPtr,count);
	*(tempBuf+count) = '\0';
	filePath = addFile(tempBuf,filePath,files,MyZone);
	files++;
	[thePasteBoard deallocatePasteboardData:pathList length:length];
    return YES;
}

- (BOOL)performDragOperation:(id <NXDraggingInfo>)sender
// try to add the files in FileList to a current document
{	
	char temp[MAXPATHLEN+1];
#ifdef DEBUG
	printf("In Method performDragOperation:\n");
#endif
    NX_DURING
	while (files--) {
		sprintf(temp,"%s\n",filePath[files]);
		[self addFiles:temp];
	}
    NX_HANDLER
    NX_ENDHANDLER
		
    return YES;
}

- concludeDragOperation:(id <NXDraggingInfo>)sender
{
	return [self _resetForDrag];
}

@end
