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

#import "ECProject.h"
#import "ServiceFunctions.h"
#import "ECDSegment.h"
#import "ECScene.h"

NSString *gProjectFileExtension = @"etokiproj";

static NSString *_infoFile = @"info.plist";
static NSString *plistSequenceKey = @"SceneSequence";
static NSString *plistSizeKey = @"Size";
static NSString *plistFPSKey = @"FPS";
static NSString *plistSegmentAuxfileKey = @"Auxfile";
static NSString *plistSegmentInfoKey = @"SegmentInfo";

static NSString *plistSceneType = @"Scene";
static NSString *plistTransitionType = @"Transition";

/*
 *  Project plist
 *   SequenceKey -> ordered list of segment key(number string)
 *   key == segment file name.
 */

@interface ECProject ()
@property (readwrite,copy) NSURL *loadURL;
@end


@implementation ECProject
@synthesize movieSize, loadURL;

+ (NSSet*)keyPathsForValuesAffectingValueForKey:(NSString *)key
{
    if([key isEqualToString: @"projectPath"])
        return [NSSet setWithObject: @"loadURL"];
    return [super keyPathsForValuesAffectingValueForKey: key];
}

- (id)initWithMovieSize:(NSSize)aSize
{
    self = [super init];
    movieSize = aSize;
    return self;
}

- (id)initWithContentsOfURL:(NSURL*)aURL
               intoTimeline:(ECTimelineManager*)timelineManager
{
    self = [super init];
    loadURL = [aURL copy];
    
    id infoURL = [aURL URLByAppendingPathComponent: _infoFile];
    id plist = [NSDictionary dictionaryWithContentsOfURL: infoURL];

    ECDTimeline *timeline = timelineManager.timeline;
    id undo = [timelineManager undoManager];
    [[timelineManager context] processPendingChanges];
    [undo disableUndoRegistration];
    
    id context = timelineManager.context;
    
    movieSize = _sizeFromData([plist objectForKey: plistSizeKey]);
    [timeline setValue: [plist objectForKey: plistFPSKey]
                forKey: @"fps"];

    id sequence = [plist objectForKey: plistSequenceKey];

    for( id key in sequence)
    {
        id segmentURL = [aURL URLByAppendingPathComponent: key];
        id seg = [ECDSegment attachSegmentWithContentsOfURL: segmentURL
                                                  inContext: context];
        if(seg)
            [timeline addSegmentsObject: seg];
    }
    
    [[timelineManager context] processPendingChanges];
    [undo enableUndoRegistration];
    [timelineManager resetUndo];
    return self;
}

- (ECScene*)emptyScene
{
    return [[[ECScene alloc] initWithSize: movieSize] autorelease];
}

- (BOOL)_atomicWriteToURL:(NSURL*)aURL
                 timeline:(ECTimelineManager*)timelineManager
{
    id fm = [NSFileManager defaultManager];
    id error;
    
    id attr = [NSDictionary dictionaryWithObjectsAndKeys:
               [NSNumber numberWithBool: YES], NSFileExtensionHidden,
               nil];
    if([fm createDirectoryAtURL: aURL
    withIntermediateDirectories: YES
                     attributes: attr
                          error: &error] == NO)
        return NO;
    
    ECDTimeline *timeline = timelineManager.timeline;
    id segments = [timeline.segments array];
    
    // 各セグメントを生成
    id plist = [NSMutableDictionary dictionary];
    id sequence = [NSMutableArray array];
    NSInteger i = 0;
    for(ECDSegment *segment in segments)
    {
        id pool = [[NSAutoreleasePool alloc] init];
        id key = [NSString stringWithFormat: @"%ld", i++];
        id segmentURL = [aURL URLByAppendingPathComponent: key];
        if([fm createDirectoryAtURL: segmentURL
        withIntermediateDirectories: YES
                         attributes: nil
                              error: &error] == NO)
        {
            [pool release];
            return NO;
        }
        
        if([segment writeToURL: segmentURL] == NO)
        {
            [pool release];
            return NO;
        }

        [sequence addObject: key];
        [pool release];
    }
    
    // Project Levelの情報
    [plist setObject: sequence
              forKey: plistSequenceKey];
    [plist setObject: _sizeToData(movieSize)
              forKey: plistSizeKey];
    [plist setObject: [timeline valueForKey: @"fps"]
              forKey: plistFPSKey];
    
    id infoURL = [aURL URLByAppendingPathComponent: _infoFile];
    if([plist writeToURL: infoURL
              atomically: NO] == NO)
        return NO;
    
    return YES;
}

- (BOOL)writeToURL:(NSURL*)aURL
      fromTimeline:(ECTimelineManager*)timelineManager
{
    id fm = [NSFileManager defaultManager];
    BOOL isDir, isExist;
    isExist = [fm fileExistsAtPath: [aURL path] isDirectory: &isDir];
    if(isExist != NO && isDir == NO)
    {
        // 既存の通常ファイルがあるので保存できない
        // フォルダの場合は拡張子テストを通過しているものと見なす
        return NO;
    }
    
    // prepare temporary folder
    id error;
    id tempFolder = [fm URLForDirectory: NSItemReplacementDirectory
                               inDomain: NSUserDomainMask
                      appropriateForURL: aURL
                                 create: YES
                                  error: &error];
    
    // 一時フォルダを取得できない
    if(tempFolder == nil)
        return NO;
    
    id tempURL = [tempFolder URLByAppendingPathComponent: @"temp.etokiproj"];
    if([self _atomicWriteToURL: tempURL
                      timeline: timelineManager] == NO)
    {
        // 一時ファイルの生成に失敗した
        [fm removeItemAtURL: tempFolder error: nil];
        return NO;
    }
    
    if(isExist)
        [fm removeItemAtURL: aURL error: nil];
    
    BOOL didMove = [fm moveItemAtURL: tempURL
                               toURL: aURL
                               error: nil];
    [fm removeItemAtURL: tempFolder error: nil];
    if(didMove)
    {
        self.loadURL = aURL;
    }
    return NO;
}
@end


@implementation ECProject (Statics)
- (NSString*)sizeString
{
    size_t width = movieSize.width;
    size_t height = movieSize.height;
    return [NSString stringWithFormat: @"%dx%d", width, height];
}

- (NSString*)projectPath
{
    return [[[loadURL path] stringByAbbreviatingWithTildeInPath] stringByDeletingPathExtension];
}
@end
