#import "Fiend.h"
#import "IconDragView.h"
#import "DockMgrView.h"
#import "Dock.h"
#import "Controller.h"
#import "FiendWraps.h"

@implementation Dock

- initMgrView:theDockMgrView
{
	dockMgrView = theDockMgrView;
	[[dockMgrView window] getFrame:&frame];

	name[0] = '\0';
	sticky = NO;
	fiendSound = destroySound = nil;
	dockWindowList = [[List allocFromZone:[self zone]] init];
	fileNameStore = [[Storage allocFromZone:[self zone]] initCount:0 elementSize:sizeof(NXAtom) description:"%"];
	appIconStore = [[Storage allocFromZone:[self zone]] initCount:0 elementSize:sizeof(int) description:"i"];
	launchFlagStore = [[Storage allocFromZone:[self zone]] initCount:0 elementSize:sizeof(int) description:"i"];
	filePositionStore = [[Storage allocFromZone:[self zone]] initCount:0
						 elementSize:sizeof(NXPoint) description:"{ff}"];
	nameWinHash = [[HashTable allocFromZone:[self zone]] initKeyDesc:"%" valueDesc:"@"];

	return self;
}

- free
{
	BOOL	hideIcons = !strcmp(NXGetDefaultValue([NXApp appName], HIDE_ICONS), "YES");

	if (hideIcons)
		[self vanishIcons:NO];

	[self empty];

	[nameWinHash free];
	[appIconStore free];
	[fileNameStore free];
	[dockWindowList free];
	[launchFlagStore free];
	[filePositionStore free];

	return [super free];
}


- empty
{
	id		win;
	int		i;
	int		count = [dockWindowList count];

	if (!sticky)	{
		for(i = 0; i < count; i++)	{
			win = [dockWindowList objectAt:i];
			if (![win isMemberOf:[Dock class]])	{
				if ([[win contentView] isSticky])
					[dockMgrView add:[win contentView] toStickyDock:NO owner:self];
				[win free];
			}
		}
	}
	[nameWinHash empty];
	[appIconStore empty];
	[fileNameStore empty];
	[dockWindowList empty];
	[filePositionStore empty];
	return self;
}

- setFiendSound:fSound destroySound:dSound
{
	fiendSound = fSound;
	destroySound = dSound;

	return self;
}

- getOffset:(NXPoint *)theOffset fromFrame:(NXRect *)theFrame
{
	NXRect	mainFrame = frame;

	theOffset->x = (NX_X(theFrame) - NX_X(&mainFrame))/NX_WIDTH(&frame);
	theOffset->y = (NX_Y(theFrame) - NX_Y(&mainFrame))/NX_HEIGHT(&frame);

	return self;
}

- createWindowWithFrame:(NXRect *)theFrame
{
	id		newWin;
	int		lowerLevel = atoi(NXGetDefaultValue([NXApp appName], DCKLWR_LEVEL));
	int		upperLevel = atoi(NXGetDefaultValue([NXApp appName], DCKUPR_LEVEL));
	BOOL	sinkDock = !strcmp(NXGetDefaultValue([NXApp appName], SINK_DOCK), "YES");

	newWin = [[Window allocFromZone:[self zone]]
			  initContent:theFrame
			  style:NX_TOKENSTYLE
			  backing:NX_BUFFERED buttonMask:0 defer:NO];
	PSsetwindowlevel(((sinkDock) ? lowerLevel : upperLevel), [newWin windowNum]);

	return newWin;
}

- select:(BOOL)flag iconWithPath:(char *)aPath
{
	id		*win;
	id		view;
	int		i;
	int		count = [fileNameStore count];
	id		*dockWinListPtr = (count > 0) ? NX_ADDRESS(dockWindowList) : (id *)NULL;

	for(i = 0, win = dockWinListPtr; i < count; i++, win++)	{
		if (strstr(*(NXAtom *)[fileNameStore elementAt:i], aPath))	{
			view = [*win contentView];
			if ([view state] != flag)
				[view setState:flag];
			return self;
		}
	}
	return self;
}

- redisplayIcons
{
	id		*win;
	int		i;
	int		count = [fileNameStore count];
	id		*dockWinListPtr = (count > 0) ? NX_ADDRESS(dockWindowList) : (id *)NULL;

	for(i = 0, win = dockWinListPtr; i < count; i++, win++)
		[[*win contentView] display];

	return self;
}

- (int)iconCount
{
	return [dockWindowList count];
}

- (int)indexOfPath:(char *)aPath exact:(BOOL)flag
{
	int		i;
	NXAtom	atom;
	int		count = [fileNameStore count];

	for(i = 0; i < count; i++)	{
		atom = *(NXAtom *)[fileNameStore elementAt:i];
		if (!flag && strstr(atom, aPath))
			return i;
		else if (flag && !strcmp(atom, aPath))
			return i;
	}
	return -1;
}

- createIconViewForPath:(const char *)path withFrame:(NXRect *)iconFrame
{
	id		iconView;
	id	   	newImage;
	BOOL	drawThumbnail = !strcmp(NXGetDefaultValue([NXApp appName], DRAW_TNAIL), "YES");

	newImage = [IconView getImageForPath:path fileIcon:!drawThumbnail zone:[self zone]];
	iconView = [[IconDragView allocFromZone:[self zone]]
				    initFrame:iconFrame
				        image:newImage
				         data:path andLength:strlen(path)
				      useSize:YES onDock:YES];
	if (dockMgrView != nil)
		[iconView setDockMgrView:dockMgrView];
	[[iconView setAutodisplay:NO] display];

	return iconView;
}

- setIsLoaded:(BOOL)flag
{
	isLoaded = flag;
	return self;
}

- (BOOL)isLoaded
{
	return isLoaded;
}

- createWindowsFromStores:(BOOL)doRegs stickyWindows:(BOOL)doStickers
{
	id		oldWin;
	id		newWin;
	id	   	iconView;
	int		i;
	int		count;
	int		autoLaunchFlag;
	BOOL    isSticky;
	NXAtom	path;
	NXPoint	*theOffset;
	NXCoord	width = NX_WIDTH(&frame);
	NXCoord	height = NX_HEIGHT(&frame);

	if (!isLoaded && doRegs)
		isLoaded = YES;

	count = [filePositionStore count];
	if (count && ![dockWindowList count]) for(i=0;i<count;i++) [dockWindowList addObject:self];
	for(i = 0; i < count; i++)	{
		path = *(NXAtom *)[fileNameStore elementAt:i];
		autoLaunchFlag = *(int *)[launchFlagStore elementAt:i];

		isSticky = (autoLaunchFlag & DOCK_STICKY) ? YES : NO;
		if (isSticky)	{
			if (!doStickers)
				continue;
		}
		else if (!doRegs)	{
			[nameWinHash insertKey:path value:self];
			continue;
		}

		theOffset = (NXPoint *)[filePositionStore elementAt:i];
		newWin = [self createWindowWithFrame:&frame];
		[newWin setAvoidsActivation:YES];
		[newWin moveTo:(theOffset->x * width - 1000.0) :(theOffset->y * height - 1000.0)];
		[nameWinHash insertKey:path value:newWin];
		oldWin = [dockWindowList replaceObjectAt:i with:newWin];
		if (![oldWin isMemberOf:[Dock class]]) [oldWin free];

		iconView = [self createIconViewForPath:path withFrame:&frame];
		[[newWin setContentView:iconView] free];

		[iconView setAutoScan:(BOOL)(autoLaunchFlag & DOCK_ASCAN)];
		if (autoLaunchFlag & DOCK_ALNCH)  {
			[iconView setAutoLaunch:YES];
			if ([iconView isApp] && ![iconView isLaunched])
				[iconView setGhost:YES];
		}
		if (autoLaunchFlag & DOCK_STICKY)	{
			[iconView setSticky:YES];
			[dockMgrView add:iconView toStickyDock:YES owner:self];
		}

		[newWin display];
		[newWin orderFront:self];
	}
	return self;
}

- performAutolaunches
{
	int		i;
	int		autoLaunchFlag;
	BOOL    isApp;
	NXAtom	path;
	char	workString[200];
	char	shortName[MAXPATHLEN+1];
	int		count = [launchFlagStore count];

	for(i = 0; i < count; i++)	{
		autoLaunchFlag = *(int *)[launchFlagStore elementAt:i];
		path = *(NXAtom *)[fileNameStore elementAt:i];
		isApp = IS_APP_PATH(path);
		if (autoLaunchFlag & DOCK_ALNCH)	{
			if (isApp && strcmp(path, WKSPC_FILE))	{
				[IconView getShortName:shortName from:(const char *)path];
				if ([IconView getLastPidFor:shortName] == -1)	{
					sprintf(workString, "Launching %s...", shortName);
					[[NXApp delegate] setProgressFieldString:workString];
					[dockMgrView launch:path autolaunch:YES];
				}
			}
			else
				[[Application workspace] openFile:path];
		}
	}
	return self;
}

- vanish:(BOOL)vanish icon:(int)appIcon for:(NXAtom)path
{
	NXSize		screenSize;

	[NXApp getScreenSize:&screenSize];	
	if (appIcon > 0 && !onNeXTDock(path, (int)screenSize.height))	{
		if (vanish)
			PSWMove(-1000.0, -1000.0, appIcon);
		else
			PSWReplaceIcon(appIcon, (int)(screenSize.width)-64);
	}
	return self;
}		

- checkLaunchStatus
{
	id		*win;
	id		iconView;
	int		i;
	int     appPid;
	int		appCtxt;
	int     appIcon;
	NXAtom  path;
	int		count = [dockWindowList count];
	id		*winListPtr = (count > 0) ? NX_ADDRESS(dockWindowList) : (id *)NULL;
	BOOL	hideIcons = !strcmp(NXGetDefaultValue([NXApp appName], HIDE_ICONS), "YES");

	for(i = 0, win = winListPtr; i < count; i++, win++)	{
		path = *(NXAtom *)[fileNameStore elementAt:i];
		if (IS_APP_PATH(path))	{
			[IconView getCtxt:&appCtxt pid:&appPid andIcon:&appIcon forPath:(char *)path];
			[appIconStore replaceElementAt:i with:(void *)&appIcon];
		}
		else
			appIcon = appPid = appCtxt = -1;
		if (hideIcons && appIcon != -1)
			[self vanish:YES icon:appIcon for:path];
		if (*win == self) continue;
		iconView = [*win contentView];
		[iconView setCtxt:appCtxt pid:appPid andIcon:appIcon];
	}
	return self;
}


- (BOOL)isShowing
{
	return (NX_X(&frame) > -1000.0 && NX_Y(&frame) > -1000.0);
}


- updateWindows:(NXPoint *)p usePlace:(BOOL)usePlace followLevels:(BOOL)follow
{
	id		*win;
	id		iconView;
	int		i;
	BOOL	exceptionRaised;
	BOOL	isLaunched;
	NXPoint	*offset;
	NXRect	winRect;
	int		width = NX_WIDTH(&frame);
	int		height = NX_HEIGHT(&frame);
	int		count = [filePositionStore count];
	id		*winListPtr = (count > 0) ? NX_ADDRESS(dockWindowList) : (id *)NULL;

	frame.origin = *p;
	for(i = 0, win = winListPtr; i < count; i++, win++)	{
		exceptionRaised = NO;
		if (*win == self) continue;
		iconView = [*win contentView];
		isLaunched = [iconView isLaunched];
		if (!sticky && follow)	{
			if (p->x == p->y && p->x == -1000.0)	{
				if ([iconView isLaunched])	{
					[iconView getScreenStatus];
					if ([iconView appWasVisible] && ![iconView isSticky])
						fiendUnhideContext([iconView appCtxt], 0, 0, 0);
				}
			}
			else	{
				if ([iconView isLaunched] && [iconView appWasVisible])	{
					if (![iconView isSticky])	{
						fiendUnhideContext([iconView appCtxt], (int)[iconView appWasVisible],
									  (int)[iconView appWasActive], 0);
					}
				}
			}
		}
		if (!sticky && [iconView isSticky])
			continue;
		offset = (NXPoint *)[filePositionStore elementAt:i];
		if (offset->x == offset->y && offset->x == 0.0)	{
			[*win getFrame:&winRect];
			[self getOffset:offset fromFrame:&winRect];
			[filePositionStore replaceElementAt:i with:(void *)offset];
		}
		if (usePlace)	{
			NXSetRect(&winRect, p->x + offset->x * width, p->y + offset->y * height,
					  NX_WIDTH(&frame), NX_HEIGHT(&frame));
			[*win placeWindowAndDisplay:&winRect];
		}
		else
			[*win moveTo:p->x + offset->x * width :p->y + offset->y * height];
		if ([iconView isSticky])
			[*win orderFront:self];
		[filePositionStore replaceElementAt:i with:(void *)offset];
	}
	return self;
}

- setSticky
{
	sticky = YES;
	return self;
}

- setDockMgrView:theMgrView
{
	id		*win;
	int		i;
	int		count = [dockWindowList count];
	id		*dockWinListPtr = (count > 0) ? NX_ADDRESS(dockWindowList) : (id *)NULL;

	dockMgrView = theMgrView;

	for(i = 0, win = dockWinListPtr; i < count; i++, win++)
		[[*win contentView] setDockMgrView:dockMgrView];
	return self;
}

- viewAtPosition:(NXRect *)checkRect besides:testView
{
	id		*win;
	int		i;
	NXRect	winFrame;
	NXRect	myWinFrame = frame;
	int		count = [dockWindowList count];
	id		*winListPtr = (count > 0) ? NX_ADDRESS(dockWindowList) : (id *)NULL;

	[[dockMgrView window] getFrame:&myWinFrame];
	if (NX_X(checkRect) == NX_X(&myWinFrame) && NX_Y(checkRect) == NX_Y(&myWinFrame))
		return self;
	for(i = 0, win = winListPtr; i < count; i++, win++)	{
		if (*win == self) continue;
		if (testView && testView == [*win contentView])
			continue;
		[*win getFrame:&winFrame];
		if (NX_X(checkRect) == NX_X(&winFrame) && NX_Y(checkRect) == NX_Y(&winFrame))
			return [*win contentView];
	}
	return nil;
}

- deleteSelectedCells
{
	id		*win;
	id		iconView;
	int		i;
	id		*cutListPtr = (id *)NULL;
	int		count = [dockWindowList count];
	id		cutList = [[List allocFromZone:[self zone]] init];
	id		*dockWinListPtr = (count > 0) ? NX_ADDRESS(dockWindowList) : (id *)NULL;

	for(i = 0, win = dockWinListPtr; i < count; i++, win++)	{
		iconView = [*win contentView];
		if ([iconView state] && ![iconView isSticky])
			[cutList addObject:iconView];
	}
	count = [cutList count];
	if (count > 0)
		cutListPtr = NX_ADDRESS(cutList);
	for(i = 0, win = cutListPtr; i < count; i++, win++)
		[self deleteView:*win unvanish:YES];

	[cutList free];
	return self;
}

- (int)hasSelectedCells
{
	id		*win;
	int		i;
	int		selCnt = 0;
	int		count = [dockWindowList count];
	id		*dockWinListPtr = (count > 0) ? NX_ADDRESS(dockWindowList) : (id *)NULL;

	for(i = 0, win = dockWinListPtr; i < count; i++, win++)	{
		if ([[*win contentView] state])
			selCnt++;
	}
	return selCnt;
}

- (const char *)selectedCellPath
{
	id		*win;
	id		iconView;
	int		i;
	int		len;
	char	*path = "";
	int		count = [dockWindowList count];
	id		*dockWinListPtr = (count > 0) ? NX_ADDRESS(dockWindowList) : (id *)NULL;

	for(i = 0, win = dockWinListPtr; i < count; i++, win++)	{
		if ([(iconView = [*win contentView]) state])	{
			[iconView getData:(void *)&path andLength:&len];
			break;
		}
	}
	return (const char *)path;
}

- selectedCell
{
	id		*win;
	id		iconView;
	int		i;
	int		count = [dockWindowList count];
	id		*dockWinListPtr = (count > 0) ? NX_ADDRESS(dockWindowList) : (id *)NULL;

	iconView = nil;
	for(i = 0, win = dockWinListPtr; i < count; i++, win++)	{
		if ([(iconView = [*win contentView]) state])
			return iconView;
	}
	return nil;
}

- select:(BOOL)flag all:sender
{
	id		*win;
	id		view;
	int		i;
	int		count = [dockWindowList count];
	id		*dockWinListPtr = (count > 0) ? NX_ADDRESS(dockWindowList) : (id *)NULL;

	for(i = 0, win = dockWinListPtr; i < count; i++, win++)	{
		view = [*win contentView];
		if ([view state] != flag)
			[[view setState:flag] display];
	}
	return self;
}

- getNextFrame:(NXRect *)theFrame
{
	int			maxTries;
	BOOL		goingDown = TRUE;
	float		limit = 4.0;
	NXSize		size = {0.0, 0.0};

	[NXApp getScreenSize:&size];
	maxTries = size.width * size.height/(NX_WIDTH(&frame) * NX_WIDTH(&frame));

	*theFrame = frame;

	while (maxTries)	{
		/* scan left */
		do	{
			maxTries--;
			NX_X(theFrame) -= NX_WIDTH(theFrame);
		} while ((NX_X(theFrame) > 0.0) && ((NX_X(&frame) - NX_X(theFrame))/NX_WIDTH(theFrame) <= limit) &&
				 ([self viewAtPosition:theFrame besides:nil] != nil ||
				 [[dockMgrView stickyDock] viewAtPosition:theFrame besides:nil] != nil));

		/* if we're within bounds, we're done */
		if (NX_X(theFrame) > 0.0  && ((NX_X(&frame) - NX_X(theFrame))/NX_WIDTH(theFrame) <= limit))
			return self;
		else	{
			/* scan right */
			NX_X(theFrame) = NX_X(&frame);
			do	{
				maxTries--;
				NX_X(theFrame) += NX_WIDTH(theFrame);
			}	while ((NX_MAXX(theFrame) < size.width) &&
					   ((NX_MAXX(theFrame) - NX_MAXX(&frame))/NX_WIDTH(theFrame) <= limit) &&
					   ([self viewAtPosition:theFrame besides:nil] != nil ||
					   [[dockMgrView stickyDock] viewAtPosition:theFrame besides:nil] != nil));

			/* if we're within bounds, we're done */
			if (NX_MAXX(theFrame) < size.width && ((NX_MAXX(theFrame) - NX_MAXX(&frame))/NX_WIDTH(theFrame) <= limit))
				return self;
			else	{
				/* move down a row */
				if (goingDown)	{
					if (NX_Y(theFrame) >= NX_HEIGHT(theFrame))
						NX_Y(theFrame) -= NX_HEIGHT(theFrame);
					else	{
						goingDown = NO;
						NX_Y(theFrame) = NX_MAXY(&frame);
					}
				}
				else	{
					if (NX_MAXY(theFrame) <= size.height)
						NX_Y(theFrame) += NX_HEIGHT(theFrame);
					else	{
						limit = 100.0;
						goingDown = YES;
						NX_Y(theFrame) = NX_Y(&frame);
					}
				}
				NX_X(theFrame) = NX_MAXX(&frame);
			}
		}
	}
	return self;
}

- addStickyWindow:aWindow atOffset:(NXPoint *)offset
{
	int		junk;
	char	*viewPath;
	id		aView = [aWindow contentView];

	[aView getData:(void **)&viewPath andLength:&junk];
	[dockWindowList addObject:aWindow];
	[filePositionStore addElement:(void *)offset];
	return self;
}

- getOffset:(NXPoint *)offset forWindow:aWindow
{
	int		index = [dockWindowList indexOf:aWindow];

	if (index == NX_NOT_IN_LIST)
		return nil;

	*offset = *(NXPoint *)[filePositionStore elementAt:index];
	return self;
}
		

- removeStickyWindow:aWindow
{
	int		index = [dockWindowList indexOf:aWindow];

	if (index != NX_NOT_IN_LIST)	{
		[dockWindowList removeObject:aWindow];
		[filePositionStore removeElementAt:index];
	}

	return self;
}

- createWindowForPath:(const char *)thePath newFrame:(NXRect *)newFrame
{
	id			newWin;
	id			iconView;

	if (!thePath)
		return nil;

	if (NX_MAXX(newFrame) <= NX_WIDTH(newFrame) || NX_MAXY(newFrame) <= NX_HEIGHT(newFrame) ||
		[self viewAtPosition:newFrame besides:nil] ||
		[[dockMgrView stickyDock] viewAtPosition:newFrame besides:nil])
		[self getNextFrame:newFrame];

	newWin = [self createWindowWithFrame:newFrame];
	iconView = [self createIconViewForPath:thePath withFrame:newFrame];
	[nameWinHash insertKey:NXUniqueString(thePath) value:newWin];
	[[newWin setContentView:iconView] free];

	[newWin setAvoidsActivation:YES];
	[dockWindowList addObject:newWin];

	[newWin display];
	[newWin orderFront:self];

	return newWin;
}

- vanishIcons:(BOOL)flag
{
	int		i;
	int		appIcon;
	NXAtom	path;
	int		count = [appIconStore count];

	for(i = 0; i < count; i++)	{
		path = *(NXAtom *)[fileNameStore elementAt:i];
		appIcon = *(int *)[appIconStore elementAt:i];
		[self vanish:flag icon:appIcon for:path];
	}
	return self;
}

- rotateOffsets
{
	id		*win;
	int		i;
	NXRect	windowRect;
	NXPoint	p;
	NXPoint	*oldOffset;
	NXPoint	newOffset;
	int		width = NX_WIDTH(&frame);
	int		height = NX_HEIGHT(&frame);
	int		count = [dockWindowList count];
	id		*winListPtr = (count > 0) ? NX_ADDRESS(dockWindowList) : (id *)NULL;

	[[dockMgrView window] getFrame:&windowRect];
	p = windowRect.origin;
	for(i = 0, win = winListPtr; i < count; i++, win++)	{
		if (*win == self) continue;
		if ([[*win contentView] isSticky])
			continue;
		oldOffset = (NXPoint *)[filePositionStore elementAt:i];
		newOffset.x = oldOffset->y;
		newOffset.y = -oldOffset->x;
		[*win moveTo:p.x+newOffset.x*width :p.y+newOffset.y*height];
		[filePositionStore replaceElementAt:i with:(void *)&newOffset];
	}
	return self;
}


- scanIcons
{
	int		i;
	id		*win;
	id		view;
	int		count = [dockWindowList count];
	id		*winListPtr = (count > 0) ? NX_ADDRESS(dockWindowList) : (id *)NULL;

	for(i = 0, win = winListPtr; i < count; i++, win++)	{
		if (*win == self) continue;
		view = [*win contentView];
		if (!sticky && [view isSticky])
			continue;
		if ([view autoScan])
			[view refreshIcon];
	}

	return self;
}

- restoreIcons
{
	int		i;
	id		*win;
	id		view;
	int		count = [dockWindowList count];
	id		*winListPtr = (count > 0) ? NX_ADDRESS(dockWindowList) : (id *)NULL;

	for(i = 0, win = winListPtr; i < count; i++, win++)	{
		if (*win == self) continue;
		view = [*win contentView];
		if (!sticky && [view isSticky])
			continue;
		if ([view autoScan])
			[view restoreIconImage];
	}

	return self;
}

- addWindowForPath:(NXAtom)pathAtom at:(NXRect *)testFrame
{
	id		newWin;
	NXPoint	newOffset;
	int		autoLaunch = NO;
	NXRect	aFrame = {{NX_X(&frame)-NX_WIDTH(&frame), NX_Y(&frame)}, {NX_WIDTH(&frame), NX_HEIGHT(&frame)}};
	NXRect	*newFrame = (testFrame == (NXRect *)NULL) ? &aFrame : testFrame;

	[launchFlagStore addElement:(void *)&autoLaunch];
	newWin = [self createWindowForPath:pathAtom newFrame:newFrame];
	[fileNameStore addElement:(void *)&pathAtom];
	[self getOffset:&newOffset fromFrame:newFrame];
	[filePositionStore addElement:(void *)&newOffset];

	return newWin;
}

- removeWindow:aWin
{
	NXAtom	pathAtom;
	int		index = [dockWindowList indexOf:aWin];

	if (index != NX_NOT_IN_LIST)	{
		pathAtom = *(NXAtom *)[fileNameStore elementAt:index];
		[nameWinHash removeKey:pathAtom];
		[appIconStore removeElementAt:index];
		[fileNameStore removeElementAt:index];
		[launchFlagStore removeElementAt:index];
		[filePositionStore removeElementAt:index];
		[dockWindowList removeObjectAt:index];
	}

	return self;
}

- addWindow:aWin withPath:(char *)aPath
{
	int			autoLaunch = NO;
	int			junk = -1;
	NXRect		aFrame;
	NXPoint		newOffset;
	NXRect		*newFrame = &aFrame;
	NXAtom		pathAtom = NXUniqueString(aPath);

	[aWin getFrame:newFrame];
	if (NX_MAXX(newFrame) <= NX_WIDTH(newFrame) || NX_MAXY(newFrame) <= NX_HEIGHT(newFrame) ||
		[self viewAtPosition:newFrame besides:nil])
		[self getNextFrame:newFrame];
	
	[dockWindowList addObject:aWin];
	[appIconStore addElement:(void *)&junk];
	[fileNameStore addElement:(void *)&pathAtom];
	[launchFlagStore addElement:(void *)&autoLaunch];
	[self setLaunchFlagsFor:[aWin contentView]];
	
	[self getOffset:&newOffset fromFrame:newFrame];
	[filePositionStore addElement:(void *)&newOffset];
	return self;
}


- deleteView:aView quickly:(BOOL)flag unvanish:(BOOL)unvanishFlag
{
	NXAtom	pathAtom;
	id		win = [aView window];
	int		index = [dockWindowList indexOf:win];
	BOOL	hideIcons = !strcmp(NXGetDefaultValue([NXApp appName], HIDE_ICONS), "YES");

	[win moveTo:-1000.0 :-1000.0];
	if (index != NX_NOT_IN_LIST)	{
		if (unvanishFlag && hideIcons)
			[aView unvanishIcon];
		pathAtom = *(NXAtom *)[fileNameStore elementAt:index];
		[nameWinHash removeKey:pathAtom];
		[appIconStore removeElementAt:index];
		[fileNameStore removeElementAt:index];
		[filePositionStore removeElementAt:index];
		[launchFlagStore removeElementAt:index];
		[dockWindowList removeObjectAt:index];
		[NXApp delayedFree:win];
	}
	return self;
}

- deleteView:aView unvanish:(BOOL)unvanishFlag
{
	return [self deleteView:aView quickly:YES unvanish:unvanishFlag];
}

- dockWindowList
{
	return dockWindowList;
}

- setLaunchFlagsFor:iconView
{
	int		index = [dockWindowList indexOf:[iconView window]];
	int		flag = ([iconView autoLaunch]) ? DOCK_ALNCH : DOCK_NONE;

	if ([iconView autoScan]) flag |= DOCK_ASCAN;
	if ([iconView isSticky]) flag |= DOCK_STICKY;
	[launchFlagStore replaceElementAt:index with:(void *)&flag];
	return self;
}

- (int)copy:sender toPasteboard:pb andCut:(BOOL)cutFlag sndEnable:(BOOL)flag
{
	id		*win;
	id		view;
	int		i;
	int		junk;
	int		length;
	int		maxLength;
	int		*launchFlags;
	NXPoint	*theOffset;
	char	*viewPath;
	char	*cutString;
	NXPoint	maxOffset = {-100.0, -100.0};
	int		count = [dockWindowList count];
	id		cutList = [[List allocFromZone:[self zone]] init];
	id		*cutListPtr = (id *)NULL;
	id		*dockWinListPtr = (count > 0) ? NX_ADDRESS(dockWindowList) : (id *)NULL;
	BOOL	useSound = (flag && !strcmp(NXGetDefaultValue([NXApp appName], USE_SOUND), "YES"));
	NXStream	*theStream = NXOpenMemory(NULL, 0, NX_WRITEONLY);
	const char 	*types[] = {FIEND_PBTYPE, NXFilenamePboardType, NXAsciiPboardType};

	[pb declareTypes:types num:3 owner:nil];

	for(i = 0, win = dockWinListPtr; i < count; i++, win++)	{
		if ([[*win contentView] state])	{
			theOffset = (NXPoint *)[filePositionStore elementAt:i];
			maxOffset.x = (maxOffset.x > theOffset->x) ? maxOffset.x : theOffset->x;
			maxOffset.y = (maxOffset.y > theOffset->y) ? maxOffset.y : theOffset->y;
		}
	}
	NXPrintf(theStream, "DOCK\t%.0f %.0f\t", maxOffset.x, maxOffset.y);
	for(i = 0, win = dockWinListPtr; i < count; i++, win++)	{
		theOffset = (NXPoint *)[filePositionStore elementAt:i];
		launchFlags = (int *)[launchFlagStore elementAt:i];
		view = [*win contentView];
		if ([view state])	{
			[view getData:(void **)&viewPath andLength:&junk];
			NXPrintf(theStream, "%6d%7.0f%7.0f  %s\t",
					 *launchFlags, theOffset->x, theOffset->y, viewPath);
			[cutList addObject:view];
		}
	}
	NXGetMemoryBuffer(theStream, &cutString, &length, &maxLength);
	[pb writeType:FIEND_PBTYPE data:cutString length:length];
	NXClose(theStream);

	length = 0;
	count = [cutList count];
	if (count > 0)
		cutListPtr = NX_ADDRESS(cutList);
	theStream = NXOpenMemory(NULL, 0, NX_WRITEONLY);
	for(i = 0, win = cutListPtr; i < count; i++, win++)	{
		[*win getData:(void **)&viewPath andLength:&junk];
		NXPrintf(theStream, "%s\t", viewPath);
	}
	NXGetMemoryBuffer(theStream, &cutString, &length, &maxLength);
	cutString[strlen(cutString)-1] = '\0';
	[pb writeType:NXFilenamePboardType data:cutString length:length];

	for(i = 0; i < strlen(cutString); i++)	{
		if (cutString[i] == '\t')
			cutString[i] = '\n';
	}
	if (cutString[strlen(cutString)-1] != '\n') strcat(cutString, "\n");
	[pb writeType:NXAsciiPboardType data:cutString length:length];
	NXClose(theStream);

	if (cutFlag)	{
		if (count && useSound)
			[destroySound play:self];
		for(i = 0, win = cutListPtr; i < count; i++, win++)	{
			if (![*win isSticky])
				[self deleteView:*win unvanish:(sender != dockMgrView)];
		}
	}

	[cutList free];

	return count;
}

- paste:sender toPasteboard:pb sndEnable:(BOOL)flag
{
	id		iconView;
	int		len;
	int		level;
	int		launchFlag;
	char	*path;
	char	*dragString;
	char	tokenString[MAXPATHLEN+1];
	BOOL	didPaste;
	BOOL	fromDock;
	BOOL	fromShelf;
	NXRect	winRect;
	NXAtom	pathAtom;
	NXCoord	x;
	NXCoord	y;
	const	char *type;
	char	*sep = "\t";
	const	char *types[] = {FIEND_PBTYPE, NXFilenamePboardType};
	BOOL	hideIcons = !strcmp(NXGetDefaultValue([NXApp appName], HIDE_ICONS), "YES");
	BOOL	useSound = (flag && !strcmp(NXGetDefaultValue([NXApp appName], USE_SOUND), "YES"));

	type = [pb findAvailableTypeFrom:types num:2];
	if (type && !strcmp(type, FIEND_PBTYPE))	{
		if (![pb readType:FIEND_PBTYPE data:&dragString length:&len])
			return self;
		sep = "\t";
	}		
	else if (type && !strcmp(type, NXFilenamePboard))	{
		if (![pb readType:NXFilenamePboardType data:&dragString length:&len])
			return self;
		sep = "\t";
	}
	else	{
		NXBeep();
		return self;
	}

	if (len == 0)	{
		NXBeep();
		return self;
	}

	[self select:NO all:self];

	didPaste = NO;
	path = strtok(dragString, sep);
	fromDock = (!strcmp(path, "DOCK")) ? YES : NO;
	fromShelf = (!strcmp(path, "SHELF")) ? YES : NO;
	if (fromShelf || fromDock)
		path = strtok(NULL, sep);
	if (fromDock) path = strtok(NULL, sep);
	while(path && strlen(path))	{
		if (strcmp(type, FIEND_PBTYPE))	{
			winRect = frame;
			pathAtom = NXUniqueString(path);
		}
		else	{
			sscanf(path, "%d %f %f %[^\n\t]", &launchFlag, &x, &y, tokenString);
			pathAtom = NXUniqueString(tokenString);
			if (fromShelf)	{
				x = rint(x); y = rint(y);
				launchFlag = DOCK_NONE;
				x -= 1.0;
			}
			NXSetRect(&winRect,
					  NX_X(&frame) + x * NX_WIDTH(&frame),
					  NX_Y(&frame) + y * NX_HEIGHT(&frame),
					  NX_WIDTH(&frame), NX_HEIGHT(&frame));
		}
		if ((level = [dockMgrView findLevelContaining:pathAtom switch:NO]) < 0)	{
			didPaste = YES;
			iconView = [[self addWindowForPath:pathAtom at:&winRect] contentView];
			[iconView setAutoScan:((launchFlag & DOCK_ASCAN)?YES:NO)];
			[iconView setAutoLaunch:((launchFlag & DOCK_ALNCH)?YES:NO)];
			[self setLaunchFlagsFor:iconView];
			[iconView refreshIcon];
			if (sender != self && hideIcons)
				[iconView vanishIcon];
		}
		else	{
			NXBeep();
			NXRunAlertPanel([NXApp appName],
							"Fiend Dock already contains %s on level %d...",
							NULL, NULL, NULL, pathAtom, level+1);
		}
		path = strtok(NULL, sep);
	}
	[pb deallocatePasteboardData:dragString length:len];

	if (didPaste && useSound)
		[fiendSound play:self];

	return self;
}

- setWindowTier:(int)aLevel
{
	int		i;
	id		*win;
	int		count = [dockWindowList count];
	id		*winListPtr = (count > 0) ? NX_ADDRESS(dockWindowList) : (id *)NULL;

	for(i = 0, win = winListPtr; i < count; i++, win++)   {
		if (*win == self) continue;
		PSsetwindowlevel(aLevel, [*win windowNum]);
	}
	return self;
}

- paste:sender sndEnable:(BOOL)flag
{
	return [self paste:sender toPasteboard:[Pasteboard new] sndEnable:flag];
}

- (int)addToWinRecArray:(struct winRec **)winRecs presentCount:(int *)presentCount
{
	id		*win;
	int		i;
	int		localNum;
	int		globalNum;
	NXPoint	*offset;
	int		actualCount = 0;
	int		winCount = [dockWindowList count];
	id		*winListPtr = (winCount > 0) ? NX_ADDRESS(dockWindowList) : (id *)NULL;

	if (winCount > 0)	{
		actualCount = 0;
		*winRecs = (struct winRec *)realloc(*winRecs,
											sizeof(struct winRec) * (*presentCount + winCount));
		for(i = 0, win = winListPtr; i < winCount; i++, win++)	{
			if (*win == self) continue;
			if (sticky || ![[*win contentView] isSticky])	{
				localNum = [*win windowNum];
				NXConvertWinNumToGlobal(localNum, &globalNum);
				offset = (NXPoint *)[filePositionStore elementAt:i];
				(*winRecs)[*presentCount + actualCount].winNum = globalNum;
				(*winRecs)[*presentCount + actualCount].xOffset = offset->x;
				(*winRecs)[*presentCount + actualCount].yOffset = offset->y;
				actualCount++;
			}
		}
		winCount = actualCount;
	}
	return (*presentCount + winCount);
}

- findWindowForName:(const char *)aName
{
	return (id)[nameWinHash valueForKey:NXUniqueString(aName)];
}

- filePositionStore
{
	return filePositionStore;
}

- fileNameStore
{
	return fileNameStore;
}

- appIconStore
{
	return appIconStore;
}

- launchFlagStore
{
	return launchFlagStore;
}

- nameWinHash
{
	return nameWinHash;
}

- getFrame:(NXRect *)aFrame
{
	*aFrame = frame;
	return self;
}

- setFrame:(const NXRect *)aFrame
{
	frame = *aFrame;
	return self;
}

- setName:(char *)aName
{
	strncpy(name, aName, DOCKNAMELEN);
	name[DOCKNAMELEN] = '\0';
	return self;
}

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

@end
