/*
SRPrefView.m

Author: Makoto Kinoshita

Copyright 2004-2006 The Shiira Project. All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted 
provided that the following conditions are met:

  1. Redistributions of source code must retain the above copyright notice, this list of conditions 
  and the following disclaimer.

  2. Redistributions in binary form must reproduce the above copyright notice, this list of 
  conditions and the following disclaimer in the documentation and/or other materials provided 
  with the distribution.

THIS SOFTWARE IS PROVIDED BY THE SHIIRA PROJECT ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE SHIIRA PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
POSSIBILITY OF SUCH DAMAGE.
*/

#import "SRPrefView.h"

// Notification
NSString*   SRPrefViewPreferenceSelected = @"SRPrefViewPreferenceSelected";

// Constant
int SRPrefColumnNumber = 6;

@implementation SRPrefView

//--------------------------------------------------------------//
#pragma mark -- Initialize --
//--------------------------------------------------------------//

- (id)initWithFrame:(NSRect)frame
{
    self = [super initWithFrame:frame];
    if (!self) {
        return nil;
    }
    
    // Initialize instance variables
    _buttons = [[NSMutableArray array] retain];
    _textFields = [[NSMutableArray array] retain];
    _prefInfos = [[NSMutableArray array] retain];
    _width = frame.size.width;
    
    return self;
}

- (void)dealloc
{
    [_buttons release], _buttons = nil;
    [_textFields release], _textFields = nil;
    [_prefInfos release], _prefInfos = nil;
    [_prefBundleIds release];
    [_prefIcons release];
    [_prefLabels release];
    
    [super dealloc];
}

//--------------------------------------------------------------//
#pragma mark -- Preference info --
//--------------------------------------------------------------//

- (void)addPreferenceIds:(NSArray*)prefIds 
        icons:(NSArray*)prefIcons 
        labels:(NSArray*)prefLabels 
        forLabel:(NSString*)label
{
    // Create pref info
    NSMutableDictionary*    prefInfo;
    prefInfo = [NSMutableDictionary dictionary];
    [prefInfo setObject:prefIcons forKey:@"prefIcons"];
    [prefInfo setObject:prefLabels forKey:@"prefLabels"];
    [prefInfo setObject:prefIds forKey:@"prefIds"];
    [prefInfo setObject:label forKey:@"label"];
    
    // Add pref info
    [_prefInfos addObject:prefInfo];
    
    // Update layout
    [self createButtons];
    [self updateButtonsLayout];
}

- (void)setPreferenceIds:(NSArray*)prefIds icons:(NSArray*)prefIcons labels:(NSArray*)prefLabels
{
    // Copy preference info
    [_prefBundleIds release];
    _prefBundleIds = [[NSArray arrayWithArray:prefIds] retain];
    [_prefIcons release];
    _prefIcons = [[NSArray arrayWithArray:prefIcons] retain];
    [_prefLabels release];
    _prefLabels = [[NSArray arrayWithArray:prefLabels] retain];
    
    // Update layout
    [self createButtons];
    [self updateButtonsLayout];
}

//--------------------------------------------------------------//
#pragma mark -- Layout --
//--------------------------------------------------------------//

- (void)createButtons
{
    // Remove all subviews
    [[self subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)];
    [_buttons removeAllObjects];
    [_textFields removeAllObjects];
    
    // Enumerate pref infos
    NSEnumerator*           enumerator;
    NSMutableDictionary*    prefInfo;
    enumerator = [_prefInfos objectEnumerator];
    while (prefInfo = [enumerator nextObject]) {
        // Get pref info
        NSArray*    prefIds;
        NSArray*    prefIcons;
        NSArray*    prefLabels;
        prefIds = [prefInfo objectForKey:@"prefIds"];
        prefIcons = [prefInfo objectForKey:@"prefIcons"];
        prefLabels = [prefInfo objectForKey:@"prefLabels"];
        
        // Create array
        NSMutableArray* buttons;
        NSMutableArray* textFields;
        buttons = [NSMutableArray array];
        textFields = [NSMutableArray array];
        [prefInfo setObject:buttons forKey:@"buttons"];
        [prefInfo setObject:textFields forKey:@"textFields"];
        
        int i;
        for (i = 0; i < [prefIds count]; i++) {
            //
            // Create button
            //
            
            // Get image
            NSImage*    image;
            image = [prefIcons objectAtIndex:i];
            
            // Get bundle ID
            NSString*   bundleId;
            bundleId = [prefIds objectAtIndex:i];
            
            // Create button
            NSButton*   button;
            button = [[NSButton alloc] initWithFrame:NSZeroRect];
            [button setButtonType:NSMomentaryChangeButton];
            if (![image isEqual:[NSNull null]]) {
                [button setImage:image];
            }
            [button setImagePosition:NSImageOnly];
            [button setBordered:NO];
            [[button cell] setRepresentedObject:bundleId];
            [button setTarget:self];
            [button setAction:@selector(selectPreferenceAction:)];
            
            [self addSubview:button];
            [buttons addObject:button];
            [button release];
            
            //
            // Create text field
            //
            
            // Get label
            NSString*   label;
            label = [prefLabels objectAtIndex:i];
            
            // Create text field
            NSTextField*    textField;
            textField = [[NSTextField alloc] initWithFrame:NSZeroRect];
            [textField setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]];
            [textField setAlignment:NSCenterTextAlignment];
            [textField setBordered:NO];
            [textField setEditable:NO];
            [textField setSelectable:NO];
            [textField setDrawsBackground:NO];
            if (![label isEqual:[NSNull null]]) {
                [textField setStringValue:label];
            }
            
            [self addSubview:textField];
            [textFields addObject:textField];
            [textField release];
        }
    }
}

static float    SRPrefViewXMargin = 8.0f;
static float    SRPrefViewYMargin = 8.0f;
static float    SRPrefViewButtonSize = 32.0f;
static float    SRPrefViewTextFieldWidth = 88.0f;
static float    SRPrefViewTextFieldHeight = 36.0f;
static float    SRPrefViewYMarginBetweenButtonAndText = 8.0f;
static float    SRPrefViewLabelHeight = 24.0f;

- (void)updateButtonsLayout
{
    // Decide column and row
    NSEnumerator*   enumerator;
    NSDictionary*   prefInfo;
    int             column, row = 0;
    column = (_width - SRPrefViewYMargin) / (SRPrefViewTextFieldWidth + SRPrefViewYMargin);
    enumerator = [_prefInfos objectEnumerator];
    while (prefInfo = [enumerator nextObject]) {
        // Get buttons
        NSArray*    buttons;
        buttons = [prefInfo objectForKey:@"buttons"];
        
        // Decide row
        row += [buttons count] / column + ([buttons count] % column > 0 ? 1 : 0);
    }
    
    // Set frame
    NSRect  frame;
    frame.origin = NSZeroPoint;
    frame.size.width = _width;
    frame.size.height = (SRPrefViewYMargin + SRPrefViewButtonSize + 
            SRPrefViewYMarginBetweenButtonAndText + SRPrefViewTextFieldHeight) * row - 1 + 
            [_prefInfos count] * SRPrefViewLabelHeight;
    [self setFrame:frame];
    
    // Set start position
    float   x, y;
    x = SRPrefViewXMargin;
    y = frame.size.height - SRPrefViewYMargin - SRPrefViewLabelHeight;
    
    // Update layout
    enumerator = [_prefInfos objectEnumerator];
    while (prefInfo = [enumerator nextObject]) {
        // Get buttons and text fields
        NSArray*    buttons;
        NSArray*    textFields;
        buttons = [prefInfo objectForKey:@"buttons"];
        textFields = [prefInfo objectForKey:@"textFields"];
        
        int i;
        for (i = 0; i < [buttons count]; i++) {
            // Get button and text field
            NSButton*       button;
            NSTextField*    textField;
            button = [buttons objectAtIndex:i];
            textField = [textFields objectAtIndex:i];
            
            // Decide button frame
            NSRect  buttonFrame;
            buttonFrame.origin.x = x + (SRPrefViewTextFieldWidth - SRPrefViewButtonSize) / 2.0f;
            buttonFrame.origin.y = y - SRPrefViewButtonSize;
            buttonFrame.size.width = SRPrefViewButtonSize;
            buttonFrame.size.height = SRPrefViewButtonSize;
            
            [button setFrame:buttonFrame];
            
            // Decide text field frame
            NSRect  textFrame;
            textFrame.origin.x = x;
            textFrame.origin.y = y - SRPrefViewButtonSize - 
                    SRPrefViewYMarginBetweenButtonAndText - SRPrefViewTextFieldHeight;
            textFrame.size.width = SRPrefViewTextFieldWidth;
            textFrame.size.height = SRPrefViewTextFieldHeight;
            
            [textField setFrame:textFrame];
            
            // Move position
            x += SRPrefViewTextFieldWidth + SRPrefViewXMargin;
            
            // Check wrap
            if (x + SRPrefViewTextFieldWidth + SRPrefViewXMargin > frame.size.width) {
                x = SRPrefViewXMargin;
                y -= SRPrefViewButtonSize + SRPrefViewYMarginBetweenButtonAndText + 
                        SRPrefViewTextFieldHeight + SRPrefViewYMargin;
            }
        }
        
        // Set next position
        x = SRPrefViewXMargin;
        y -= SRPrefViewButtonSize + SRPrefViewYMarginBetweenButtonAndText + 
                SRPrefViewTextFieldHeight + SRPrefViewYMargin + SRPrefViewLabelHeight;
    }
}

//--------------------------------------------------------------//
#pragma mark -- Action --
//--------------------------------------------------------------//

- (void)selectPreferenceAction:(id)sender
{
    // Get bundle ID
    NSString*   bundleId;
    bundleId = [[sender cell] representedObject];
    if (!bundleId) {
        return;
    }
    
    // Notify preference selection
    NSDictionary*   userInfo;
    userInfo = [NSDictionary dictionaryWithObjectsAndKeys:
            bundleId, @"bundleID", nil];
    [[NSNotificationCenter defaultCenter] 
            postNotificationName:SRPrefViewPreferenceSelected object:self userInfo:userInfo];
}

//--------------------------------------------------------------//
#pragma mark -- Drawing --
//--------------------------------------------------------------//

- (void)drawRect:(NSRect)rect
{
    // Fill with window background
    NSDrawWindowBackground(rect);
    
    // Get frame
    NSRect  frame;
    frame = [self frame];
    
    // Prepare background color
    static NSColor* _altBackgroundColor = nil;
    static NSColor* _altGridColor = nil;
    if (!_altBackgroundColor) {
        _altBackgroundColor = [[[NSColor blackColor] colorWithAlphaComponent:0.05f] retain];
        _altGridColor = [[[NSColor blackColor] colorWithAlphaComponent:0.1f] retain];
    }
    
#if 1
    // Create attributes
    static NSDictionary*    _labelAttr = nil;
    if (!_labelAttr) {
        _labelAttr = [[NSDictionary dictionaryWithObjectsAndKeys:
                [NSFont boldSystemFontOfSize:[NSFont systemFontSize]], NSFontAttributeName, 
                nil] retain];
    }
    
    // Decide column
    int column;
    column = (_width - SRPrefViewYMargin) / (SRPrefViewTextFieldWidth + SRPrefViewYMargin);
    
    NSRect  fillRect;
    BOOL    alt = NO;
    fillRect.size.width = frame.size.width;
    fillRect.size.height = 0;
    fillRect.origin.x = 0;
    fillRect.origin.y = frame.origin.y + frame.size.height;
    
    int i;
    for (i = 0; i < [_prefInfos count]; i++) {
        // Get pref info
        NSDictionary*   prefInfo;
        prefInfo = [_prefInfos objectAtIndex:i];
        
        //
        // Draw label
        //
        
        // Get label
        NSString*   label;
        label = [prefInfo objectForKey:@"label"];
        if (label) {
            // Create attributed string
            NSAttributedString* attrStr;
            attrStr = [[NSAttributedString alloc] initWithString:label attributes:_labelAttr];
            
            // Draw label
            NSPoint point;
            point.x = 8;
            point.y = fillRect.origin.y - 4 - [attrStr size].height;
            [attrStr drawAtPoint:point];
            [attrStr release];
        }
        
        //
        // Draw background
        //
        
        // Get buttons
        NSArray*    buttons;
        buttons = [prefInfo objectForKey:@"buttons"];
        
        // Decide row
        int row;
        row = [buttons count] / column + ([buttons count] % column > 0 ? 1 : 0);
        
        // Decide frame height
        fillRect.size.height = (SRPrefViewYMargin + SRPrefViewButtonSize + 
                SRPrefViewYMarginBetweenButtonAndText + SRPrefViewTextFieldHeight) * row + 
                SRPrefViewLabelHeight;
        fillRect.origin.y -= fillRect.size.height;
        
        // Fill with alternate color
        if (alt) {
            [_altBackgroundColor set];
            NSRectFillUsingOperation(fillRect, NSCompositeSourceOver);
            
            [_altGridColor set];
            
            NSRect  gridRect;
            gridRect.origin.x = fillRect.origin.x;
            gridRect.origin.y = fillRect.origin.y;
            gridRect.size.width = fillRect.size.width;
            gridRect.size.height = 1.0f;
            NSRectFillUsingOperation(gridRect, NSCompositeSourceOver);
            
            gridRect.origin.x = fillRect.origin.x;
            gridRect.origin.y = fillRect.origin.y + fillRect.size.height;
            gridRect.size.width = fillRect.size.width;
            gridRect.size.height = 1.0f;
            NSRectFillUsingOperation(gridRect, NSCompositeSourceOver);
        }
        
        alt = !alt;
    }
#else
    // Fill background
    NSRect  fillRect;
    BOOL    alt = NO;
    fillRect.size.width = frame.size.width;
    fillRect.size.height = SRPrefViewYMargin + SRPrefViewButtonSize + 
            SRPrefViewYMarginBetweenButtonAndText + SRPrefViewTextFieldHeight;
    fillRect.origin.x = 0;
    fillRect.origin.y = frame.origin.y + frame.size.height - fillRect.size.height;
    while (fillRect.origin.y + fillRect.size.height > 0) {
        if (NSIntersectsRect(rect, frame)) {
            if (alt) {
                [_altBackgroundColor set];
                NSRectFillUsingOperation(fillRect, NSCompositeSourceOver);
                
                [_altGridColor set];
                
                NSRect  gridRect;
                gridRect.origin.x = fillRect.origin.x;
                gridRect.origin.y = fillRect.origin.y;
                gridRect.size.width = fillRect.size.width;
                gridRect.size.height = 1.0f;
                NSRectFillUsingOperation(gridRect, NSCompositeSourceOver);
                
                gridRect.origin.x = fillRect.origin.x;
                gridRect.origin.y = fillRect.origin.y + fillRect.size.height;
                gridRect.size.width = fillRect.size.width;
                gridRect.size.height = 1.0f;
                NSRectFillUsingOperation(gridRect, NSCompositeSourceOver);
            }
        }
        
        fillRect.origin.y -= fillRect.size.height;
        alt = !alt;
    }
#endif
}

@end
