#import "DWCustomizableTableView.h"
#import "DWTableColumn.h"
#import "DWUtil.h"
#import "Profile.h"

#define DEFAULTS_IDENTIFIERS @"DWCustomizableTableView_Identifiers"
#define DEFAULTS_WIDTHS	     @"DWCustomizableTableView_Widths"


@implementation DWCustomizableTableView

/* Initialization */

    - (void) awakeFromNib; {
        [super awakeFromNib];
        [self init];
    }
    
    - (id) init; 
    {
        self = [super init];
        
        autosavesColumns = YES;
            
        /* table */
            
            if ([[self dataSource] respondsToSelector: @selector(initColumns)])
                [[self dataSource] initColumns];
        
            [self setHeaderView: [[DWCustomizableTableHeaderView alloc] initWithFrame: [[self headerView] frame]]];
        
        /* corner view */
        
            corner = [[DWCustomizableCornerView alloc] initWithFrame: [[self cornerView] frame]];
                [corner setPullsDown: YES];
                [corner setTableView: self];
            [self setCornerView: corner];
        
        return self;
    }


#pragma mark -
/* Customization Menu */

    - (NSMenu*) customizationMenuWithNullFirstElement: (BOOL) nullFirstElement;
    {
        NSArray* columns = [[self availableTableColumns] retain];
        NSMenu* menu = [[NSMenu alloc] initWithTitle: @"nil"];
        NSMenuItem* menuItem;
        unsigned i;
        BOOL optionalItem;
        
        if (nullFirstElement) {
            /* a null item to be ignored (popupmenu -> ispulldown) */
            [menu addItem: [NSMenuItem separatorItem]];
        }

        /* the columns themselves */
        for (i=0; i<[columns count]; i++) 
        {
            id tableColumn = [columns objectAtIndex: i];
            
            if ([[self dataSource] respondsToSelector: @selector(isColumn:requiredInTableView:)]) {
                optionalItem = ![[self dataSource] isColumn: tableColumn requiredInTableView: self];
            } else {
                optionalItem = YES;
            }
            
            menuItem = [[NSMenuItem alloc] initWithTitle: [tableColumn menuTitle] action: @selector(toggleColumnVisibility:) keyEquivalent: @""];
    
            if (optionalItem) {
                [menuItem setTarget: self];
                [menuItem setRepresentedObject: tableColumn];
                [menuItem setState: ([self isColumnVisible: tableColumn]) ? NSOnState : NSOffState];
            } else {
                [menuItem setState: NSOnState];
            }

            [menu addItem: [menuItem autorelease]];
        }

        /* "reset to default" */
        [menu addItem: [NSMenuItem separatorItem]];
        menuItem = [[NSMenuItem alloc] initWithTitle: @"Reset To Default" action: @selector(loadDefaultColumns:) keyEquivalent: @""];
        [menuItem setTarget: self];
        [menu addItem: menuItem];

        [columns release];

        #ifdef DEBUG
        NSLog(@"customizationMenu: %@", menu);
        #endif
        
        return [menu autorelease];
    }
    
    - (void) toggleColumnVisibility: (id) sender; 
    {
        id tableColumn = [sender representedObject];
        if ([self isColumnVisible: tableColumn]) {
            /* hide it */
            [self removeTableColumn: tableColumn];
            [self saveColumnDefaultsIfNeeded: self];
        } else {
            /* show it */
            [self addTableColumn: tableColumn];
            [self saveColumnDefaultsIfNeeded: self];
        }
        [self sizeToFit];
    }


#pragma mark -
/* CUSTOM COLUMNS */
    
    - (NSArray*) availableTableColumns; 
    {
        if ([[self dataSource] respondsToSelector: @selector(columnsInTableView:)]) {
            return [[self dataSource] columnsInTableView: self];
        } else {
            return nil;
        }
    }
    
    - (BOOL) isColumnVisible: (id) column; {
        return [[self tableColumns] containsObject: column];
    }

    - (NSTableColumn*) tableColumnWithIdentifier: (id) object;
    {
        NSArray* available = [self availableTableColumns];
        int i, count = [available count];

        for (i=0; i<count; i++) {
            id column = [available objectAtIndex: i];
            if ([[column identifier] isEqual: object]) {
                return column;
            }
        }

        return nil;
    }
    
    
#pragma mark -
/* COLUMNS */
    
    - (void) removeAllTableColumns; {
        autosavesColumns = NO;
          while ([[self tableColumns] count]) {
            [self removeTableColumn: [[self tableColumns] objectAtIndex: 0]];
          }
        autosavesColumns = YES;
    }

    - (void) loadDefaultColumns: (id) sender; {
        [self loadDefaultColumns];
    }

    - (void) loadDefaultColumns; 
    {
        [self removeAllTableColumns];
        
        if ([[self dataSource] respondsToSelector: @selector(defaultColumnsInTableView:)]) 
        {
            NSArray* columns = [[self dataSource] defaultColumnsInTableView: self];
            unsigned i;
            for (i=0; i<[columns count]; i++) 
            {
                [self addTableColumn: [columns objectAtIndex: i]];
            }
        }
        [self sizeToFit];
    }


#pragma mark -
/* AUTOSAVE */

    - (NSString*) identifiersDefaultsKey; {
        return [NSString stringWithFormat: @"%@_%@", DEFAULTS_IDENTIFIERS, [self autosaveName]];
    }
    
    - (NSString*) widthsDefaultsKey; {
        return [NSString stringWithFormat: @"%@_%@", DEFAULTS_WIDTHS, [self autosaveName]];
    }

    - (void) setAutosaveName: (NSString*) name; {
        [super setAutosaveName: name];
        //NSLog(@"setAutosaveName 1: %@", [self tableColumns]);
        [self loadColumnsFromPreferences];
        //NSLog(@"setAutosaveName 2: %@", [self tableColumns]);
    }

    - (void) loadColumnsFromPreferences; 
    {
        if (autosavesColumns && [self autosaveName] && [self dataSource])
        {       
            /* STOP LISTENING */
            //[[NSNotificationCenter defaultCenter] removeObserver: self name: NSTableViewColumnDidResizeNotification object: self];
            [[NSNotificationCenter defaultCenter] removeObserver: self name: NSTableViewColumnDidMoveNotification object: self];
            
            {
                NSArray* columnIdentifiers = [defaults arrayForKey: [self identifiersDefaultsKey]];
                NSArray* columnWidths      = [defaults arrayForKey: [self widthsDefaultsKey]];
                NSMutableArray* columnsToAdd = [[NSMutableArray alloc] init];
                unsigned i;

                #ifdef DEBUG
                NSLog(@"Loading: %@", [self autosaveName]);
                NSLog(@"%@", columnIdentifiers);
                NSLog(@"%@", columnWidths);
                #endif
                
                for (i=0; i<[columnIdentifiers count]; i++) 
                {
                    id column = [self tableColumnWithIdentifier: [columnIdentifiers objectAtIndex: i]];
                    if (column) 
                    {
                        [column setWidth: [[columnWidths objectAtIndex: i] intValue]];
                        [columnsToAdd addObject: column];
                    }
                }
                
                if ([columnsToAdd count]) 	// *valid* prefs do indeed exist
                {
                    [self removeAllTableColumns];
                    
                    for (i=0; i<[columnsToAdd count]; i++) 
                    {
                        id column = [columnsToAdd objectAtIndex: i];
                        [self addTableColumn: column];
                    }
                }
                else
                {
                    [self loadDefaultColumns];
                }
                
                [self sizeToFit];
            }

            /* RESUME LISTENING */
            //[[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(saveColumnDefaultsIfNeeded:) name: NSTableViewColumnDidResizeNotification object: self];
            [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(saveColumnDefaultsIfNeeded:) name: NSTableViewColumnDidMoveNotification object: self];
        }
    }
    
    - (void) saveColumnDefaultsIfNeeded: (id) sender; 
    {
        if (autosavesColumns && [self autosaveName])
        {
            NSMutableArray* columnIdentifiers = [[NSMutableArray alloc] init];
            NSMutableArray* columnWidths      = [[NSMutableArray alloc] init];
            unsigned i;
            
            for (i=0; i<[[self tableColumns] count]; i++) 
            {
                id column = [[self tableColumns] objectAtIndex: i];
                [columnIdentifiers addObject: [column identifier]];
                [columnWidths	   addObject: [NSNumber numberWithFloat: [column width]]];
            }
            
            #ifdef DEBUG
            NSLog(@"Saving: %@ (%@)", [self autosaveName], sender);
            NSLog(@"%@", columnIdentifiers);
            //NSLog(@"%@", columnWidths);
            #endif

            [defaults setObject: columnIdentifiers forKey: [self identifiersDefaultsKey]];
            [defaults setObject: columnWidths forKey: [self widthsDefaultsKey]];
            
            [columnIdentifiers release];
            [columnWidths release];
        }
    }

@end



#pragma mark -
@implementation DWCustomizableTableHeaderView

    - (id) menuForEvent: (NSEvent*) event; {	
        return [(DWCustomizableTableView*)[self tableView] customizationMenuWithNullFirstElement: NO];
    }
    
@end



#pragma mark -
@implementation DWCustomizableCornerView

/* Initialization */
    
    static NSTableHeaderCell* headerCell;
    
    - (id) initWithFrame: (NSRect) frame; 
    {
        self = [super initWithFrame: frame];
        if (!headerCell) headerCell = [[NSTableHeaderCell alloc] init];
        return self;
    }

    
/* set... */

    - (void) setTableView: (id) view; {
        tableView = view;
    }
    

/* Mouse Down */
    
    - (void) mouseDown: (id) event; {
        [self setMenu: [tableView customizationMenuWithNullFirstElement: YES]];
        [super mouseDown: event];
    }
    
    
/* Draw */

    static NSImage* arrow;
    static NSImage* image[2];
        
    - (void) drawRect: (NSRect) rect;
    {
        /* do some correction */

            rect.origin.y = 0;
            rect.size.height = 17;
        
        BOOL highlighted = [[self cell] isHighlighted];
        int index = (highlighted) ? 1 : 0;
        
        if (image[index]) {
            [image[index] setFlipped: YES];
            [image[index] drawInRect: rect fromRect: NSZeroRect operation: NSCompositeCopy fraction: 1.0];
            return;
        }
        
        /* some further correction */

            rect.size.width += 1;
        
        if (!arrow) 
        {
            arrow = [[NSImage alloc] initWithSize: (NSSize){16,16}];
            [arrow setFlipped: YES];
            
            #define r 2.3
            #define y 6.5
            
            [arrow lockFocus];
            [[NSColor blackColor] set];

            [[NSBezierPath bezierPathWithOvalInRect: (NSRect){{2,  y}, {r,r}}] fill];
            [[NSBezierPath bezierPathWithOvalInRect: (NSRect){{6,  y}, {r,r}}] fill];
            [[NSBezierPath bezierPathWithOvalInRect: (NSRect){{10, y}, {r,r}}] fill];
                        
            #undef r
            #undef y

            [arrow unlockFocus];
        }
                
        /* draw background */

            [headerCell setState: (highlighted) ? NSOnState : NSOffState];
            //[headerCell drawWithFrame: rect inView: nil];
            //[headerCell setHighlighted: YES];
            //[headerCell setEnabled: YES];
            
            [headerCell highlight: YES withFrame: rect inView: nil];
            
    
        /* draw 'customize' widget */
            
            [arrow drawAtPoint: rect.origin fromRect: NSZeroRect operation: NSCompositeSourceOver fraction: 1.0];
    
        /* cache the result */
        
            image[index] = [[NSImage alloc] initWithFocusedViewRect: rect];
    }
    
@end