/* Dock.m created by fred on Wed 22-Sep-1999 */

#import "Dock.h"

#import "DockTileView.h"
#import "DockPreferences.h"
#import "DockBackgroundView.h"
#import "DockHandleView.h"
#import "DockWindow.h"

#define W_BORDER		3
#define B_INTERSPACE	2
#define D_SIZE		10

@implementation Dock

- init
{	[super init];
	itsTiles = [[NSMutableArray alloc] init];
	itsWindow = nil;
	itsPreferences = [[DockPreferences alloc] init];
	itsPath = nil;
	[self setImageSize:24];
	[self setWindowPosition:NSZeroPoint];
	return self;
}

//	----------------------------------------------------------------------------

- initFromPropertyList:(NSDictionary *)aDictionary
{	NSEnumerator *e;
	id o;
	NSString *theString;

	[self init];

	[self setPreferences:[[[DockPreferences alloc] initFromPropertyList:[aDictionary objectForKey:@"Preferences"]] autorelease]];

	e = [[aDictionary objectForKey:@"Tiles"] objectEnumerator];
	while (o=[e nextObject])
		[self addTile:[[[DockTileView alloc] initFromPropertyList:o] autorelease]];

	if (theString=[aDictionary objectForKey:@"ImageSize"])
		[self setImageSize:[theString intValue]];

	if (theString=[aDictionary objectForKey:@"WindowPosition"])
		[self setWindowPosition:NSPointFromString(theString)];

	return self;
}

//	----------------------------------------------------------------------------

- initFromPath:(NSString *)aPath
{	NSDictionary *theDict = [NSDictionary dictionaryWithContentsOfFile:aPath];

		//	This is ugly
	if (!theDict)
	{	NSLog( @"Dock at [%@] is inexistant, unreadable or badly formed -- skipping", aPath );
		[super init];
		[self release];
		return nil;
	}

	[self initFromPropertyList:theDict];
	[self setPath:aPath];

	return self;
}

//	----------------------------------------------------------------------------

- (void)dealloc
{	[itsTiles release];
	[itsWindow setDelegate:nil];
	[itsWindow release];
	[itsPreferences release];
	[itsPath release];
	[super dealloc];
}

//	----------------------------------------------------------------------------

- (int)imageSize
{	return itsTileSize - 2;
}

//	----------------------------------------------------------------------------

- (void)setImageSize:(int)aSize
{	if (aSize==0)
		aSize = 24;
	itsTileSize = aSize + 2;
}

//	----------------------------------------------------------------------------

- (NSPoint)windowPosition
{	return itsWindowPosition;
}

//	----------------------------------------------------------------------------

- (void)setWindowPosition:(NSPoint)aPosition
{	itsWindowPosition = aPosition;
}

//	----------------------------------------------------------------------------

- (void)placeWindow
{	[itsWindow setFrameOrigin:itsWindowPosition];
}

//	----------------------------------------------------------------------------

- (void)takeImageSizeFromTag:sender
{	NSEnumerator *e = [itsTiles objectEnumerator];
	DockTileView *o;

	[self setImageSize:[sender tag]];

		//	We reset the tiles
	while (o=[e nextObject])
		[o setPath:[o path]];

		//	Re-layout
	[self layout];
}

//	----------------------------------------------------------------------------

- (void)setPreferences:(DockPreferences *)aPreference
{	[itsPreferences autorelease];
	itsPreferences = [aPreference retain];
}

//	----------------------------------------------------------------------------

- (NSString *)path
{	return itsPath;
}

//	----------------------------------------------------------------------------

- (void)setPath:(NSString *)aPath
{	[itsPath autorelease];
	itsPath = [aPath retain];
}

//	----------------------------------------------------------------------------

- (void)addTile:(DockTileView *)aTile
{	[aTile setSlotIndex:[itsTiles count]];
	[aTile setDock:self];
	[itsTiles addObject:aTile];
}

//	----------------------------------------------------------------------------

- (void)tileChanged:(DockTileView *)aTile
{	[self doSave:self];
}

//	----------------------------------------------------------------------------

- (void)windowDidMove:(NSNotification *)notification
{	[self setWindowPosition:[itsWindow frame].origin];
	[self doSave:nil];
}

//	----------------------------------------------------------------------------

- (NSDictionary *)propertyList
{	NSMutableDictionary *theDict = [NSMutableDictionary dictionary];
	NSMutableArray *theArray = [NSMutableArray array];
	NSEnumerator *e = [itsTiles objectEnumerator];
	DockTileView *o;

	[theDict setObject:[itsPreferences propertyList] forKey:@"Preferences"];

	while (o=[e nextObject])
		[theArray addObject:[o propertyList]];

	[theDict setObject:theArray forKey:@"Tiles"];

	[theDict setObject:[NSNumber numberWithInt:[self imageSize]] forKey:@"ImageSize"];

	[theDict setObject:NSStringFromPoint([self windowPosition]) forKey:@"WindowPosition"];

	return theDict;
}

//	----------------------------------------------------------------------------

- (void)makeKeyAndOrderFront:sender
{	if (!itsWindow)
	{	itsWindow = [[DockWindow alloc] initWithContentRect:NSZeroRect styleMask:NSBorderlessWindowMask backing: NSBackingStoreBuffered defer:YES screen:[NSScreen mainScreen]];
		itsBackgroundView = [[DockBackgroundView alloc] init];
		itsHandleView = [[DockHandleView alloc] init];
		[itsBackgroundView addSubview:itsHandleView];

		itsAlternateHandleView = [[DockHandleView alloc] init];

		[itsWindow setContentView:itsBackgroundView];
//		[self placeWindow];
		[itsWindow setLevel:NSStatusWindowLevel];
		[itsWindow setDelegate:self];
	}
	[self layout];

	[itsBackgroundView startTracking];

	[self placeWindow];
	[itsWindow orderFront:self];
}

//	----------------------------------------------------------------------------

- (void)doSave:sender
{	if (itsPath)
	{	if (![[self propertyList] writeToFile:[self path] atomically:YES])
			NSLog( @"**** Cannot write dock to [%@]", [self path] );
	}
}

//	----------------------------------------------------------------------------

- (void)layoutNonCollapsed
{	NSEnumerator *e = [itsTiles objectEnumerator];
	DockTileView *o;

	int theLastX = W_BORDER+D_SIZE;

	if (itsfIsTemporaryUncollapsed)
		[itsWindow setBackgroundColor:[NSColor colorWithCalibratedHue:30.0/360 saturation:54.0/100 brightness:57.0/100 alpha:1.0]];
	else
		[itsWindow setBackgroundColor:[NSColor lightGrayColor]];

		//	We layout the tiles
	while (o=[e nextObject])
	{	[itsBackgroundView addSubview:o];
		[o setFrame:NSMakeRect( theLastX, W_BORDER, itsTileSize,itsTileSize )];
		theLastX += itsTileSize + B_INTERSPACE;
	}
	theLastX -= B_INTERSPACE;

		//	We layout the drag handle
	[itsHandleView setFrame:NSMakeRect( 0, 0, D_SIZE, itsTileSize+2*W_BORDER) ];
	[itsBackgroundView addSubview:itsAlternateHandleView];
	[itsAlternateHandleView setFrame:NSMakeRect( theLastX+W_BORDER, 0, D_SIZE, itsTileSize+2*W_BORDER) ];

		//	We change the window size
	[itsWindow setContentSize:NSMakeSize( [itsTiles count]*(itsTileSize+B_INTERSPACE) - B_INTERSPACE + W_BORDER*2 + D_SIZE*2, itsTileSize+2*W_BORDER )];
}

//	----------------------------------------------------------------------------

- (void)layoutCollapsed
{	NSEnumerator *e = [itsTiles objectEnumerator];
	DockTileView *o;

	[itsWindow setBackgroundColor:[NSColor lightGrayColor]];

		//	We layout the tiles
	while (o=[e nextObject])
		[o removeFromSuperview];

		//	We layout the drag handle
	[itsHandleView setFrame:NSMakeRect( 0, 0, D_SIZE, itsTileSize+2*W_BORDER) ];
	[itsAlternateHandleView removeFromSuperview];

		//	We change the window size
	[itsWindow setContentSize:NSMakeSize( D_SIZE, itsTileSize+2*W_BORDER )];
}

//	----------------------------------------------------------------------------

- (void)layout
{	if (itsfCollapsed)
		[self layoutCollapsed];
	else
		[self layoutNonCollapsed];
}

//	----------------------------------------------------------------------------

	//	We should do a small animation there and in the next method
	//	(Copy window content in an offscreen buffer, and animate the collapse)
- (void)uncollapse:sender
{	itsfCollapsed = NO;
//	[itsWindow setContentSize:NSMakeSize(  (itsTileSize+B_INTERSPACE)*32-B_INTERSPACE+W_BORDER*2+D_SIZE, itsTileSize+ W_BORDER*2 )];
	[itsBackgroundView stopCheckingForControl];
	[self layout];
}

//	----------------------------------------------------------------------------

- (void)collapse:sender
{	itsfCollapsed = YES;
//	[itsWindow setContentSize:NSMakeSize(  D_SIZE, itsTileSize+ W_BORDER*2 )];
	[self layout];
}

//	----------------------------------------------------------------------------

- (BOOL)isCollapsed
{	return itsfCollapsed;
}

//	----------------------------------------------------------------------------

- (void)flipCollapse:sender
{	[itsBackgroundView startTracking];

	if ([self isCollapsed])
		[self uncollapse:sender];
	else
		[self collapse:sender];
}

//	----------------------------------------------------------------------------

- (void)temporaryUncollapse:sender
{
	itsfIsTemporaryUncollapsed = YES;
	[self uncollapse:nil];

	[itsBackgroundView startTracking];
}

//	----------------------------------------------------------------------------

- (void)temporaryAbortUncollapse:sender
{
	itsfIsTemporaryUncollapsed = NO;
	[self collapse:nil];
}

//	----------------------------------------------------------------------------

- (void)backgroundEntered:sender
{
#ifdef VERBOSE
	NSLog( @"ENTERED" );
#endif
	if (itsfCollapsed)
	{
//		I stopped doing this because it had a very strange feeling (ie: it is a kind of exepert function that bite the average user which have troubles to get its double-click again)
//		[self performSelector:@selector(temporaryUncollapse:) withObject:nil afterDelay:1];
#ifdef VERBOSE
		NSLog( @"  SCHEDULING A TEMPORARY UNCOLLAPSE" );
#endif

		[itsBackgroundView startCheckingForControl];
	}
	else
	{	[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(temporaryAbortUncollapse:) object:nil];
#ifdef VERBOSE
		NSLog( @"  STOPPING EVENTUAL COLLAPSE" );
#endif
	}
}

//	----------------------------------------------------------------------------

- (void)wantUncollapse:sender
{	if (itsfCollapsed && !itsfIsTemporaryUncollapsed)
		[self temporaryUncollapse:self];
}

//	----------------------------------------------------------------------------

- (void)backgroundExited:sender
{
#ifdef VERBOSE
	NSLog( @"EXITED" );
#endif
	if (!itsfIsTemporaryUncollapsed)
	{	[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(temporaryUncollapse:) object:nil];
#ifdef VERBOSE
		NSLog( @"  STOPPING EVENTUAL TEMPORARY UNCOLLAPSE" );
#endif
	}
	else
	{	[self performSelector:@selector(temporaryAbortUncollapse:) withObject:nil afterDelay:1];
#ifdef VERBOSE
		NSLog( @"  *** SCHEDULING AN COLLAPSE" );
#endif
	}

	[itsBackgroundView stopCheckingForControl];
}

//	----------------------------------------------------------------------------

- (BOOL)applicationLaunched:(NSString *)aPath
{	return [[NSApp delegate] applicationLaunched:aPath];
}

//	----------------------------------------------------------------------------

- (void)controlPressed:sender
{		//	The problem is that we get suprious modifier flags (ie: the normal ones generated by the AppKit) when the background view is the keyview _and_ the application is active
//	if (itsfCollapsed)
		[self temporaryUncollapse:nil];
}

@end
