//
//  NJRIntervalField.m
//  Pester
//
//  Created by Nicholas Riley on Wed Dec 25 2002.
//  Copyright (c) 2002 Nicholas Riley. All rights reserved.
//

#import "NJRIntervalField.h"

// XXX much implementation borrowed from DockCam, then factored; should replace DockCam interval selector with a NJRIntervalField at some point

@implementation NJRIntervalField

- (NSTimeInterval)interval;
{
    NSText *editor = [self currentEditor];
    id obj = nil;
    
    if (editor != nil) {
        NSString *stringValue = [editor string];
        if (![[self formatter] getObjectValue: &obj forString: stringValue errorDescription: NULL])
            return 0;
    } else {
        obj = self;
    }
    
    return [obj intValue] * [[intervalUnits selectedItem] tag];
}

- (BOOL)setInterval:(NSTimeInterval)interval;
{
    // we assume that the tags are in ascending order in the array
    NSEnumerator *e = [[intervalUnits itemArray] reverseObjectEnumerator];
    NSMenuItem *i;
    int multiplierTag;

    while ( (i = [e nextObject]) != nil) {
        multiplierTag = [i tag];
        if (multiplierTag <= 0) continue;
        if (((int)interval % multiplierTag) == 0) {
            NSFormatter *formatter = [self formatter];
            int intervalValue = interval / multiplierTag;
            if (formatter != nil) {
                id ignored;
                if (![formatter getObjectValue: &ignored forString: [formatter stringForObjectValue: [NSNumber numberWithInt: intervalValue]] errorDescription: NULL]) return NO;
            }
            [self setIntValue: intervalValue];
            [intervalUnits selectItem: i];
            return YES;
        }
    }
    return NO;
}

- (BOOL)textView:(NSTextView *)textView shouldChangeTextInRange:(NSRange)range replacementString:(NSString *)string;
{
    unsigned length = [string length];
    if (length != 0) {
        unichar c;
        int tag = -1;
        c = [string characterAtIndex: length - 1];
        switch (c) {
            case 's': case 'S': tag = 1; break;
            case 'm': case 'M': tag = 60; break;
            case 'h': case 'H': tag = 60 * 60; break;
            case 'u': case 'U': tag = -2; break;
            default: break;
        }
        if (tag != -1) {
            int itemIndex = [intervalUnits indexOfItemWithTag: tag];
            if (itemIndex != -1) {
                [intervalUnits selectItemAtIndex: itemIndex];
                [[intervalUnits menu] performActionForItemAtIndex: itemIndex];
            }
            if (tag < 0) return NO; // don't send update
        }
    }
    return [super textView: textView shouldChangeTextInRange: range replacementString: string];
}

- (void)handleDidFailToFormatString:(NSString *)string errorDescription:(NSString *)error label:(NSString *)label;
{
    NSString *alertMessage = nil;
    NSString *alternateButtonString = nil;
    NSNumber *proposedValue = nil;
    NSDictionary *contextInfo;

    NSString *alertInformation = [NSString localizedStringWithFormat:
        NSLocalizedString(@"The %@ field must be set to a value between %@ and %@.",
                          @"Informative text for alert posed by text field when invalid value entered"),
        label, [[self formatter] minimum], [[self formatter] maximum]];
    NSString *defaultButtonString = NSLocalizedString(@"Edit", @"Name of Edit button");
    NSString *otherButtonString = NSLocalizedString(@"Cancel", @"Name of Cancel button");

    if ([error isEqualToString:
        NSLocalizedStringFromTableInBundle(@"Fell short of minimum", @"Formatter",
                                           [NSBundle bundleForClass:[NSFormatter class]],
                                           @"Presented when user value smaller than minimum")]) {
        proposedValue = [[self formatter] minimum];
        alertMessage = [NSString stringWithFormat:
            NSLocalizedString(@"%@ is too small for the %@ field.",
                              @"Message text for alert posed by numeric field when too-small value entered"),
            string, label];
        alternateButtonString = [NSString localizedStringWithFormat:
            NSLocalizedString(@"Set to %@",
                              @"Name of alternate button for alert posed by numeric field when too-small value entered"),
            proposedValue];
    } else if ([error isEqualToString:
        NSLocalizedStringFromTableInBundle(@"Maximum exceeded", @"Formatter",
                                           [NSBundle bundleForClass:[NSFormatter class]],
                                           @"Presented when user value larger than maximum")]) {
        proposedValue = [[self formatter] maximum];
        alertMessage = [NSString stringWithFormat:
            NSLocalizedString(@"%@ is too large for the %@ field.",
                              @"Message text for alert posed by numeric field when too-large value entered"),
            string, label];
        alternateButtonString = [NSString localizedStringWithFormat:
            NSLocalizedString(@"Set to %@",
                              @"Name of alternate button for alert posed by numeric field when too-large value entered"),
            proposedValue];
    } else if ([error isEqualToString:
        NSLocalizedStringFromTableInBundle(@"Invalid number", @"Formatter",
                                           [NSBundle bundleForClass:[NSFormatter class]],
                                           @"Presented when user typed illegal characters: no valid object")]) {
        alertMessage = [NSString stringWithFormat:
            NSLocalizedString(@"%@ is not a valid entry for the %@ field.",
                              @"Message text for alert posed by text field when invalid value entered"),
            string, label];
        alternateButtonString = nil;
    }

    contextInfo = [NSDictionary dictionaryWithObject: proposedValue forKey: @"proposedValue"];
    [contextInfo retain];
    NSBeep();
    NSBeginAlertSheet(alertMessage, defaultButtonString, alternateButtonString, otherButtonString, [self window],
                      self, @selector(validationFailedSheetDidEnd:returnCode:contextInfo:), NULL, contextInfo,
                      alertInformation);
}

- (void)_propagateValidationChange;
{
    NSText *fieldEditor = [self currentEditor];
    NSDictionary *userInfo = nil;
    if (fieldEditor != nil) userInfo = [NSDictionary dictionaryWithObject: fieldEditor forKey: @"NSFieldEditor"];
    [[NSNotificationCenter defaultCenter] postNotificationName: NSControlTextDidChangeNotification object: self userInfo: userInfo];
    [self selectText: self];
}

- (void)validationFailedSheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo {
    // modal delegate callback method for NSBeginAlertSheet() function; called in the above method
    if (returnCode == NSAlertOtherReturn) { // cancel
        [self abortEditing]; // abort edit session and reinstate original value
        [self _propagateValidationChange];
    } else if (returnCode == NSAlertAlternateReturn) { // set to min/max/default value
        [self setObjectValue: [(NSDictionary *)contextInfo objectForKey: @"proposedValue"]];
        [self validateEditing];
        [self _propagateValidationChange];
    }
    [(NSDictionary *)contextInfo release];
}

@end
