//
//  ECTimelineManager.m
//  Etokicho
//
//  Created by 二鏡 on 11/12/07.
//  Copyright (c) 2011年 二鏡庵. All rights reserved.
//

#import "ECTimelineManager.h"

static NSString *oSegmentsContext = @"Segments";

@implementation ECTimelineManager
@synthesize selection, timeline, context;

+ (NSSet*)keyPathsForValuesAffectingValueForKey:(NSString *)key
{
    if([key isEqualToString: @"selectedSegment"])
        return [NSSet setWithObject: @"selection"];
    if([key isEqualToString: @"totalTimeString"])
        return [NSSet setWithObject: @"segments"];

    return [super keyPathsForValuesAffectingValueForKey: key];
}

- (void)_prepareTimeline
{
    id entity = [NSEntityDescription entityForName: @"Timeline"
                            inManagedObjectContext: context];
    timeline = [[ECDTimeline alloc] initWithEntity: entity
                    insertIntoManagedObjectContext: context];
    [context processPendingChanges];
    
    [timeline addObserver: self
               forKeyPath: @"segments"
                  options: 0
                  context: oSegmentsContext];
}

- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary *)change
                       context:(void *)aContext
{
    if (aContext == oSegmentsContext) {
        // スマートじゃないのだが、一番てっとりばやい
        [self willChangeValueForKey: @"selectedSegment"];
        [context processPendingChanges];
        [self didChangeValueForKey: @"selectedSegment"];
        return ;
    } else {
        [super observeValueForKeyPath:keyPath ofObject:object change:change context:aContext];
    }
}

- (id)init
{
    self = [super init];
    id modelURL = [[NSBundle mainBundle] URLForResource: @"Timeline"
                                          withExtension: @"momd"];
    id model = [[NSManagedObjectModel alloc] initWithContentsOfURL: modelURL];
    id coord = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: model];
    context = [[NSManagedObjectContext alloc] init];
    [coord addPersistentStoreWithType: NSInMemoryStoreType
                        configuration: nil
                                  URL: nil
                              options: nil
                                error: nil];
    [context setPersistentStoreCoordinator: coord];
    
    [model release];
    [coord release];
    id undo = [context undoManager];
    [undo disableUndoRegistration];
    [self _prepareTimeline];
    [undo enableUndoRegistration];
    
    [self resetUndo];
    [self startUndoTracking: undo];
    
    [[NSNotificationCenter defaultCenter] addObserver: self
                                             selector: @selector(contextDidChange:)
                                                 name: NSManagedObjectContextObjectsDidChangeNotification
                                               object: context];
    return self;
}

- (BOOL)isEmpty
{
    return [[timeline segments] count] == 0;
}

- (BOOL)hasChange
{
    return changeCount != 0;
}

- (void)resetUndo:(id)obj
{
    [[context undoManager] removeAllActions];
    changeCount = 0;
}

- (void)resetUndo
{
    [self performSelectorOnMainThread: @selector(resetUndo:)
                           withObject: nil
                        waitUntilDone: YES];
}

- (void)reset
{
    [self willChangeValueForKey: @"timeline"];
    [timeline removeObserver: self
                  forKeyPath: @"segments"];
    [timeline release];
    [context reset];
    id undo = [context undoManager];
    // タイムラインの初期化はundo外に置く
    [undo disableUndoRegistration];
    
    [self _prepareTimeline];
    [undo enableUndoRegistration];
    
    self.selection = [NSIndexSet indexSet];
    [self didChangeValueForKey: @"timeline"];
}

- (void)resetWithFPS:(NSInteger)fps
{
    [self willChangeValueForKey: @"timeline"];
    [timeline removeObserver: self
                  forKeyPath: @"segments"];
    [timeline release];
    [context reset];
    id undo = [context undoManager];
    // タイムラインの初期化はundo外に置く
    [undo disableUndoRegistration];
    
    [self _prepareTimeline];
    timeline.fps = fps;

    [undo enableUndoRegistration];
    [undo removeAllActions];
   
    self.selection = [NSIndexSet indexSet];
    [self didChangeValueForKey: @"timeline"];
}

- (NSUndoManager*)undoManager
{
    return [context undoManager];
}

- (ECDSegment*)attachNewSegmentOfType:(NSString*)type
{
    return nil;
}

- (ECDSegment*)selectedSegment
{
    switch([selection count])
    {
        case 0:
            return NSNoSelectionMarker;
        case 1:
            return [[timeline segments] objectAtIndex: [selection firstIndex]];
        default:
            return NSMultipleValuesMarker;
    }
}

- (void)contextDidChange:(id)notif
{
    [self willChangeValueForKey: @"totalTimeString"];
    [self didChangeValueForKey: @"totalTimeString"];
}

@end

#pragma mark -
@implementation ECTimelineManager (Undo)
- (void)updateChangeCount:(NSDocumentChangeType)val
{
    switch(val)
    {
        case NSChangeDone:
            changeCount++;
            break;
        case NSChangeUndone:
            changeCount--;
            break;
        case NSChangeRedone:
            changeCount++;
            break;
        case NSChangeCleared:
            changeCount = 0;
            break;
        default:
            break;
    }
}

- (void)startUndoTracking:(NSUndoManager*)undo {
	id center = [NSNotificationCenter defaultCenter];
    [center addObserver: self
               selector: @selector(_didRedo_:) 
                   name: NSUndoManagerDidRedoChangeNotification
                 object: undo];
    [center addObserver: self
               selector: @selector(_didUndo_:)
                   name: NSUndoManagerDidUndoChangeNotification
                 object: undo];
    [center addObserver: self
               selector: @selector(_willCloseUndo_:)
                   name: NSUndoManagerWillCloseUndoGroupNotification
                 object: undo];
}

- (void)stopUndoTracking:(NSUndoManager*)undo {
	id center = [NSNotificationCenter defaultCenter];
	[center removeObserver: self
                      name: NSUndoManagerDidRedoChangeNotification
                    object: undo];
	[center removeObserver: self
                      name: NSUndoManagerDidUndoChangeNotification
                    object: undo];
	[center removeObserver: self
                      name: NSUndoManagerDidOpenUndoGroupNotification
                    object: undo];
}

- (void)_didUndo_:(id)notif {
    [self updateChangeCount: NSChangeUndone];
}
- (void)_didRedo_:(id)notif {
    [self updateChangeCount: NSChangeRedone];
}
- (void)_willCloseUndo_:(id)notif {
    [self updateChangeCount: NSChangeDone];
}
@end
