#import "DWColor.h"
#import "DWIconCache.h"
#import "DWStripedTableView.h"
#import "DWMultiLevelCell.h"
#import "DWTableColumn.h"
#import "DWTableController.h"
#import "NSStringExtensions.h"
#import "Profile.h"


@implementation DWStripedTableView

/* Stripes */

    + (id) stripedBackgroundPatternWithHeight: (int) height; {
        id result = [[[NSImage alloc] initWithSize: (NSSize){height, 2*height}] autorelease];
        [result lockFocus];
            [[DWColor lightBlueColor] set];
            NSRectFill((NSRect){{0,0}, {height, height}});
            [[DWColor whiteColor] set];
            NSRectFill((NSRect){{0,height}, {height, height}});
        [result unlockFocus];
        return result;
    }


/* Initialization */

    static id lightBlue = nil;
    static id grey = nil;
    static id white = nil;
    static id alternate = nil;
    static id secondary = nil;
    static id alternateSeparator = nil;
    static id secondarySeparator = nil;
    
    - (id) init; 
    {
        self = [super init];
        
        /* initialize the colours */
        
        if (!lightBlue) 
        {
            grey = [[NSColor colorWithCalibratedRed: 0.850980 green: 0.850980 blue: 0.850980 alpha: 1.0] retain];

            white     = [DWColor whiteColor];
            lightBlue = [DWColor lightBlueColor];
            alternate = [DWColor alternateSelectedControlColor];
            secondary = [DWColor secondarySelectedControlColor];

            alternateSeparator = [[[DWColor alternateSelectedControlColor] blendedColorWithFraction: .14902 ofColor: [NSColor blackColor]] retain];
            secondarySeparator = [[[DWColor secondarySelectedControlColor] blendedColorWithFraction: .14902 ofColor: [NSColor blackColor]] retain];
        }
        
        return self;
    }
    
    - (void) awakeFromNib; {
        [self init];
    }


#pragma mark -
/* Draw */

    static inline void drawColumnSeparatorsWithColorInRect(NSTableView* self, NSColor* theColor, NSRect theRect) 
    {
        [theColor set];
        
        NSRect r = {
            {-1.0f, theRect.origin.y},
            {1.0f, theRect.size.height}
        };
        
        int i;
        id columns = [self tableColumns];
        int count = [columns count];

        for (i=0; i<count; i++) {
            r.origin.x += ([[columns objectAtIndex: i] width] + 3.0f);
            NSRectFill(r);
        }
    }

    static inline void tableViewDrawRowInRectWithBackgroundColorIndex(id delegate, id view, int row, NSRect rect, int dwColorIndex)
    {
        id cols = [view tableColumns];
        id obj = [delegate objectAtRow: row];

        unsigned i, count = [cols count];
        for (i=0; i<count; i++) 
        {
            DWTableColumn* col = (DWTableColumn*) [cols objectAtIndex: i];
            unsigned flags = col->flags;
            NSRect frame = NSIntersectionRect(rect, [view rectOfColumn: i ]);

            #define kDWImageCellTopMargin   1.0f
            #define kDWImageCellRightMargin 4.0f

            if ( flags & DWCachedImageValue || flags & DWImageAccessor || flags & DWIconValue ) {
            
                /* cached image fast path (fastest) */

                id value = [obj performSelector: col->sel];
                
                if ( flags & DWImageAccessor ) {
                    value = [value image];
                } else if ( flags & DWIconValue ) {
                    if (rect.size.width >= 32)
                        value = [[DWIconCache instance32] iconForFilePath: value];
                    else
                        value = [[DWIconCache instance16] iconForFilePath: value];
                }
                                
                id image = [value imageWithBackgroundColorIndex: dwColorIndex];
                NSSize imsize = [image size];
        
                NSRect drawRect = {
                    {frame.origin.x, frame.origin.y + kDWImageCellTopMargin},
                    {frame.size.width, imsize.height}
                };
        
                /* handle center-alignment case */
                
                if (flags & DWCenterAligned) {
                    if (imsize.width < drawRect.size.width) {
                        drawRect.origin.x += (int)((drawRect.size.width - imsize.width)/2.0f);
                    }
                } else {
                    drawRect.origin.x += 4.0f;
                    drawRect.size.width -= 6.0f;
                }

                NSRect sourceRect = {
                    {0.0f,0.0f},
                    drawRect.size
                };
        
                [image drawInRect: drawRect fromRect: sourceRect operation: NSCompositeCopy fraction: 1.0f];
                
            } else if (flags & DWTableStringValue) {

                /* DWTableString path (DWConfinedString) */
                
                id value = [obj performSelector: col->sel];
                
                NSRect theRect = frame;
                theRect.origin.y += 1;
                
                BOOL centered = (flags & DWCenterAligned);
                if (!centered) {
                    theRect.origin.x += 5;
                    theRect.size.width -= 5;
                }
                
                if (dwColorIndex == kDWColorAlternateIndex) {
                    [[value alternateString] drawInRect: theRect centered: centered];
                } else {
                    [value drawInRect: theRect centered: centered];
                }
                
            } else if (flags & DWTableCellValue) {

                /* DWTableCell path */
                /* Much of the preceeding code should/could be relocated using this mechanism, at the expense of one Objective-C method call per cell.  Is it worth it? */ 
                
                id value = (col->sel) ? [obj performSelector: col->sel] : obj;

                DWTableCell* cell = [col dataCell];
                cell->dwColorIndex = dwColorIndex;
                [cell setObjectValue: value];

                [cell drawWithFrame: frame inView: view];
                
            } else if (flags & DWMultiLevelCellValue) {
                
                /* DWMultiLevelCell path */
                
                DWMultiLevelCell* cell = [col dataCell];
                cell->dwColorIndex = dwColorIndex;
                
                id primary = [obj performSelector: col->primary];
                id secondary = [obj performSelector: col->secondary];
                
                [cell setPrimary: primary];
                [cell setSecondary: secondary];
                [cell setCenterAligned: (flags & DWCenterAligned)];

                [cell drawWithFrame: frame inView: view];
            
            } else {
                
                /* default path */

                id value = (col->sel) ? [obj performSelector: col->sel] : obj;
                
                id cell = [col dataCell];
                [cell setObjectValue: value];
              
                [cell drawWithFrame: frame inView: view];

            }
        }
    }
    
    #define rectOfRow(view, row) (NSRect) {				\
            {0.0f, row * (view->_rowHeight + 2.0f)},			\
            {view->_frame.size.width, (view->_rowHeight + 2.0f)}	\
        }
    
    - (void) drawRect: (NSRect) rect; 
    {
        if ([[self headerView] draggedColumn] > -1) {
            [super drawRect: rect];
            return;
        }
        
        id bgColor;
        int dwColorIndex;
        
        /* draw background & stripes */
            
            /* dangerous! (accessing _rowHeight & _delegate) */

            #if 0

                float dy = _rowHeight + 2.0f;
                
                if (!stripedBackgroundPattern) {
                    stripedBackgroundPattern = [[NSColor colorWithPatternImage: [DWStripedTableView stripedBackgroundPatternWithHeight: [self rowHeight]]] retain];
                }
                
                [stripedBackgroundPattern set];
                NSRectFill(rect);

            #else

                float dy = _rowHeight + 2.0f;
                float dy2 = 2.0f * dy;

                [white set];
                NSRectFill(rect);
    
                NSRect r = (NSRect){
                    rect.origin,
                    {rect.size.width, dy}
                };
                
                float max = rect.origin.y + rect.size.height;
                float y;
                
                [lightBlue set];
    
                for (y = dy2 * (int)(rect.origin.y/dy/2.0f); y<max; y += dy2) {
                    r.origin.y = y;
                    NSRectFill(r);
                }

            #endif
            
        /* draw column separators */
            
            drawColumnSeparatorsWithColorInRect(self, grey, rect);

        /* draw rows */
                    
            int i, count;
            i = floor(rect.origin.y/dy);
            count = MIN([self numberOfRows], ceil((rect.origin.y + rect.size.height)/dy));

            //NSLog(@"%i, %i", i, count);

            BOOL hasComputedFirstResponder = NO;
            BOOL isFirstResponder = NO;

            for (; i<count; i++) 
            {
                //NSRect rowRect = [self rectOfRow: i];
                NSRect rowRect = rectOfRow(self, i);
                rowRect.size.height -= 0.5f;
                
                /* draw background, if necessary */
                if ([self isRowSelected: i]) {

                    if (!hasComputedFirstResponder) {
                        id window = [self window];
                        isFirstResponder = [window firstResponder] == self && [window isKeyWindow];
                        hasComputedFirstResponder = YES;
                    }

                    if (isFirstResponder) {
                        bgColor = alternate;
                        dwColorIndex = kDWColorAlternateIndex;
                    } else {
                        bgColor = secondary;
                        dwColorIndex = kDWColorSecondaryIndex;
                    }

                    [bgColor set];
                    NSRectFill(rowRect);
                    
                    NSRect colRect = rowRect;
                    colRect.size.height -= 0.5f;

                    drawColumnSeparatorsWithColorInRect(self, (isFirstResponder) ? alternateSeparator : secondarySeparator, colRect);

                } else {

                    if (i % 2) {
                        dwColorIndex = kDWColorWhiteIndex;
                    } else {
                        dwColorIndex = kDWColorLightBlueIndex;
                    }

                }
                
                /* draw the row */

                    tableViewDrawRowInRectWithBackgroundColorIndex(_delegate, self, i, rowRect, dwColorIndex);
            }
    }
    

#pragma mark -
/* Resizing */

    #if 0
    - (void) sizeLastColumnToFit; {
        //NSLog(@"sizeLastColumnToFit");
    }
    
    - (void) tile; 
    {
        [super tile];

        id scrollView = [self enclosingScrollView];
        
        BOOL shouldHaveHorizontalScroller = (_frame.size.width > [scrollView documentVisibleRect].size.width);
        BOOL shouldChangeScroller = shouldHaveHorizontalScroller ^ [scrollView hasHorizontalScroller];

        if (shouldChangeScroller) {
            [scrollView setHasHorizontalScroller: shouldHaveHorizontalScroller];
            [[scrollView contentView] viewFrameChanged: nil];
        }

        //[[self cornerView] setFrameOrigin: (NSPoint){[[self cornerView] frame].origin.x, 0}];
        //[[scrollView verticalScroller] setFrameOrigin: (NSPoint){[[scrollView verticalScroller] frame].origin.x, 17}];
    }
    #endif
    
@end