// 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 "OHFormInputButton.h"

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

#import "OHForm.h"
#import "OHFormValue.h"
#import "OWScriptEventHandlerHolder.h"

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

@interface OHFormInputButton (Private)
- (void)generateClickEvent:(id)sender;
- (void)radioButtonSelect:(id)sender;
- (void)setButtonChecked:(BOOL)newChecked;
@end

@implementation OHFormInputButton

- initWithForm:(OHForm *)aForm name:(NSString *)aName value:(NSString *)aValue radio:(BOOL)isRadio checked:(BOOL)isChecked;
{
    if (![super initWithForm:aForm name:aName value:aValue])
        return nil;

    formButtonFlags.initiallyChecked = isChecked;
    formButtonFlags.radioMode = isRadio;
//    elementStateLock = [[NSRecursiveLock allocWithZone:[self zone]] init];

    return self;
}

// OHFormButton subclass

- (void)setupButton;
{
    [super setupButton];
    if (formButtonFlags.radioMode) {
        [button setButtonType:NSRadioButton];
        [button setImagePosition:NSImageOnly];
        [button setBordered:NO];
        [button setImage:[NSImage imageNamed:@"NSRadioButton"]];
        [button setAlternateImage:[NSImage imageNamed:@"NSHighlightedRadioButton"]];
    } else {
        [button setButtonType:NSSwitchButton];
        [button setImagePosition:NSImageOnly];
        [button setBordered:NO];
        [button setImage:[NSImage imageNamed:@"NSSwitch"]];
        [button setAlternateImage:[NSImage imageNamed:@"NSHighlightedSwitch"]];
    }
    [button setTarget:self];
    [button setAction:@selector(generateClickEvent:)];
    [self reset];
}

- (void)setContentView:(NSView *)newContentView
{
    // add room to draw the first responder border...
    NSRect frameRect = [newContentView frame];
    frameRect.size.width +=2;
    frameRect.size.height +=2;
    [newContentView setFrame:frameRect];
    [super setContentView:newContentView];
}

- (BOOL)includeFormValues;
{
    BOOL checked;
//    [elementStateLock lock];
    // bitfield access should be atomic
    checked = formButtonFlags.currentlyChecked;
//    [elementStateLock unlcok];
    return checked; // [button state] != 0
}

// OHFormElement protocol (partial)

- (void)reset;
{
    [self mainThreadPerformSelector:@selector(setButtonChecked:) withBool:formButtonFlags.initiallyChecked];
}

- (void)clear;
{
    [self mainThreadPerformSelector:@selector(setButtonChecked:)
                           withBool:NO];
}

- (NSString *)type;
{
    if (formButtonFlags.radioMode)
        return @"Radio";
    else
        return @"Checkbox";
}

- (NSArray *)defaultFormValues;
{
    if (!name)
        return nil;

    if (formButtonFlags.initiallyChecked)
        return [NSArray arrayWithObject:[OHFormValue formValueWithName:name valueString:value]];
    else
        return nil;
}

- (void)resetFromFormValues:(NSArray *)values;
{
    BOOL newState = (values != nil && [values count] != 0);
    [self mainThreadPerformSelector:@selector(setButtonChecked:)
                           withBool:newState];
}


@end

@implementation OHFormInputButton (Private)

- (void)generateClickEvent:(id)sender
{
    OWScriptEvent *click;

    click = [[OWScriptEvent alloc] initWithType:OWSE_Click fromEvent:[NSApp currentEvent]];
    if (formButtonFlags.radioMode)
        [click setTarget:self action:@selector(radioButtonSelect:) cancelAction:@selector(cancelClick:)];
    else
        [click setTarget:self action:@selector(checkboxButtonSelect:) cancelAction:@selector(cancelClick:)];
    [click setInstigator:self];

    // TODO: efficiency shortcuts here ?
    [click addResponder:[self eventHandlers]];
    // TODO: event capture by parent objects

    [click deliverAsynchronously];
    [click release];
}

// Called when the script cancels a click action. Reset the UI element.
- (void)cancelClick:(id)sender
{
    // Access to currentlyChecked should be atomic
    [self setButtonChecked:formButtonFlags.currentlyChecked];
}

// Called if the user clicks on a radio button and the script doesn't stop it: do the radiobutton stuff.
- (void)radioButtonSelect:(id)sender;
{
    [self setButtonChecked:YES];
}

// Called if the user clicks on a checkbox and the script doesn't stop it: copy the UI's state into our state
- (void)checkboxButtonSelect:(id)sender;
{
    int newState;
    newState = [button state] ? 1 : 0;
    // Access to currentlyChecked should be atomic
    formButtonFlags.currentlyChecked = newState;
}

- (void)setButtonChecked:(BOOL)newChecked;
{
    int newState;

    OBPRECONDITION([NSThread inMainThread]);

    newState = newChecked ? 1 : 0;
    if ([button state] != newState) {
	[button setState:newState];
        [self redisplayCell];
    }
    formButtonFlags.currentlyChecked = newState;
    if (formButtonFlags.radioMode && newChecked)
	[nonretainedForm radioButtonSelected:self];
}

// Debugging

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

    debugDictionary = [super debugDictionary];

    [debugDictionary setObject:formButtonFlags.initiallyChecked ? @"YES" : @"NO" forKey:@"formButtonFlags.initiallyChecked"];
    [debugDictionary setObject:formButtonFlags.radioMode ? @"YES" : @"NO" forKey:@"formButtonFlags.radioMode"];

    return debugDictionary;
}

@end
