//
//  ECStoryboardView.m
//  Etokicho
//
//  Created by 二鏡 on 11/11/21.
//  Copyright 2011年 二鏡庵. All rights reserved.
//

#import "ECStoryboardView.h"
#import "ECDSceneSegment.h"

static NSString *_contentBindingContext = @"ECStoryboardViewContent";
static NSString *_selectedIndexesBindingContext = @"ECStoryboardViewSelectionIndexes";

NSString *ECStoryBoardViewLayerSegmentRequestNotification = @"ECStoryBoardViewLayerSegmentRequest";
static const CGFloat cLayerSperator = 16.0;


static NSSize
layerSizeToMovieSize(NSSize aSize)
{
    CGFloat h = 72.0;
    CGFloat w = h*aSize.width/aSize.height;
    return NSMakeSize(w,h);
}


@interface ECStoryboardView ()
- (void)scrollToTail;
- (void)scrollTo:(NSUInteger)idx;
@end

@implementation ECStoryboardView
@synthesize target, action, doubleAction, delegate;
- (id)initWithFrame:(NSRect)frameRect
{
    self = [super initWithFrame: frameRect];
    if(self)
    {
        layerTable = [[NSMapTable mapTableWithWeakToStrongObjects] retain];
        reverseTable = [[NSMapTable mapTableWithWeakToStrongObjects] retain];
        
        id bundle = [NSBundle mainBundle];
        id url = [bundle URLForResource: @"Transition" withExtension: @"png"];
        CGImageSourceRef src = CGImageSourceCreateWithURL((CFURLRef)url, nil);
        transitionImage = CGImageSourceCreateImageAtIndex(src, 0, nil);
        CFRelease(src);
        
        // setup bg
        CALayer *bgLayer = [CALayer layer];
        CGColorRef color = CGColorCreateGenericGray(0.8, 1.0);
        bgLayer.backgroundColor = color;
        CFRelease(color);
        [self setLayer: bgLayer];

        [self attachEmptyLayerIfNeed];
        click.prev = NSNotFound;
        keyMove.start = NSNotFound;
    }
    return self;
}

#pragma mark Property
- (BOOL)acceptsFirstMouse:(NSEvent *)theEvent
{
    return YES;
}

- (BOOL)acceptsFirstResponder
{
    return YES;
}

- (BOOL)isFlipped
{
    return YES;
}

- (BOOL)isOpaque
{
    return YES;
}

#pragma mark Resize
- (void)sizeToFit
{
    NSSize contentSize = [[self enclosingScrollView] contentSize];
    CGFloat w = MAX( minSize.width, contentSize.width);
    CGFloat h = MAX( minSize.height, contentSize.height);
    [self setFrameSize: NSMakeSize(w,h)];
}

- (void)viewDidMoveToSuperview
{
    id center = [NSNotificationCenter defaultCenter];
    id scroll = [self enclosingScrollView];
    if(scroll)
    {
        [center addObserver: self
                   selector: @selector(scrollFrameDidChange:)
                       name: NSViewFrameDidChangeNotification
                     object: scroll];
        [self sizeToFit];
    }
    else
    {
        [center removeObserver: self 
                          name: NSViewFrameDidChangeNotification
                        object: nil];
    }
}

- (void)scrollFrameDidChange:(id)notif
{
    [self sizeToFit];
}

#pragma mark Empty Layer
- (void)attachEmptyLayerIfNeed
{
    // maptableが空の時のみattachする
    if([layerTable count] != 0)
        return;
    
    NSRect bounds = [self bounds];
    
    emptyLayer = [CATextLayer layer];
    emptyLayer.string = NSLocalizedString(@"Empty",@"");
    emptyLayer.font = [NSFont systemFontOfSize: 12.0];
    emptyLayer.fontSize = 48.0;
    emptyLayer.frame = NSMakeRect(0,0,200,64);
    emptyLayer.position = NSMakePoint(200/2+cLayerSperator, NSMidY(bounds));
    CGColorRef fcolor = CGColorGetConstantColor(kCGColorBlack);
    emptyLayer.foregroundColor = fcolor;
    [[self layer] addSublayer: emptyLayer];
    minSize = NSMakeSize(200+cLayerSperator*2,NSHeight(bounds));
}

- (void)detachEmptyLayer
{
    // 存在するならdetach
    [emptyLayer removeFromSuperlayer];
    emptyLayer = nil;
}

#pragma mark Layer Operation
- (void)setImageOfLayer:(CALayer*)aLayer
              toSegment:(ECDSegment*)aSegment
{
    if([aSegment isKindOfClass: [ECDSceneSegment class]])
    {
        ECScene *scene = [(ECDSceneSegment*)aSegment scene];
        NSSize movieSize = scene.size;
        NSSize size = layerSizeToMovieSize(movieSize);
        CGFloat ratio = size.height/movieSize.height;
        CGImageRef thumbnail = [scene allocSnapshot: ratio];
        aLayer.contents = (id)thumbnail;
        CGImageRelease(thumbnail);
    }
}

- (id)layerForSegment:(ECDSegment*)aSegment
{
    CGColorRef borderColor = CGColorCreateGenericRGB(1.0, 1.0, 0.0, 1.0);
    CALayer *layer;
    if([aSegment isKindOfClass: [ECDSceneSegment class]])
    {
        ECScene *scene = [(ECDSceneSegment*)aSegment scene];
        NSSize movieSize = scene.size;
        NSSize size = layerSizeToMovieSize(movieSize);
        CGFloat ratio = size.height/movieSize.height;
        CGImageRef thumbnail = [scene allocSnapshot: ratio];
        [scene cleanupRendering];
        
        layer = [CALayer layer];
        layer.frame = CGRectMake(0,0,size.width,size.height);
        layer.contents = (id)thumbnail;
        
        CGImageRelease(thumbnail);
    }
    else
    {
        // transition処理
        CGFloat w = CGImageGetWidth(transitionImage);
        CGFloat h = CGImageGetHeight(transitionImage);
        layer = [CALayer layer];
        layer.frame = CGRectMake(0,0, w, h);
        layer.contents = (id)transitionImage;
    }
    
    layer.shadowOpacity = 0.5;
    layer.borderColor = borderColor;
    CGColorRelease(borderColor);
    return layer;
}

- (void)updatePositionFrom:(NSUInteger)index
{
    id segments = [content.obj valueForKeyPath: content.keyPath];
    NSRect bounds = [self bounds];
    NSUInteger limit = [segments count];
    if(index >= limit)
        index = 0;
    
    CGFloat x = 0;
    CGFloat y = NSMidY(bounds);
    if(index != 0)
    {
        id key = [segments objectAtIndex: index-1];
        CALayer *layer = [layerTable objectForKey: key];
        x = NSMaxX(layer.frame);
    }

    for(NSUInteger i=index;i<limit;i++)
    {
        CALayer *layer = [layerTable objectForKey: [segments objectAtIndex: i]];
        // フレーム計算
        NSSize size = layer.frame.size;
        x += cLayerSperator+size.width/2.0;
        layer.position = CGPointMake(x,y);
        x += size.width/2.0;
    }
    x += cLayerSperator;
    minSize = CGSizeMake(x, NSHeight(bounds));
    [self sizeToFit];
}

- (void)completeLayers:(NSArray*)segments
{
    [self detachEmptyLayer];
    for(id layer in [layerTable objectEnumerator])
    {
        [layer removeFromSuperlayer];
    }
    [layerTable removeAllObjects];
    [reverseTable removeAllObjects];
    
    NSRect bounds = [self bounds];
    CALayer *bgLayer = [self layer];
    CGFloat x = 0;
    CGFloat y = NSMidY(bounds);
    for(id aSegment in segments)
    {
        CALayer *layer = [self layerForSegment: aSegment];
        // フレーム計算
        NSSize size = layer.frame.size;
        x += cLayerSperator+size.width/2.0;
        layer.position = CGPointMake(x,y);
        x += size.width/2.0;
        [bgLayer addSublayer: layer];
        [layerTable setObject: layer
                       forKey: aSegment];
        [reverseTable setObject: aSegment
                       forKey: layer];
    }
    if([segments count] == 0)
    {
        [self attachEmptyLayerIfNeed];
    }
    else
    {
        x += cLayerSperator;
        minSize = CGSizeMake(x, NSHeight(bounds));
    }
    [self sizeToFit];
}

- (void)insertLayers:(NSArray*)segments
           atIndexes:(NSIndexSet*)indexes
// 与えられたsegmentをそれぞれindexに配列
{
    id bgLayer = [self layer];
    __block NSUInteger i = 0;
    [indexes enumerateIndexesUsingBlock: ^(NSUInteger idx, BOOL *sotp) {
        id segment = [segments objectAtIndex: i++];
        id layer = [self layerForSegment: segment];
        [bgLayer insertSublayer: layer atIndex: (unsigned)idx];
        [layerTable setObject: layer forKey: segment];
        [reverseTable setObject: segment forKey: layer];
    }];
}

- (void)removeLayers:(NSArray*)segments
{
    for(id segment in segments)
    {
        id layer = [layerTable objectForKey: segment];
        [layer removeFromSuperlayer];
        [reverseTable removeObjectForKey: layer];
        [layerTable removeObjectForKey: segment];
    }
}

- (void)replaceLayersOf:(NSArray*)oldSegments
                   with:(NSArray*)newSegments
{
    NSUInteger limit = [oldSegments count];
    for(NSUInteger i=0;i<limit;i++)
    {
        id oldKey = [oldSegments objectAtIndex: i];
        id newKey = [newSegments objectAtIndex: i];
        id layer = [layerTable objectForKey: oldKey];
        [self setImageOfLayer: layer toSegment: newKey];
        [layerTable removeObjectForKey: oldKey];
        [reverseTable setObject: newKey forKey: layer];
        [layerTable setObject: layer forKey: newKey];
    }
}

- (NSUInteger)_indexOfLayer:(CALayer*)aLayer
{
    id seg = [reverseTable objectForKey: aLayer];
    if(seg == nil)
        return NSNotFound;
    id array = [content.obj valueForKeyPath: content.keyPath];
    return [array indexOfObject: seg];
}

- (void)_selectLayers:(NSIndexSet*)indexes
{
    // deselect & new selection
    id layers = [[self layer] sublayers];
    for(CALayer *layer in layers)
        layer.borderWidth = 0.0;
    
    id segments = [content.obj valueForKeyPath: content.keyPath];
    [indexes enumerateIndexesUsingBlock: ^(NSUInteger idx, BOOL *stop)
     {
         id aSegment = [segments objectAtIndex: idx];
         CALayer *layer = [layerTable objectForKey: aSegment];
         layer.borderWidth = 3.0;
     }];
}

#pragma mark Selection
- (void)_selectInserted:(NSIndexSet*)indexes
{
    if([indexes count] == 1)
        [selection.obj setValue: indexes 
                     forKeyPath: selection.keyPath];
    else
    {
        // もしシーンが一つだけ含まれるならばそれを選択
        id segments = [content.obj valueForKeyPath: content.keyPath];
        id inserted = [segments objectsAtIndexes: indexes];
        Class Scene = [ECDSceneSegment class];
        NSInteger count = 0;
        NSUInteger limit = [inserted count];
        NSUInteger idx;
        for(NSUInteger i=0;i<limit;i++)
        {
            id obj = [inserted objectAtIndex: i];
            if([obj isKindOfClass: Scene])
            {
                count++;
                idx = i;
            }
        }
        if(count == 1)
        {
            id obj = [inserted objectAtIndex: idx];
            NSUInteger orig_idx = [segments indexOfObject: obj];
            [selection.obj setValue: [NSIndexSet indexSetWithIndex: orig_idx]
                         forKeyPath: selection.keyPath];
        }
        else
            [selection.obj setValue: indexes 
                         forKeyPath: selection.keyPath];
    }
}
- (void)deselectAll
{
    [selection.obj setValue: [NSIndexSet indexSet]
                 forKeyPath: selection.keyPath];
}

#pragma mark KVO
- (void)bind:(NSString *)binding
    toObject:(id)observable 
 withKeyPath:(NSString *)keyPath 
     options:(NSDictionary *)options
{
    if([binding isEqualToString: @"content"])
    {
        content.obj = observable;
        [content.keyPath release];
        content.keyPath = [keyPath copy];
        [observable addObserver: self
                     forKeyPath: keyPath
                        options: (NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew | NSKeyValueObservingOptionInitial)
                        context: _contentBindingContext];
        return;
    }

    if([binding isEqualToString: @"selectedIndexes"])
    {
        selection.obj = observable;
        [selection.keyPath release];
        selection.keyPath = [keyPath copy];
        [observable addObserver: self
                     forKeyPath: keyPath
                        options: NSKeyValueObservingOptionNew
                        context: _selectedIndexesBindingContext];
        return;
    }
    
    [super bind: binding toObject: observable withKeyPath: keyPath options: options];
}

- (void)unbind:(NSString *)binding
{
    if([binding isEqualToString: @"content"])
    {
        [content.obj removeObserver: self forKeyPath: content.keyPath];
        [content.keyPath release];
        content.obj = nil; content.keyPath = nil;
        return;
    }
    if([binding isEqualToString: @"selectedIndexes"])
    {
        [selection.obj removeObserver: self forKeyPath: selection.keyPath];
        [selection.keyPath release];
        selection.obj = nil; selection.keyPath = nil;
        return;
    }

    [super unbind: binding];
}

- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary *)change
                       context:(void *)context
{
    if(context == _contentBindingContext)
    {
        id newObjects,oldObjects,indexes;
        NSKeyValueChange type = [[change valueForKey: NSKeyValueChangeKindKey] unsignedIntegerValue];
        switch(type)
        {
            case NSKeyValueChangeSetting:
                [self completeLayers: [object valueForKeyPath: keyPath]];
                [self deselectAll];
                click.prev = NSNotFound;
                keyMove.start = NSNotFound;
                [self scrollToTail];
                break;
            case NSKeyValueChangeReplacement:
                oldObjects = [change objectForKey: NSKeyValueChangeOldKey];
                newObjects = [change objectForKey: NSKeyValueChangeNewKey];
                [self replaceLayersOf: oldObjects with: newObjects];
                break;
            case NSKeyValueChangeRemoval:
                oldObjects = [change objectForKey: NSKeyValueChangeOldKey];
                indexes = [change objectForKey: NSKeyValueChangeIndexesKey];
                [self removeLayers: oldObjects];
                [self updatePositionFrom: [indexes firstIndex]-1]; // トリッキーだが、-1>他の全てだから問題ない
                [self attachEmptyLayerIfNeed];
                [self deselectAll];
                click.prev = NSNotFound;
                keyMove.start = NSNotFound;
                break;
            case NSKeyValueChangeInsertion:
                newObjects = [change objectForKey: NSKeyValueChangeNewKey];
                indexes = [change objectForKey: NSKeyValueChangeIndexesKey];
                [self insertLayers: newObjects atIndexes: indexes];
                [self updatePositionFrom: [indexes firstIndex]];
                [self detachEmptyLayer];
                [self scrollTo: [indexes lastIndex]];
                [self _selectInserted: indexes];
                click.prev = NSNotFound;
                keyMove.start = NSNotFound;
                break;
        }
        
        return;
    }
    
    if(context == _selectedIndexesBindingContext)
    {
        id after  = [change objectForKey: NSKeyValueChangeNewKey];
        [self _selectLayers: after];
        return;
    }
    
    [super observeValueForKeyPath: keyPath ofObject:object change:change context:context];
}

#pragma mark Visibility
- (void)scrollTo:(NSUInteger)idx
{
    id segments = [content.obj valueForKeyPath: content.keyPath];
    id seg = [segments objectAtIndex: idx];
    id layer = [layerTable objectForKey: seg];
    NSRect frame = [layer frame];
    NSRect visibleRect = [self visibleRect];
    
    // 完全に見えている場合は何もしない
    if(NSContainsRect(visibleRect, frame))
        return;
    
    CGFloat x;
    // 理想的原点の計算
    if(NSMinX(frame) > NSMinX(visibleRect))
    {
        // 右側に出っ張っている
        x = NSMaxX(frame)+cLayerSperator-NSWidth(visibleRect);
    }
    else
    {
        // 左側に出っ張っている
        x = NSMinX(frame)-cLayerSperator;
    }
    
    NSPoint point = NSMakePoint(x, 0);
    [[[self enclosingScrollView] documentView] scrollPoint: point];
}

- (void)scrollToTail
{
    [[[self enclosingScrollView] documentView] scrollPoint: NSMakePoint(FLT_MAX,0)];
}

#pragma mark Interaction
- (void)_testShiftSelection:(NSUInteger)idx
{
    id now = [[[selection.obj valueForKeyPath: selection.keyPath] mutableCopy] autorelease];
    if(click.prev == NSNotFound)
    {  // 基準点がないならば、現在の選択状態を見て決める
        click.prev = idx;
        
        if([now count] == 0)
        {
            // 何もない時は単純に追加？
            [now addIndex: idx];
            [selection.obj setValue: now forKey: selection.keyPath];
            return;
        }
        else
        {
            // 近いindexとの間を埋める
            // ここに来るのは恐らく挿入されたセグメントが自動で新規選択された場合で、
            // この時基準点はクリアされているので開始点を特定できない
            NSUInteger lt = [now indexLessThanIndex: idx];
            NSUInteger gt = [now indexGreaterThanIndex: idx];
            NSRange range;
            if(lt != NSNotFound)
            {
                if(gt != NSNotFound)
                {
                    // 近い方へfill
                    if(gt-idx > idx-lt)
                    {
                        range = NSMakeRange(idx, gt-idx);
                    }
                    else
                    {
                        range = NSMakeRange(lt+1, idx-lt);
                    }
                }
                else
                {
                    // ltを採用
                    range = NSMakeRange(lt+1, idx-lt);
                }
            }
            else
            {
                // gtを採用
                range = NSMakeRange(idx, gt-idx);
            }
            [now addIndexesInRange: range];
            [selection.obj setValue: now forKey: selection.keyPath];
            return;
        }
    }
    else
    {
        // 基準点があるならば、間をfill
        NSRange range;
        if(click.prev > idx)
        {
            range = NSMakeRange(idx, click.prev-idx+1);
        }
        else
        {
            range = NSMakeRange(click.prev,idx-click.prev+1); // 0 の時は大丈夫か？
        }
        id set = [NSIndexSet indexSetWithIndexesInRange: range];
        [selection.obj setValue: set forKey: selection.keyPath];
    }
    return ;
}

- (void)_interpretClick:(NSUInteger)idx
               modifier:(NSUInteger)modifier
{    
    if(modifier & NSCommandKeyMask)
    {
        // 選択の反転
        id now = [[[selection.obj valueForKeyPath: selection.keyPath] mutableCopy] autorelease];
        if([now containsIndex: idx])
            [now removeIndex: idx];
        else
            [now addIndex: idx];
        [selection.obj setValue: now forKeyPath: selection.keyPath];
        click.prev = idx;
        return;
    }
    
    if(modifier & NSShiftKeyMask)
    {
        [self _testShiftSelection: idx];
        return;
    }
    
    [selection.obj setValue: [NSIndexSet indexSetWithIndex: idx]
                 forKeyPath: selection.keyPath];
    click.prev = idx;
}

// 現在のポインタ状態からイベント評価を行う
// click/dragで共通
- (void)_testMouse:(NSPoint)point
          modifier:(NSUInteger)modifier
{
    id layers = [[self layer] sublayers];
    for(CALayer *layer in layers)
    {
        if(layer == emptyLayer)
            continue;
        NSRect frame = [layer frame];
        if(NSPointInRect(point, frame))
        {
            NSUInteger idx = [self _indexOfLayer: layer];
            [self _interpretClick: idx modifier: modifier];
            return;
        }
    }
    
    if(modifier & NSShiftKeyMask || modifier & NSCommandKeyMask)
        return;
    
    // dselect
    [selection.obj setValue: [NSIndexSet indexSet]
                 forKeyPath: selection.keyPath];
    click.prev = NSNotFound;
}

- (void)_testDoubleClick:(NSPoint)point
{
    id layers = [[self layer] sublayers];
    for(CALayer *layer in layers)
    {
        if(layer == emptyLayer)
            continue;
        NSRect frame = [layer frame];
        if(NSPointInRect(point, frame))
        {
            id segments = [content.obj valueForKeyPath: content.keyPath];
            NSUInteger idx = [self _indexOfLayer: layer];
            id segment = [segments objectAtIndex: idx];
            id ui = [NSDictionary dictionaryWithObject: segment
                                                forKey: @"segment"];
            [[NSNotificationCenter defaultCenter]
             postNotificationName: ECStoryBoardViewLayerSegmentRequestNotification
             object: self
             userInfo: ui];
            return;
        }
    }
}

- (void)_tryAction
{
    if(target && action)
        [NSApp sendAction: action 
                       to: target 
                     from: self];
}

- (void)_tryDoubleAction
{
    if(target && doubleAction)
        [NSApp sendAction: doubleAction
                       to: target
                     from: self];
}

- (void)mouseDown:(NSEvent*)theEvent
{
    click.start = [self convertPoint: [theEvent locationInWindow]
                            fromView: nil];
    keyMove.start = NSNotFound; // キーの移動をリセット
    NSUInteger modifier = [theEvent modifierFlags];
    NSUInteger count = [theEvent clickCount];
    switch(count)
    {
        case 1:
            [self _testMouse: click.start modifier: modifier];
            [self _tryAction];
            break;
        case 2:
            // reload scene
            [self _testDoubleClick: click.start];
            [self _tryDoubleAction];
            break;
        default:
            ; // ignore
    }
}

- (void)mouseDragged:(NSEvent*)theEvent
{
    NSPoint point = [self convertPoint: [theEvent locationInWindow]
                              fromView: nil];
    NSUInteger modifier = [theEvent modifierFlags];
    [self _testMouse: point modifier: modifier];
    [self autoscroll: theEvent];
}

- (void)keyDown:(NSEvent *)theEvent
{
    [self interpretKeyEvents:[NSArray arrayWithObject:theEvent]];
}

- (void)moveLeft:(id)sender
{
    id index = [selection.obj valueForKeyPath: selection.keyPath];
    NSUInteger idx = [index firstIndex];
    if(idx == NSNotFound)
        idx = 0;
    
    if(idx == 0)
    {
        [selection.obj setValue: [NSIndexSet indexSetWithIndex: 0]
                     forKeyPath: selection.keyPath];
        keyMove.start = 0;
        [self scrollTo: 0];
        [self _tryAction];        
    }

    id segments = [content.obj valueForKeyPath: content.keyPath];
    CFIndex i = idx-1;
    for(;i >= 0; i--)
    {
        id leftSegment = [segments objectAtIndex: i];
        if([leftSegment isKindOfClass: [ECDSceneSegment class]])
        {
            // これを選択すべき
            [selection.obj setValue: [NSIndexSet indexSetWithIndex: i]
                         forKeyPath: selection.keyPath];
            keyMove.start = i;
            [self scrollTo: i];
            [self _tryAction];
            return;
        }
    }
}

- (void)moveRight:(id)sender
{
    id index = [selection.obj valueForKeyPath: selection.keyPath];
    id segments = [content.obj valueForKeyPath: content.keyPath];
    NSUInteger idx = [index lastIndex];
    NSUInteger limit = [segments count];
    if([index count] == 0)
        idx = limit -1;
    
    if(idx == limit-1)
    {
        [selection.obj setValue: [NSIndexSet indexSetWithIndex: limit-1]
                         forKey: selection.keyPath];
        keyMove.start = limit-1;
        [self scrollTo: limit-1];
        [self _tryAction];
    }
    
    CFIndex i = idx+1;
    for(;i<limit; i++)
    {
        id rightSegment = [segments objectAtIndex: i];
        if([rightSegment isKindOfClass: [ECDSceneSegment class]])
        {
            [selection.obj setValue: [NSIndexSet indexSetWithIndex: i]
                         forKeyPath: selection.keyPath];
            keyMove.start = i;
            [self scrollTo: i];
            [self _tryAction];
            return;
        }
    } 
}

- (void)moveLeftAndModifySelection:(id)sender
{
    id index = [selection.obj valueForKeyPath: selection.keyPath];
    if([index count] == 0)
        return;
    
    if(keyMove.start != NSNotFound)
    {
        NSUInteger last = [index lastIndex];
        NSRange range;
        if(last != keyMove.start)
        {
            // 右へ伸びていると考えられる -> 短くする
            range = NSMakeRange(keyMove.start, last-keyMove.start);
            [selection.obj setValue: [NSIndexSet indexSetWithIndexesInRange: range]
                             forKey: selection.keyPath];
            [self scrollTo: NSMaxRange(range)-1];
        }
        else
        {
            // 左へ伸ばす。一致する場合も含む
            NSUInteger first = [index firstIndex];
            if(first == 0)
                return; 
            range = NSMakeRange(first-1, keyMove.start-first+2);
            [selection.obj setValue: [NSIndexSet indexSetWithIndexesInRange: range]
                             forKey: selection.keyPath];
            [self scrollTo: range.location];
        }
    }
    else
    {
        keyMove.start = [index firstIndex]; // 0でも起点の設定はする
        if(keyMove.start == 0)
            return;
        
        NSRange range = NSMakeRange(keyMove.start-1, 2);
        [selection.obj setValue: [NSIndexSet indexSetWithIndexesInRange: range]
                         forKey: selection.keyPath];
        [self scrollTo: range.location];
    }
    [self _tryAction];
}

- (void)moveRightAndModifySelection:(id)sender
{
    id index = [selection.obj valueForKeyPath: selection.keyPath];
    if([index count] == 0)
        return;
    
    if(keyMove.start != NSNotFound)
    {
        NSUInteger first = [index firstIndex];
        NSRange range;
        if(first < keyMove.start)
        {
            // 左に延びていると考えられる->短くする
            range = NSMakeRange(first+1, keyMove.start-first);
            [selection.obj setValue: [NSIndexSet indexSetWithIndexesInRange: range]
                             forKey: selection.keyPath];
            [self scrollTo: range.location];
        }
        else
        {
            // 右に延ばす
            NSUInteger last = [index lastIndex];
            id segments = [content.obj valueForKeyPath: content.keyPath];
            NSUInteger limit = [segments count];
            if(last == limit-1)
                return;
            range = NSMakeRange(keyMove.start, last-keyMove.start+2);
            [selection.obj setValue: [NSIndexSet indexSetWithIndexesInRange: range]
                             forKey: selection.keyPath];
            [self scrollTo: NSMaxRange(range)-1];
        }
    }
    else
    {
        keyMove.start = [index lastIndex]; // 末尾でも起点設定はする
        id segments = [content.obj valueForKeyPath: content.keyPath];
        NSUInteger limit = [segments count];
        if(keyMove.start == limit-1)
            return;
        NSRange range = NSMakeRange(keyMove.start, 2);
        [selection.obj setValue: [NSIndexSet indexSetWithIndexesInRange: range]
                         forKey: selection.keyPath];
    }
    [self _tryAction];

}
- (IBAction)deselect:(id)sender
{
    [self deselectAll];
}

- (void)deleteBackward:(id)sender
{
    [delegate deleteSelection: self];
}

- (IBAction)cut:(id)sender
{
    [delegate copySelection: self];
    [delegate deleteSelection: self];
}

- (IBAction)copy:(id)sender
{
    [delegate copySelection: self];
}

- (IBAction)paste:(id)sender
{
    [delegate pasteOnSelection: self];
}

- (IBAction)pasteAfter:(id)sender
{
    [delegate pasteAfterSelection: self];
}

- (IBAction)pasteBefore:(id)sender
{
    [delegate pasteBeforeSelection: self];
}
@end
