// 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 "OHFormText.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 "OHFormTextArea.h"
#import "OHFormValue.h"
#import "OWScriptEventHandlerHolder.h"

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

@implementation OHFormText

static NSCharacterSet *newlineSet, *carriageReturnSet;
static NSSize figureSpaceSize;
static NSFont *textFont;

+ (void)initialize;
{
    static BOOL initialized = NO;
    NSGlyph zeroGlyph;
    NSFont *screenFont;
    NSString *fontName;
    float size;

    [super initialize];
    if (initialized)
	return;
    initialized = YES;

    newlineSet = [[NSCharacterSet characterSetWithCharactersInString:@"\n"] retain];
    carriageReturnSet = [[NSCharacterSet characterSetWithCharactersInString:@"\r"] retain];

    fontName = [[OFUserDefaults sharedUserDefaults] stringForKey:@"OHFixedPitchFont"];
    size = [[OFUserDefaults sharedUserDefaults] floatForKey:@"OHFixedPitchFontSize"];
    if (size < 0.5)
	size = 12.0;
    textFont = [[NSFont fontWithName:fontName size:size] retain];
    if (!textFont)
	textFont = [[NSFont fontWithName:@"Courier" size:size] retain];

    screenFont = [textFont screenFont];

    zeroGlyph = [textFont glyphWithName:@"zero"];
    if (screenFont) {
        if (zeroGlyph != NSNotFound && [screenFont glyphIsEncoded:zeroGlyph])
            figureSpaceSize.width = ceil([screenFont advancementForGlyph:zeroGlyph].width);
	else
            figureSpaceSize.width = ceil([screenFont maximumAdvancement].width);
    } else {
        if (zeroGlyph != NSNotFound && [textFont glyphIsEncoded:zeroGlyph])
            figureSpaceSize.width = ceil([textFont advancementForGlyph:zeroGlyph].width);
	else
	    figureSpaceSize.width = ceil([textFont maximumAdvancement].width);
    }

    figureSpaceSize.height = ceil(NSHeight([textFont boundingRectForFont]));
}

+ (OHFormText *)formTextWithForm:(OHForm *)aForm name:(NSString *)aName value:(NSString *)aValue alignment:(NSTextAlignment)anAlignment disabled:(BOOL)shouldBeDisabled invisibleInput:(BOOL)shouldBeInvisible width:(unsigned int)aWidth height:(unsigned int)aHeight maximumLength:(unsigned int)aMaximumLength;
{
    Class class;

    class = (aHeight > 1) ? [OHFormTextArea class] : self;
    return [[[class alloc] initWithForm:aForm name:aName value:aValue alignment:anAlignment disabled:shouldBeDisabled invisibleInput:shouldBeInvisible width:aWidth height:aHeight maximumLength:aMaximumLength] autorelease];
}

+ (NSFont *)textFont;
{
    return textFont;
}

+ (NSRect)textFrameForWidth:(unsigned int)aWidth height:(unsigned int)aHeight;
{
    return NSMakeRect(0.0, 0.0, figureSpaceSize.width * aWidth, figureSpaceSize.height * aHeight);
}

- initWithForm:(OHForm *)aForm name:(NSString *)aName value:(NSString *)aValue alignment:(NSTextAlignment)anAlignment disabled:(BOOL)shouldBeDisabled invisibleInput:(BOOL)shouldBeInvisible width:(unsigned int)aWidth height:(unsigned int)aHeight maximumLength:(unsigned int)aMaximumLength;
{
    if (![super init])
	return nil;

    form = aForm;
    name = [aName retain];
    initialValue = [(aValue ? aValue : @"") retain];
    textAlignment = anAlignment;
    formTextFlags.isDisabled = shouldBeDisabled;
    formTextFlags.invisibleInput = shouldBeInvisible;
    formTextFlags.autoSubmit = NO;
    width = aWidth;
    height = aHeight;
    maximumLength = aMaximumLength;
    elementStateLock = [[NSRecursiveLock alloc] init];
    eventHandlers = [[OWScriptEventHandlerHolder alloc] init];

    return self;
}

- (void)dealloc;
{
    [textField release];
    [name release];
    [initialValue release];
    [eventHandlers release];
    [elementStateLock release];
    [super dealloc];
}

- (void)setNextKeyViewCell:(OHViewCell *)nextKeyViewCell;
{
    [self _setNextKeyViewCell:nextKeyViewCell];
}

- (void)setAutoSubmit;
{
    if (![NSThread mainThreadOpsOK]) {
        [self mainThreadPerformSelectorOnce:_cmd];
        return;
    }
    ASSERT_IN_MAIN_THREAD(@"AppKit calls must be from main thread!");

    formTextFlags.autoSubmit = YES;
    if (textField) {
        [textField setTarget:form];
        [textField setAction:@selector(delayedSubmit:)];
    }
}

- (NSView *)setupTextField;
{
    NSRect textFrame;
    Class textFieldClass;

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

    textFrame = [isa textFrameForWidth:width height:height];

    // add a little for the border
    textFrame.size.height += 6.0;
    textFrame.size.width += 9.0;

    textFieldClass = formTextFlags.invisibleInput ? [OASecureTextField class] : [NSTextField class];
    textField = [[textFieldClass alloc] initWithFrame:textFrame];
    [textField setFont:[isa textFont]];
    [textField setDelegate:self];
    [textField setBezeled:YES];
    [textField setEditable:!formTextFlags.isDisabled];
    [textField setEnabled:!formTextFlags.isDisabled];
    [[textField cell] setScrollable:YES]; // In NS3.3, this reset the alignment
    [textField setAlignment:textAlignment];
    if (formTextFlags.autoSubmit) {
        [textField setTarget:form];
        [textField setAction:@selector(delayedSubmit:)];
    }
    return textField;
}

- (void)controlTextDidChange:(NSNotification *)aNotification
{
    OBASSERT([aNotification object] == textField);
    
    [elementStateLock lock];
    [currentValue release];
    currentValue = [[textField stringValue] retain];
    [elementStateLock unlock];

//    [self userDidChangeValue];
}

- (void)controlTextDidEndEditing:(NSNotification *)aNotification
{
    OBASSERT([aNotification object] == textField);
    [self userDidChangeValue];
}

- (void)userDidChangeValue
{
    [OWScriptEvent sendBackgroundEvent:OWSE_Change
                            instigator:self
                             responder:[self eventHandlers]];
}

- (void)updateUI
{
    ASSERT_MAIN_THREAD_OPS_OK(@"AppKit calls must be from main thread!");
    [elementStateLock lock];
    [textField setStringValue:currentValue];
    [elementStateLock unlock];
}
   
// OHViewCell subclass

- (void)setupContentView;
{
    NSView *theContentView;

    theContentView = [self setupTextField];
    [self reset];
    [self setContentView:theContentView];
}

// OHFormElement protocol

- (void)reset;
{
    [elementStateLock lock];
    [initialValue retain];
    [currentValue release];
    currentValue = initialValue;
    [elementStateLock unlock];

    [self mainThreadPerformSelectorOnce:@selector(updateUI)];
}

- (void)clear;
{
}

- (NSString *)name;
{
    return name;
}

- (NSString *)type;
{
    if (formTextFlags.invisibleInput)
        return @"Password";
    else
        return @"Text";
}

- (NSArray *)formValues;
{
    NSString *value;

    [elementStateLock lock];
    value = [[currentValue copy] autorelease];
    [elementStateLock unlock];
    
    if (!name)
	return nil;
    if (!value)
        value = @"";

    if ([value rangeOfCharacterFromSet:newlineSet].length) {
	NSMutableString *mutableValue;
    
	mutableValue = [value mutableCopy];
        [mutableValue collapseAllOccurrencesOfCharactersInSet:carriageReturnSet
                                                   toString:@""];
	[mutableValue replaceAllOccurrencesOfCharactersInSet:newlineSet withString:@"\r\n"];
        value = [[mutableValue copy] autorelease];
        [mutableValue release];
    }

    return [NSArray arrayWithObject:[OHFormValue formValueWithName:name valueString:value]];
}

- (NSArray *)defaultFormValues
{
    return [NSArray arrayWithObject:[OHFormValue formValueWithName:name valueString:initialValue]];
}

- (void)resetFromFormValues:(NSArray *)values;
{
    OHFormValue *formValue;

    if ([values count] != 1)
        return;
    formValue = [values objectAtIndex:0];

    [elementStateLock lock];
    [currentValue release];
    currentValue = [[formValue valueString] copy];
    [elementStateLock unlock];

    [self mainThreadPerformSelectorOnce:@selector(updateUI)];
}

- (OWScriptEventHandlerHolder *)eventHandlers
{
    return eventHandlers;
}

@end
