/*
 * Copyright 2011 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#import "SkOptionsTableView.h"
#import "SkTextFieldCell.h"
@implementation SkOptionItem
@synthesize fCell, fItem;
- (void)dealloc {
    [fCell release];
    [super dealloc];
}
@end

@implementation SkOptionsTableView
@synthesize fItems;

- (id)initWithCoder:(NSCoder*)coder {
    if ((self = [super initWithCoder:coder])) {
        self.dataSource = self;
        self.delegate = self;
        fMenus = NULL;
        fShowKeys = YES;
        [self setSelectionHighlightStyle:NSTableViewSelectionHighlightStyleNone];
        self.fItems = [NSMutableArray array];
    }
    return self;
}

- (void)dealloc {
    self.fItems = nil;
    [super dealloc];
}

- (void) view:(SkNSView*)view didAddMenu:(const SkOSMenu*)menu {}
- (void) view:(SkNSView*)view didUpdateMenu:(const SkOSMenu*)menu {
    [self updateMenu:menu];
}

- (IBAction)toggleKeyEquivalents:(id)sender {
    fShowKeys = !fShowKeys;
    NSMenuItem* item = (NSMenuItem*)sender;
    [item setState:fShowKeys];
    [self reloadData];
}

- (void)registerMenus:(const SkTDArray<SkOSMenu*>*)menus {
    fMenus = menus;
    for (int i = 0; i < fMenus->count(); ++i) {
        [self loadMenu:(*fMenus)[i]];
    }
}

- (void)updateMenu:(const SkOSMenu*)menu {
    // the first menu is always assumed to be the static, the second is
    // repopulated every time over and over again

    // seems pretty weird that we have to get rid of the const'ness here,
    // but trying to propagate the const'ness through all the way to the fMenus
    // vector was a non-starter.

    int menuIndex = fMenus->find(const_cast<SkOSMenu *>(menu));
    if (menuIndex >= 0 && menuIndex < fMenus->count()) {
        NSUInteger first = 0;
        for (int i = 0; i < menuIndex; ++i) {
            first += (*fMenus)[i]->getCount();
        }
        [fItems removeObjectsInRange:NSMakeRange(first, [fItems count] - first)];
        [self loadMenu:menu];
    }
    [self reloadData];
}

- (NSCellStateValue)triStateToNSState:(SkOSMenu::TriState)state {
    if (SkOSMenu::kOnState == state)
        return NSOnState;
    else if (SkOSMenu::kOffState == state)
        return NSOffState;
    else
        return NSMixedState;
}

- (void)loadMenu:(const SkOSMenu*)menu {
    const SkOSMenu::Item* menuitems[menu->getCount()];
    menu->getItems(menuitems);
    for (int i = 0; i < menu->getCount(); ++i) {
        const SkOSMenu::Item* item = menuitems[i];
        SkOptionItem* option = [[SkOptionItem alloc] init];
        option.fItem = item;

        if (SkOSMenu::kList_Type == item->getType()) {
            int index = 0, count = 0;
            SkOSMenu::FindListItemCount(*item->getEvent(), &count);
            NSMutableArray* optionstrs = [[NSMutableArray alloc] initWithCapacity:count];
            std::unique_ptr<SkString[]> ada(new SkString[count]);
            SkString* options = ada.get();
            SkOSMenu::FindListItems(*item->getEvent(), options);
            for (int i = 0; i < count; ++i)
                [optionstrs addObject:[NSString stringWithUTF8String:options[i].c_str()]];
            SkOSMenu::FindListIndex(*item->getEvent(), item->getSlotName(), &index);
            option.fCell = [self createList:optionstrs current:index];
            [optionstrs release];
        }
        else {
            bool state = false;
            SkString str;
            SkOSMenu::TriState tristate;
            switch (item->getType()) {
                case SkOSMenu::kAction_Type:
                    option.fCell = [self createAction];
                    break;
                case SkOSMenu::kSlider_Type:
                    SkScalar min, max, value;
                    SkOSMenu::FindSliderValue(*item->getEvent(), item->getSlotName(), &value);
                    SkOSMenu::FindSliderMin(*item->getEvent(), &min);
                    SkOSMenu::FindSliderMax(*item->getEvent(), &max);
                    option.fCell = [self createSlider:value
                                                  min:min
                                                  max:max];
                    break;
                case SkOSMenu::kSwitch_Type:
                    SkOSMenu::FindSwitchState(*item->getEvent(), item->getSlotName(), &state);
                    option.fCell = [self createSwitch:(BOOL)state];
                    break;
                case SkOSMenu::kTriState_Type:
                    SkOSMenu::FindTriState(*item->getEvent(), item->getSlotName(), &tristate);
                    option.fCell = [self createTriState:[self triStateToNSState:tristate]];
                    break;
                case SkOSMenu::kTextField_Type:
                    SkOSMenu::FindText(*item->getEvent(),item->getSlotName(), &str);
                    option.fCell = [self createTextField:[NSString stringWithUTF8String:str.c_str()]];
                    break;
                default:
                    break;
            }
        }
        [fItems addObject:option];
        [option release];
    }
}

- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView {
    return [self.fItems count];
}

- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
    NSInteger columnIndex = [tableView columnWithIdentifier:[tableColumn identifier]];
    if (columnIndex == 0) {
        const SkOSMenu::Item* item = ((SkOptionItem*)[fItems objectAtIndex:row]).fItem;
        NSString* label = [NSString stringWithUTF8String:item->getLabel()];
        if (fShowKeys)
            return [NSString stringWithFormat:@"%@ (%c)", label, item->getKeyEquivalent()];
        else
            return label;
    }
    else
        return nil;
}

- (NSCell *)tableView:(NSTableView *)tableView dataCellForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
    if (tableColumn) {
        NSInteger columnIndex = [tableView columnWithIdentifier:[tableColumn identifier]];
        if (columnIndex == 1)
            return [((SkOptionItem*)[fItems objectAtIndex:row]).fCell copy];
        else
            return [[[SkTextFieldCell alloc] init] autorelease];
    }
    return nil;
}

- (void)tableView:(NSTableView *)tableView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
    NSInteger columnIndex = [tableView columnWithIdentifier:[tableColumn identifier]];
    if (columnIndex == 1) {
        SkOptionItem* option = (SkOptionItem*)[self.fItems objectAtIndex:row];
        NSCell* storedCell = option.fCell;
        const SkOSMenu::Item* item = option.fItem;
        switch (item->getType()) {
            case SkOSMenu::kAction_Type:
                break;
            case SkOSMenu::kList_Type:
                [cell selectItemAtIndex:[(NSPopUpButtonCell*)storedCell indexOfSelectedItem]];
                break;
            case SkOSMenu::kSlider_Type:
                [cell setFloatValue:[storedCell floatValue]];
                break;
            case SkOSMenu::kSwitch_Type:
                [cell setState:[(NSButtonCell*)storedCell state]];
                break;
            case SkOSMenu::kTextField_Type:
                if ([[storedCell stringValue] length] > 0)
                    [cell setStringValue:[storedCell stringValue]];
                break;
            case SkOSMenu::kTriState_Type:
                [cell setState:[(NSButtonCell*)storedCell state]];
                break;
            default:
                break;
        }
    }
    else {
        [(SkTextFieldCell*)cell setEditable:NO];
    }
}

- (void)tableView:(NSTableView *)tableView setObjectValue:(id)anObject forTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
    NSInteger columnIndex = [tableView columnWithIdentifier:[tableColumn identifier]];
    if (columnIndex == 1) {
        SkOptionItem* option = (SkOptionItem*)[self.fItems objectAtIndex:row];
        NSCell* cell = option.fCell;
        const SkOSMenu::Item* item = option.fItem;
        switch (item->getType()) {
            case SkOSMenu::kAction_Type:
                item->postEvent();
                break;
            case SkOSMenu::kList_Type:
                [(NSPopUpButtonCell*)cell selectItemAtIndex:[anObject intValue]];
                item->setInt([anObject intValue]);
                break;
            case SkOSMenu::kSlider_Type:
                [cell setFloatValue:[anObject floatValue]];
                item->setScalar([anObject floatValue]);
                break;
            case SkOSMenu::kSwitch_Type:
                [cell setState:[anObject boolValue]];
                item->setBool([anObject boolValue]);
                break;
            case SkOSMenu::kTextField_Type:
                if ([anObject length] > 0) {
                    [cell setStringValue:anObject];
                    item->setString([anObject UTF8String]);
                }
                break;
            case SkOSMenu::kTriState_Type:
                [cell setState:[anObject intValue]];
                item->setTriState((SkOSMenu::TriState)[anObject intValue]);
                break;
            default:
                break;
        }
        item->postEvent();
    }
}

- (NSCell*)createAction{
    NSButtonCell* cell = [[[NSButtonCell alloc] init] autorelease];
    [cell setTitle:@""];
    [cell setButtonType:NSMomentaryPushInButton];
    [cell setBezelStyle:NSSmallSquareBezelStyle];
    return cell;
}

- (NSCell*)createList:(NSArray*)items current:(int)index {
    NSPopUpButtonCell* cell = [[[NSPopUpButtonCell alloc] init] autorelease];
    [cell addItemsWithTitles:items];
    [cell selectItemAtIndex:index];
    [cell setArrowPosition:NSPopUpArrowAtBottom];
    [cell setBezelStyle:NSSmallSquareBezelStyle];
    return cell;
}

- (NSCell*)createSlider:(float)value min:(float)min max:(float)max {
    NSSliderCell* cell = [[[NSSliderCell alloc] init] autorelease];
    [cell setFloatValue:value];
    [cell setMinValue:min];
    [cell setMaxValue:max];
    return cell;
}

- (NSCell*)createSwitch:(BOOL)state {
    NSButtonCell* cell = [[[NSButtonCell alloc] init] autorelease];
    [cell setState:state];
    [cell setTitle:@""];
    [cell setButtonType:NSSwitchButton];
    return cell;
}

- (NSCell*)createTextField:(NSString*)placeHolder {
    SkTextFieldCell* cell = [[[SkTextFieldCell alloc] init] autorelease];
    [cell setEditable:YES];
    [cell setStringValue:@""];
    [cell setPlaceholderString:placeHolder];
    return cell;
}

- (NSCell*)createTriState:(NSCellStateValue)state {
    NSButtonCell* cell = [[[NSButtonCell alloc] init] autorelease];
    [cell setAllowsMixedState:TRUE];
    [cell setTitle:@""];
    [cell setState:(NSInteger)state];
    [cell setButtonType:NSSwitchButton];
    return cell;
}
@end