#pragma .h #import <Foundation/NSObject.h>
#pragma .h #import <Foundation/NSArray.h>
#pragma .h #import "IKIconObject.h"
#pragma .h #import "IKDependency.h"
#pragma .h @class IKAnnouncer;

#import <Foundation/NSArchiver.h>
#import <Foundation/NSUtilities.h>

#import <InterfaceBuilder/InterfaceBuilder.h>

#import "IKAnnouncer.h"
#import "IKfunctions.h"
#import "IKList.h"
#import "NSObject.LoadImage.h"

@implementation  IKList:NSObject
#pragma .h <IKDependency,IKDraggableObject>
#pragma .h {
#pragma .h 	NSMutableArray	*embeddedArray;
#pragma .h 	IKAnnouncer	*users;
#pragma .h }

static NSImage		* sheaf = nil;
static NSImage		* miniSheaf = nil;

+ (void)initialize
{
    if (self == [IKList class]) {
        IKInitIDpboardType();
        sheaf = [self loadImageFromBundle:@"IKSheaf"];
        miniSheaf = [self loadImageFromBundle:@"IKMiniSheaf"];
    }
}


- (NSImage *) getIBImage
{
	return sheaf;
}

- init
{
	return [self initCount:10];
}

- initCount: (unsigned int) numSlots
{
	if ((self = [super init]) != nil) {
		embeddedArray = [[NSMutableArray alloc] initWithCapacity:numSlots];
		users = [[IKAnnouncer alloc] initOwner: self];
	}
	return self;
}


- copyWithZone: (NSZone *) zone
{
	IKList *copy = NSCopyObject(self, 0, zone);
	
	if (copy) {
		copy->users = [[IKAnnouncer alloc] initOwner: copy];
		copy->embeddedArray = [embeddedArray copyWithZone:zone];
	}
	return copy;
}


- (void)dealloc
{
	NSMutableArray *usersAndListeners;

#if DEBUG
	NSLog(@"freeing list: %@\n", [self description]);
#endif
	[users  announce: @selector(willFree:)];
	usersAndListeners = [users usersAndListeners];
	[usersAndListeners removeAllObjects];
	[usersAndListeners addObject:self];
	[embeddedArray makeObjectsPerform:@selector(removeUser:) withObject: self];
	[users release];
	[super dealloc];
}

- (void)forwardInvocation:(NSInvocation *)anInvocation
{
    if(embeddedArray && [embeddedArray count] > 0) {
        id	target = [embeddedArray objectAtIndex:0];
        if ([target respondsToSelector:[anInvocation selector]]) {
            [anInvocation invokeWithTarget:target];
        }
    }
    [super forwardInvocation:anInvocation];
}

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
	if(embeddedArray && [embeddedArray count] > 0) {
		return [[embeddedArray objectAtIndex:0] methodSignatureForSelector:aSelector];
    }
	return [super methodSignatureForSelector:aSelector];
}

- (BOOL) respondsToSelector: (SEL) method
{
	if([super respondsToSelector:method]) {
		return YES;
	} else {
		if(embeddedArray && [embeddedArray count] > 0) {
			return [[embeddedArray objectAtIndex:0] respondsToSelector:method];
  	 	}
	}
	return NO;
}


- (id)initWithCoder:(NSCoder *)aDecoder
{
	embeddedArray = [aDecoder decodeObject];
	if(embeddedArray) {
		[embeddedArray retain];
	}
	users = [[IKAnnouncer alloc] initOwner:self];
	return self;
}

- (void)encodeWithCoder:(NSCoder *)aCoder
{
	[aCoder encodeObject:embeddedArray];
}

- (void)addUser: who		{	[users  addUser: who];			}
- (void)addListener: who	{	[users  addListener: who];		}
- (void)removeListener: who	{	[users  removeListener: who];	}


- (void)removeUser: who
{
	[users removeUser: who];
	if(		([users  numUsers] == 0)
		&&	[self  garbageCollect]
		&&  (![NSApp  conformsToProtocol: @protocol(IB)])) {
		[self release];
	}
}


- (BOOL) garbageCollect
{
	return YES;
}

- (NSString *)name
{
    if ([embeddedArray count] == 0)
        return nil;
    else if ([embeddedArray count] == 1)
        return [[embeddedArray objectAtIndex: 0] name];
    else
        return [NSString stringWithFormat:@"%d objects", [embeddedArray count]];
}

- (id)image
{
	if ([embeddedArray count] == 0)
		return nil;
	else if ([embeddedArray count] == 1)
		return [[embeddedArray objectAtIndex: 0] image];
	else
		return sheaf;
}


- (id)miniImage
{
	if ([embeddedArray count] == 0)
		return nil;
	else if ([embeddedArray count] == 1)
		return [[embeddedArray objectAtIndex:0] miniImage];
	else
		return miniSheaf;
}


- (NSString *)descrition
{
	int	numElements = [embeddedArray count];
	if (numElements == 0)
		return @"<empty IKList>";
	else if ([embeddedArray count] == 1)
		return [[embeddedArray objectAtIndex:0] descrition];
	else {
		return [NSString stringWithFormat:@"%d items", numElements];
	}
}


- (BOOL)isDraggable
{
	if ([embeddedArray count] == 0)
		return NO;
	else
		return [[embeddedArray objectAtIndex:0] isDraggable];
}

- (BOOL) isDragAccepting			{	return NO;	}
- (BOOL) isEditable					{	return NO;	}
- (void)setDraggable: (BOOL)flag;	{}


- (void)appendList: (NSArray *)objects
{
	if (![users poll: @selector(list:willAppendList:) with:objects])
		return;
	[users setSendAnnouncements: NO];
	[embeddedArray addObjectsFromArray: objects];
	[users setSendAnnouncements: YES];
	[users announce: @selector(list:didAppendList:) with:objects];
}


- (void)removeList: (NSArray *) objects
{
	if (![users  poll: @selector(list:willRemoveList:)  with:objects])
			return;
	
	[users  setSendAnnouncements: NO];
	[embeddedArray removeObjectsInArray:objects];
	[users  setSendAnnouncements: YES];
	[users  announce: @selector(list:didRemoveList:)  with:objects];
}

- (unsigned)count
{
	return [embeddedArray count];
}

- (id)objectAtIndex:(unsigned)i
{
	return [embeddedArray objectAtIndex:i];
}

- (void)addObject:anObject
{
	[embeddedArray addObject:anObject];
}

- insertObject: object  atIndex: (unsigned int) i
{
	if (![users  poll: @selector(list:willAdd:)  with:object])
			return nil;

	[embeddedArray insertObject:object atIndex:i];
	[object addUser: self];
	[users announce: @selector(list:didAdd:)  with:object];
	return self;
}


- (void)removeObjectAtIndex: (unsigned int) i
{
	id object = [embeddedArray objectAtIndex: i];
	
	if (![users  poll: @selector(list:willRemove:)  with:object])
		return;
	[embeddedArray removeObjectAtIndex: i];
	[object removeUser: self];
	[users announce: @selector(list:didRemove:) with:object];
}


- (void)willFree: who
{
	[embeddedArray removeObject:who];
}


+ (NSArray *) pasteTypes
{
	return IKIDPasteTypes();
}

- (void)copyToPasteboard: (NSPasteboard *) pboard
{
	IKCopyID (pboard, self);
}


+ readFromPasteboard: (NSPasteboard *) pboard;
{
	id object = IKReadID (pboard);
	return [object isKindOfClass: [self class]] ? object : nil;
}


@end


@implementation NSObject (IKListAnnouncements)
- (BOOL)list:sender  willAppendList: objects{	return YES;		}
- (BOOL)list:sender  willRemoveList: objects{	return YES;		}
- (BOOL)list:sender  willAdd: object		{	return YES;		}
- (BOOL)list:sender  willRemove:object		{	return YES;		}
- (void)list: sender didAppendList: objects	{	;				}
- (void)list: sender didRemoveList: objects	{	;				}
- (void)list: sender didAdd: object			{	;				}
- (void)list: sender didRemove: object		{	;				}
- (void)willFree: sender					{	;				}
@end
