// Copyright 1997-2000 Omni Development, Inc.  All rights reserved.
//
// This software may only be used and reproduced according to the
// terms in the file OmniSourceLicense.html, which should be
// distributed with this project and can also be found at
// http://www.omnigroup.com/DeveloperResources/OmniSourceLicense.html.

#import "OHFormSelectMultiple.h"

#import <Foundation/Foundation.h>
#import <AppKit/AppKit.h>
#import <OmniBase/OmniBase.h>
#import <OmniFoundation/OmniFoundation.h>
#import <OmniAppKit/OmniAppKit.h>

#import "OHFormSelectOption.h"
#import "OHFormValue.h"

RCS_ID("$Header: /Network/Source/CVS/OmniGroup/Frameworks/OmniHTML/Forms.subproj/OHFormSelectMultiple.m,v 1.10 2000/01/20 00:27:52 kc Exp $")

@implementation OHFormSelectMultiple

- initWithForm:(OHForm *)aForm name:(NSString *)aName options:(NSArray *)someOptions visibleRows:(unsigned int)aRowCount allowMultiple:(BOOL)shouldAllowMultiple;
{
    if (![super initWithForm:aForm name:aName options:someOptions])
	return nil;

    visibleRows = aRowCount;
    allowMultiple = shouldAllowMultiple;

    return self;
}

- (void)dealloc;
{
    [scrollView release];
    [matrix release];
    [super dealloc];
}

- (void)constructView;
{
    unsigned int optionIndex, optionCount;
    NSRect matrixFrame, scrollFrame;
    NSSize cellSize, intercellSize;
    NSBrowserCell *prototypeCell;

    ASSERT_IN_MAIN_THREAD(@"AppKit calls must be from main thread!");

    [elementStateLock lock];
    optionCount = [options count];

    prototypeCell = [[NSBrowserCell alloc] initTextCell:@"selection"];
    [prototypeCell setLeaf:YES];

    matrix = [[NSMatrix alloc] initWithFrame:NSMakeRect(0.0, 0.0, 100.0, 100.0) mode:(allowMultiple ? NSListModeMatrix : NSRadioModeMatrix) prototype:prototypeCell numberOfRows:optionCount numberOfColumns:1];

    [prototypeCell release];

    [matrix setAutoscroll:YES];
    [matrix setAllowsEmptySelection:YES];
    [matrix setTarget:self];
    [matrix setAction:@selector(uiDidSelect:)];

    for (optionIndex = 0; optionIndex < optionCount; optionIndex++)
        [[matrix cellAtRow:optionIndex column:0] setStringValue:[[options objectAtIndex:optionIndex] text]];
    
    [elementStateLock unlock];

    [matrix setAutosizesCells:YES];
    [matrix sizeToFit];
    matrixFrame = [matrix frame];
    // we seems to be sizing too small in some cases.... "elephant" for example
    matrixFrame.size.width += 11;
    [matrix setFrame:matrixFrame];

    cellSize = [matrix cellSize];
    intercellSize = [matrix intercellSpacing];

    // Make sure the number of visible rows is reasonable.
    if (visibleRows == 0)
        visibleRows = 5;

    if (visibleRows > 0)
        matrixFrame.size.height = visibleRows * cellSize.height + (visibleRows - 1) * intercellSize.height;
    else
        matrixFrame.size.height = 0.0;

    // Make sure we always have enough room for the scrollview to have the up and down arrows, or the user won't be able to select anything.
    matrixFrame.size.height = MAX(NSHeight(matrixFrame), 53.0);

    scrollFrame.origin.x = 0.0;
    scrollFrame.origin.y = 0.0;
    scrollFrame.size = [NSScrollView frameSizeForContentSize:matrixFrame.size hasHorizontalScroller:NO hasVerticalScroller:YES borderType:NSBezelBorder];

    scrollView = [[NSScrollView alloc] initWithFrame:scrollFrame];
    [scrollView setDocumentView:matrix];
    [scrollView setHasVerticalScroller:YES];
    [scrollView setHasHorizontalScroller:NO];
    [scrollView setBorderType:NSBezelBorder];
    [scrollView freeGStates];

    [self reset];
}

// Matrix action method

- (void)uiDidSelect:(id)sender
{
   int cellIndex, cellCount;

   /* TODO: This could be made faster in most cases, I'm sure */
   [elementStateLock lock];
   [selectedOptions removeAllObjects];
   cellCount = [options count];
   for(cellIndex = 0; cellIndex < cellCount; cellIndex ++) {
       if ([[matrix cellAtRow:cellIndex column:0] state])
           [selectedOptions addObject:[options objectAtIndex:cellIndex]];
   }
   [elementStateLock unlock];

   [self userDidChangeSelection];
}

// OHViewCell subclass

- (void)setupContentView;
{
    [self constructView];
    [self setContentView:scrollView];
}

// OHFormElement protocol (partial)

- (NSString *)type;
{
    return @"Select-Multiple";
}

// OHFormSelect subclass stuff

- (void)updateUI
{
    unsigned int firstSelectedIndex;

    [elementStateLock lock];

    if ([options count] == 0) {
        /* Nothing to do. */
        [elementStateLock unlock];
        return;
    }
    
    /* Quick sanity check. */
    if (!allowMultiple) {
        if ([selectedOptions count] == 0) {
            /* Radio mode. Select the first option. */
            [selectedOptions addObject:[options objectAtIndex:0]];
        } else {
            while ([selectedOptions count] > 1) {
                /* Remove all but first selected option. */
                [selectedOptions removeLastObject];
            }
        }
    }

    firstSelectedIndex = NSNotFound;
    if (allowMultiple) {
        unsigned int optionIndex;
        unsigned int selectionIndex, selectionCount;
        
        [matrix deselectAllCells];
        
        selectionCount = [selectedOptions count];
        for(selectionIndex = 0; selectionIndex < selectionCount; selectionIndex ++) {
            optionIndex = [options indexOfObjectIdenticalTo:[selectedOptions objectAtIndex:selectionIndex]];
            if (optionIndex == NSNotFound) {
                /* This should never happen */
                continue;
            }
            if (firstSelectedIndex == NSNotFound)
                firstSelectedIndex = optionIndex;
            [matrix setState:YES atRow:optionIndex column:0];
            [matrix highlightCell:YES atRow:optionIndex column:0];
        }
    } else {
        unsigned int optionIndex;
        /* Radio mode. There will be exactly one object in selectedOptions. */
        optionIndex = [options indexOfObjectIdenticalTo:[selectedOptions objectAtIndex:0]];
        firstSelectedIndex = optionIndex;
        if (optionIndex != NSNotFound)
            [matrix selectCellAtRow:optionIndex column:0];
    }

    [elementStateLock unlock];

    /* Scroll the matrix to be visible and redisplay it */
    if (firstSelectedIndex != NSNotFound) {
        [matrix scrollCellToVisibleAtRow:[options count] - 1 column:0];
        [matrix scrollCellToVisibleAtRow:firstSelectedIndex column:0];
    }
    [scrollView setNeedsDisplay:YES];
}

- (BOOL)allowsMultipleSelection
{
    return allowMultiple;
}

// Debugging

- (NSMutableDictionary *)debugDictionary;
{
    NSMutableDictionary *debugDictionary;

    debugDictionary = [super debugDictionary];
    [debugDictionary setBoolValue:allowMultiple forKey:@"allowMultiple"];
    [debugDictionary setIntValue:visibleRows forKey:@"visibleRows"];

    return debugDictionary;
}

@end
