// AcceptDragScrollView.m
// By Charles G. Fleming, Educational Computing Services, Allegheny College.
// Copyright 1993, Allegheny College.
// You may freely copy, distribute and reuse this code. 
// Allegheny College and the author disclaim any warranty of any kind, 
// expressed or implied, as to its fitness for any particular use.

#import "AcceptDragScrollView.h"
#import "ToolLoader.h"
#import "Borders.h"

@implementation AcceptDragScrollView

- initFrame:(const NXRect *)frameRect
{
	int numTypes = 1;
	const char *pasteboardTypes[2] = {NXFilenamePboardType, NULL};
	NXRect borderRect = {0, 0, 646, 57};	

	self = [super initFrame:frameRect];

	// Register the dragging types that this view will accept.
	[self registerForDraggedTypes:pasteboardTypes count:numTypes];

	// Get a pasteboard for dragging.
	dragPasteboard = [Pasteboard newName:NXDragPboard];	
	return self;
}

- setToolLoader:anObject
{
	toolLoader = anObject;
	return self;
}

//*****************************************************************************
//*****************************************************************************
// NXDraggingDestination routines. 
// Note that views and windows do not have to implement all of these methods
// since the View and Window classes provide private implemenations for all of
// these methods.
//*****************************************************************************
//*****************************************************************************

// The dragged image has entered the view.
- (NXDragOperation)draggingEntered:sender
{
	NXDragOperation sourceMask;
	NXRect borderRect;
	NXPoint corner = {0, 18};

	// Set up the NXImage that will display a white border when a tool is
	// dragged into the tool scroll view.
	[self getContentSize:&borderRect.size];
	if(blackBorderNXImage)
		[blackBorderNXImage free];
		
	blackBorderNXImage = [[NXImage allocFromZone:[self zone]] 
			initSize:&borderRect.size];
	[blackBorderNXImage lockFocus];
	drawBlackBorder(borderRect.size.width, borderRect.size.height,
			borderRect.size.width-3, borderRect.size.height-1);
	[blackBorderNXImage unlockFocus];

	// Draw a black border around the scroll view when the dragged image
	// enters.	
	[superview convertPoint:&corner toView:[window contentView]];	
	[[window contentView] lockFocus];
	[blackBorderNXImage composite:NX_SOVER toPoint:&corner];
	[[window contentView]  unlockFocus];
	[window flushWindow];

	// Ask the drag source for its operation mask.
	sourceMask = [sender draggingSourceOperationMask]; 
	if (sourceMask & NX_DragOperationCopy)
		dragOperation = NX_DragOperationCopy;
	else
		dragOperation = NX_DragOperationNone;
	return dragOperation;
}
	
// While the dragged image remains in the view, we receive this message.
- (NXDragOperation)draggingUpdated:sender
{
	return dragOperation;  
}

// If the dragged image leaves the view, we receive this message.
- draggingExited:sender
{
	// Remove the white border being displayed.
	[self display];
	return self;
}

// When the dragged image is released, this message is sent.  If we return 
// YES, we will receive the performDragOperation: message.
- (BOOL)prepareForDragOperation:sender
{
	// Remove the white border being displayed.
	[self display];

	// We do want to accept the dragged image and receive the
	// performDragOperation message.
	return YES;
}

// Do your work here.	
- (BOOL)performDragOperation:sender
{
	BOOL viewAcceptedData = NO, directoryFound = NO;
	int dataLength;
	char *filePath;

	int index, count, toolCount = 0, nextFile;
	char *tab, *startPath, *remainingPaths, *extension, *lastSlash;
	char tempPath[MAXPATHLEN+1], directory[MAXPATHLEN+1];
	char **paths, **files;

	// Get the filename from the pasteboard.
	if([dragPasteboard readType:NXFilenamePboardType data:&filePath
			length:&dataLength])
	{
		// Count the files.
		tab = filePath;
		for(count = 1; tab = index(tab, '\t'); tab++, count++);

		// Make a copy of each file.
		paths = (char **)malloc(sizeof(char *) * count);
		count = 0;
		startPath = filePath;
		while(tab = index(startPath, '\t'))
		{
			remainingPaths = tab+1;
			*tab = '\0';
			*(paths+count) = (char *)malloc(strlen(startPath)+1);
			strcpy(*(paths+count), startPath);
			startPath = remainingPaths;
			count++;
		}
		*(paths+count) = (char *)malloc(strlen(startPath)+1);
		strcpy(*(paths+count), startPath);		
		count++;

		// Use the null string for files without the .wbTool extension.  
		// Find the directory once.
		for(index = 0; index < count; index++)
			if(extension = rindex(*(paths+index), '.'))
				if(strcmp(extension, ".wbTool"))
					strcpy(*(paths+index), "");
				else
					if(lastSlash = rindex(*(paths+index), '/'))
					{
						*lastSlash = '\0';
						if(!directoryFound)
						{
							strcpy(directory, *(paths+index));
							directoryFound = YES;
						}	
						
						strcpy(tempPath, lastSlash+1);
						strcpy(*(paths+index), tempPath);
						toolCount++;
					}
					else
						strcpy(*(paths+index), "");
			else
				strcpy(*(paths+index), "");

		// Keep only those files with the .wbTool extension.				
		if(toolCount)
		{
			files = (char **)malloc((1+toolCount) * sizeof(char *));
			nextFile = 0;
			for(index = 0; index < count; index++)
				if(strcmp(*(paths+index), ""))
				{
					*(files+nextFile) = (char *) malloc(strlen( 
							*(paths+index))+1);
					strcpy(*(files+nextFile), *(paths+index));
					nextFile++;
				}	
			*(files+nextFile) = NULL;
				
			[toolLoader setToolDirectory:directory];
			[toolLoader setToolFiles:files ];
			[toolLoader loadTool];
				
			// Free the tool paths.
			for(index = 0; index < toolCount+1; index++)
				free(*(files+index));
				
			free(files);
		}

		// Free the file paths when done.
		for(index = 0; index < count; index++)
			free(*(paths+index));
		free(paths);
		
		// Deallocate the memory allocated by the readType:data:length: method.
    	[dragPasteboard deallocatePasteboardData:filePath length:dataLength];
		
		viewAcceptedData = YES;
	}
	else
		viewAcceptedData = NO;
	return viewAcceptedData;
}

// Any necessary cleaning can be done here.  This is the last message
// we will be sent.	
- concludeDragOperation:sender
{
	return self;
}

@end
