//
//  NJRLabeledImageCell.m
//  HostLauncher
//
//  Created by nicholas on Wed Aug 01 2001.
//  Copyright (c) 2001 Nicholas Riley. All rights reserved.
//

/*

 F-Script Anywhere is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or
 (at your option) any later version.

 F-Script Anywhere is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with F-Script Anywhere; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

*/

#import "NJRLabeledImageCell.h"
#import "NSString-NJRExtensions.h"

const static float LEFT_PADDING = 3;

@implementation NJRLabeledImageCell

+ (NJRLabeledImageCell *)cell {
    return [[[self alloc] init] autorelease];
}

- (void)dealloc {
    [image release];
    [imageCacheSource release];
    image = nil;
    [super dealloc];
}

- copyWithZone:(NSZone *)zone {
    NJRLabeledImageCell *cell = [super copyWithZone:zone];
    cell->image = [image retain];
    return cell;
}

- (void)setImage:(NSImage *)anImage {
    if (anImage != image) {
        [image release];
        image = [anImage retain];
    }
}

- (NSImage *)image {
    return image;
}

- (void)setImageCacheSource:(id)aSource {
    if (aSource != imageCacheSource) {
        [imageCacheSource release];
        imageCacheSource = [aSource retain];
    }
}

- (NSRect)imageFrameForCellFrame:(NSRect)cellFrame {
    if (image != nil) {
        NSRect imageFrame;
        imageFrame.size = [image size];
        imageFrame.origin = cellFrame.origin;
        imageFrame.origin.x += LEFT_PADDING;
        imageFrame.origin.y += ceil((cellFrame.size.height - imageFrame.size.height) / 2);
        return imageFrame;
    }
    return NSZeroRect;
}

- (void)editWithFrame:(NSRect)aRect inView:(NSView *)controlView editor:(NSText *)textObj delegate:(id)anObject event:(NSEvent *)theEvent {
    NSRect textFrame, imageFrame;
    NSDivideRect(aRect, &imageFrame, &textFrame,
                 LEFT_PADDING + [image size].width, NSMinXEdge);
    [super editWithFrame: textFrame inView: controlView
           editor: textObj delegate: anObject event: theEvent];
}

- (void)selectWithFrame:(NSRect)aRect inView:(NSView *)controlView editor:(NSText *)textObj delegate:(id)anObject start:(int)selStart length:(int)selLength {
    NSRect textFrame, imageFrame;
    NSDivideRect(aRect, &imageFrame, &textFrame, LEFT_PADDING + [image size].width,
                 NSMinXEdge);
    [super selectWithFrame: textFrame inView: controlView editor:textObj delegate:anObject start:selStart length:selLength];
}

- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView {
    if (image != nil) {
        NSSize	imageSize;
        NSRect	imageFrame;
        NSImageRep *preferredRep, *rep;

        imageSize = NSMakeSize(cellFrame.size.height - 1, cellFrame.size.height - 1);

        preferredRep = [[[imageCacheSource cachedImage] representations] objectAtIndex: 0];
        if (preferredRep != nil && abs([preferredRep size].width - imageSize.width) < 1 && abs([preferredRep size].height != imageSize.height) < 1) {
            [self setImage: [imageCacheSource cachedImage]];
            // FSALog(@"%@ accepting cached image: %@", [self stringValue], preferredRep);
        } else {
            NSArray	*imageReps = [image representations];
            int		i, repCount = [imageReps count];
            NSSize	repSize;
            
            preferredRep = [imageReps objectAtIndex: 0];
            // FSALog(@"%@ rejecting cached image: %@", [self stringValue], preferredRep);
            for (i = 1 ; i < repCount ; i++) {
                rep = [imageReps objectAtIndex: i];
                repSize = [rep size];
                if (repSize.width == imageSize.width && repSize.height == imageSize.height) {
                    preferredRep = rep;
                    break;
                }
                if (repSize.width >= imageSize.width || repSize.height >= imageSize.height) {
                    // pick the smallest of the larger representations
                    if (repSize.width <= [preferredRep size].width ||
                        repSize.height <= [preferredRep size].height) preferredRep = rep;
                } else {
                    // or the largest of the smaller representations
                    if (repSize.width >= [preferredRep size].width ||
                        repSize.height >= [preferredRep size].height) preferredRep = rep;
                }
            }
            /* // Working code as of OS X 10.0.4; this breaks in 10.1
                for (i = repCount - 1 ; i >= 0 ; i--) {
                    rep = [imageReps objectAtIndex: i];
                    if (rep != preferredRep) {
                        [image removeRepresentation: rep];
                    }
                }
            // End working code
            */
            // Begin workaround code for bug in OS X 10.1 (removeRepresentation: has no effect)
            if ([preferredRep size].width > imageSize.width || [preferredRep size].height > imageSize.height) {
                NSImage *scaledImage = [[NSImage alloc] initWithSize: imageSize];
                NSRect rect = { NSZeroPoint, imageSize };
                FSALog(@"rescaling %@", [self stringValue]);
                [scaledImage setFlipped: [controlView isFlipped]]; // XXX this works, but is correct?
                [scaledImage lockFocus];
                [preferredRep drawInRect: rect];
                [scaledImage unlockFocus];
                [image release];
                image = scaledImage;
            } else if (repCount > 1) {
                NSImage *sizedImage = [[NSImage alloc] initWithSize: [preferredRep size]];
                [sizedImage addRepresentation: preferredRep];
                [image release];
                image = sizedImage;
            }
            // End workaround code
        }
        
        NSDivideRect(cellFrame, &imageFrame, &cellFrame,
                     LEFT_PADDING + imageSize.width, NSMinXEdge);
        if ([self drawsBackground]) {
            [[self backgroundColor] set];
            NSRectFill(imageFrame);
        }
        imageFrame.origin.x += LEFT_PADDING;
        imageFrame.size = imageSize;

        imageFrame.origin.y += ceil((cellFrame.size.height +
                                     ([controlView isFlipped] ? -1 : 1) *
                                        imageFrame.size.height - 2) / 2);
        if ([image isFlipped] != [controlView isFlipped])
            [image setFlipped: [controlView isFlipped]];
        [image drawInRect: imageFrame
            fromRect: NSOffsetRect(imageFrame, -imageFrame.origin.x, -imageFrame.origin.y)
            operation: NSCompositeSourceOver fraction: 1.0];
        [imageCacheSource setCachedImage: image];
    }
    [self setAttributedStringValue:
        [[self stringValue] asAttributedStringTruncatedToWidth: cellFrame.size.width - 4]];
    [self setImageCacheSource: nil]; // without this, we crash (multiple cells get created!)
    [super drawWithFrame: cellFrame inView: controlView];
}

- (NSSize)cellSize {
    NSSize cellSize = [super cellSize];
    cellSize.width += (image ? [image size].width : 0) + LEFT_PADDING;
    return cellSize;
}

@end
