#pragma .h #import <Foundation/NSString.h>
#pragma .h #import "IKIconPath.h"
#pragma .h #import "IKDependency.h"
#pragma .h
#pragma .h @interface NSObject (IKShelfAnnouncements)
#pragma .h + (unsigned int) shelf: sender  willDrag: objectToPaste from: (id <NSDraggingInfo>) source;
#pragma .h + shelf: sender  dragWillEnter:         (id <NSDraggingInfo>) source;
#pragma .h + shelf: sender  dragWillExit:          (id <NSDraggingInfo>) source;
#pragma .h + shelf: sender  dragWillComplete:      (id <NSDraggingInfo>) source;
#pragma .h @end
#pragma .h 

#import <AppKit/AppKit.h>
#import <InterfaceBuilder/InterfaceBuilder.h>
#import <objc/objc-runtime.h>

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

@implementation IKShelf:IKIconPath 
#pragma .h <IKDependency>
#pragma .h {
#pragma .h 		id		 users,
#pragma .h 				 objectToPaste;
#pragma .h 	
#pragma .h 		NSString *classToHold;
#pragma .h 		BOOL	 dynamic,
#pragma .h 				 lastIsEmptyContainer;
#pragma .h }

static NSImage		* folder = nil;
static NSSize		defaultCellSize = { 70.0, 74.0 };


+ (void)initialize
{
    if (self == [IKShelf  class]) {
        IKInitIDpboardType();
        folder = [self loadImageFromBundle:@"IKFolder"];
    }
}


- (NSString *) inspectorClassName
{
    return ([[NSApp currentEvent] modifierFlags] & NSAlternateKeyMask) ? [super inspectorClassName] : @"IKShelfInspector";
}


/* ========================================================================== */


- initWithFrame:(NSRect)frameRect
{
    if ((self = [self  initWithFrame:frameRect mode: NSHighlightModeMatrix
                           cellClass: [IKCell  class]
                        numberOfRows: 0
                     numberOfColumns: 0]) != nil) {
        IKCell *aCell = [[IKCell alloc] init];
        [aCell setLocked: YES];
        [aCell setReallyLocked: NO];
        [aCell setContainer: YES];
        [self  setPrototype:aCell];
        if ([NSApp  conformsTo: @protocol(IB)]) {
            id newVar = [self prototype];
            [newVar setTitle:@"IconKit"];
            [newVar setImage:folder];
        }
        [self fillWithCells];
        [self sizeToCells];
    }
    return self;
}


- initWithFrame:(NSRect)frameRect mode:(int)aMode cellClass:class numberOfRows:(int)rows numberOfColumns:(int)cols
{
    if ((self = [super initWithFrame:frameRect mode:aMode cellClass:class numberOfRows:rows numberOfColumns:cols]) != nil) {
        users = [[IKAnnouncer  alloc]  initOwner: self];
        objectToPaste = nil;
        lastIsEmptyContainer = NO;
        dynamic = YES;
        [self setAutosizesCells:NO];
        [self setClassToHold: @""];
        [self setCellSize: defaultCellSize];
        [self sizeCellsToFit];
    }

    return self;
}


- (void)dealloc
{
    [self unregisterDraggedTypes];
    [users  announce: @selector(willFree:)];
    [users release];
    [super dealloc];
}


/* ========================================================================== */


- (id)initWithCoder:(NSCoder *)aDecoder
{
    char * name;

    [super initWithCoder:aDecoder];

    users = [[IKAnnouncer  alloc]  initOwner: self];
    [aDecoder decodeValuesOfObjCTypes:"*c", &name, &dynamic];
    [self  setPrototype: [[aDecoder decodeObject] retain]];
    [self  setClassToHold:[NSString stringWithCString:name]];
    free(name);

    return self;
}


- (void)encodeWithCoder:(NSCoder *)aCoder
{
    const char *className = [classToHold cString];
    [super encodeWithCoder:aCoder];
    [aCoder encodeValuesOfObjCTypes:"*c", &className, &dynamic];
    [aCoder encodeObject:[self  prototype]];
}


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


- (BOOL) isDynamic		{	return dynamic;						}
- (NSString *) classToHold	{	return classToHold;					}
- setDynamic: (BOOL) flag	{	dynamic = flag; return self;		}


- (void)setClassToHold: (NSString *) name
{
    NSArray	* pasteTypes;
    id	class;

    if (classToHold)
        [classToHold release];
    classToHold = name ? [name retain] : NULL;
    class = classToHold ? objc_lookUpClass([name cString]) : nil;
    pasteTypes =
        classToHold == NULL ? NULL:
        [class respondsTo: @selector(pasteTypes)] ? [class  pasteTypes]:
        [classToHold length] == 0 ? IKIDPasteTypes():
        NULL;

    if (pasteTypes != NULL) {
        [self unregisterDraggedTypes];
        [self registerForDraggedTypes:pasteTypes];
    }
}


- delegate
{
    return [[self selectedCell]  delegate];
}



- (void)setFrameSize:(NSSize)_newSize
{
    [super setFrameSize:(NSSize)_newSize];
    if (dynamic)
        [[self  fillWithCells]  sizeCellsToFit];
}


- fillWithCells
{
    int rows = [self frame].size.height / [self cellSize].height,
        cols = [self frame].size.width  / [self cellSize].width;

    [self renewRows:rows columns:cols];
    [self  sizeCellsToFit];
    return self;
}


- sizeCellsToFit
{
    NSSize gap;

    gap.height = _numRows > 1 ?
        ([self frame].size.height - [self cellSize].height * _numRows) / (_numRows - 1) : 0.0;
    gap.width  = _numCols > 1 ?
        ([self frame].size.width  - [self cellSize].width  * _numCols) / (_numCols - 1) : 0.0;

    [self  setIntercellSpacing:gap];
    return self;
}


- (void)mouseDown:(NSEvent *)event 
{
    [super mouseDown:event];
    if ([self  mode] == NSHighlightModeMatrix) {
        [[self selectedCell] setState:0];
        [self  drawCell: [self selectedCell]];
        [self selectCellAtRow:-1 column:-1];
    }
}


- (unsigned int) draggingOperation: (id <NSDraggingInfo>) sender
{
	id
		delegates = [users  usersAndListeners],
		who;
	int
		i = [delegates  count];
	
	while (i--) {
		who = [delegates objectAtIndex: i];
		if ([who  respondsToSelector: @selector(shelf:willDrag:from:)])
				return [who  shelf: self  willDrag: objectToPaste from: sender];
	}
	
	return	objectToPaste != nil ?
				NSDragOperationAll:
				NSDragOperationNone;
}


- (unsigned int) draggingEntered: (id <NSDraggingInfo>) sender
{
    id class;

    [users  announce: @selector(shelf: dragWillEnter:)  with: sender];
    lastIsEmptyContainer = NO;
    class = classToHold ? objc_lookUpClass([classToHold cString]) : nil;

    objectToPaste =
        class && [class respondsTo: @selector(readFromPasteboard:)]
            ? [class readFromPasteboard: [sender  draggingPasteboard]]
            : IKReadID ([sender draggingPasteboard]);

    [objectToPaste  addUser: self];

    return [super  draggingEntered: sender];
}


- (void)draggingExited:(id <NSDraggingInfo>)sender
{
    [users  announce: @selector(shelf: dragWillExit:)  with: sender];
    [objectToPaste removeUser:self];
    [super draggingExited:sender];
}


- (unsigned int) cellEntered: (id <NSDraggingInfo>) sender
{
    unsigned int op;

    if (    [current  isEmptyContainer]
         && ((op = [self  draggingOperation: sender]) != NSDragOperationNone)) {
        [current  setGhosted: YES];
        [current setDelegate:objectToPaste];
        [self drawCell:current];
        lastIsEmptyContainer = YES;
        return op;
    } else {
        return [super  cellEntered: sender];
    }
}


- (unsigned int) cellUpdated: (id <NSDraggingInfo>) sender
{
	return lastIsEmptyContainer ?
				[self  draggingOperation: sender]:
				[super  cellUpdated: sender];
}


- (void)cellExited:(id <NSDraggingInfo>)sender
{
    if (lastIsEmptyContainer) {
        if(last) {
            [last setGhosted: NO];
            [last setDelegate:nil];
            [self drawCell:last];
        }
        lastIsEmptyContainer = NO;
    } else {
       [super cellExited:sender];
    }
}


- (BOOL) prepareForDragOperation: (id <NSDraggingInfo>) sender
{
    return !lastIsEmptyContainer ? [super  prepareForDragOperation: sender] : YES;
}


- (BOOL) performDragOperation: (id <NSDraggingInfo>) sender
{
    [objectToPaste  removeUser: self];
    objectToPaste = nil;
    if (lastIsEmptyContainer) {
        [current  setGhosted: NO];
        [self drawCell:current];
    }
    return !lastIsEmptyContainer ? [super  performDragOperation: sender] : YES;
}


- (void)concludeDragOperation:(id <NSDraggingInfo>)sender
{
    [users  announce:  @selector(shelf:dragWillComplete:)];
    return !lastIsEmptyContainer ? [super concludeDragOperation:sender] : nil;
}


@end
