//
//  XspfQTPlayerMovieMode.m
//  XspfQT
//
//  Created by Hori,Masaki on 2013/06/25.
//  Copyright (c) 2013年 masakih. All rights reserved.
//

#import "XspfQTPlayerMovieMode.h"


#import <QTKit/QTKit.h>

#import "HMXSPFComponent.h"
#import "NSURL-HMExtensions.h"
#import "XspfQTMovieLoader.h"
#import "XspfQTMovieTimer.h"
#import "XspfQTPreference.h"


static NSString *XspfQTCurrentTrackKey = @"currentTrack";


@interface XspfQTPlayerMovieMode ()

@property (retain) XspfQTMovieLoader *loader;
@property BOOL didJoin;

@end

@implementation XspfQTPlayerMovieMode
@synthesize loader = _loader;
@synthesize didJoin = _didJoin;


static XspfQTMovieTimer* timer = nil;
+ (void)initialize
{
	static BOOL isFirst = YES;
	if(isFirst) {
		isFirst = NO;
		timer = [[XspfQTMovieTimer movieTimerWithFireInterval:0.5] retain];
	}
}

- (id)init
{
	self = [super init];
	if(self) {
		_loader = [[XspfQTMovieLoader loaderWithMovieURL:nil] retain];
		[timer put:self];
	}
	
	return self;
}

- (void)dealloc
{
	[_loader release];
	[timer remove:self];
	
	[[_playlist childAtIndex:0] removeObserver:self forKeyPath:XspfQTCurrentTrackKey];
	[_playlist release];
	
	NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
	[nc removeObserver:self];
	[_playingMovie release];
	
	[durations release];
	
	[super dealloc];
}

- (void)setPlaylist:(HMXSPFComponent *)newList
{
	if(_playlist == newList) return;
	
	[[_playlist childAtIndex:0] removeObserver:self forKeyPath:XspfQTCurrentTrackKey];
	[_playlist autorelease];
	_playlist = [newList retain];
	[[_playlist childAtIndex:0] addObserver:self
								 forKeyPath:XspfQTCurrentTrackKey
									options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
									context:NULL];
	
	if(!newList) {
		[timer remove:self];
	}
}
- (HMXSPFComponent *)playlist
{
	return _playlist;
}

- (HMXSPFComponent *)trackList
{
	return [self.playlist childAtIndex:0];
}

+ (NSSet *)keyPathsForValuesAffectingPlayingMovieDuration
{
	return [NSSet setWithObject:@"playingMovie"];
}
- (void)setPlayingMovie:(QTMovie *)newMovie
{
	NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
	if(_playingMovie) {
		[nc removeObserver:self
					  name:nil
					object:_playingMovie];
	}
	
	[_playingMovie autorelease];
	_playingMovie = [newMovie retain];
	self.playingMovieDuration = 0;
	
	if(_playingMovie) {
		[nc addObserver:self
			   selector:@selector(notifee:)
				   name:QTMovieRateDidChangeNotification
				 object:_playingMovie];
	}
}
- (QTMovie *)playingMovie
{
	return _playingMovie;
}
- (void)setPlayingMovieDuration:(NSTimeInterval)playingMovieDuration
{
	_playingMovieDuration = playingMovieDuration;
}
- (NSTimeInterval)playingMovieDuration
{
	if(_playingMovieDuration == 0) {
		QTTime qttime = [self.playingMovie duration];
		if(!QTGetTimeInterval(qttime, &_playingMovieDuration)) _playingMovieDuration = 0;
	}
	
	return _playingMovieDuration;
}

- (void)buildStartPositionsWithDurations:(NSArray *)aDurations
{
	QTTime time = QTZeroTime;
	NSMutableArray *aStartPoints = [NSMutableArray array];
	[aStartPoints addObject:[NSValue valueWithQTTime:time]];
	
	for(id value in aDurations) {
		QTTime aTime = [value QTTimeValue];
		time = QTTimeIncrement(time, aTime);
		[aStartPoints addObject:[NSValue valueWithQTTime:time]];
	}
	durations = [[NSArray alloc] initWithArray:aStartPoints];
}
- (void)joinMovie
{
	QTMovie *theMovie = [QTMovie movie];
	[theMovie setMovieAttributes:@{QTMovieEditableAttribute:@YES}];
	
	HMXSPFComponent *trackList = self.trackList;
	
	NSMutableArray *aDurations = [NSMutableArray array];
	
	NSArray *children = [trackList children];
	BOOL firstTime = YES;
	for(HMXSPFComponent *track in children) {
		//
		self.loader.movieURL = [track movieLocation];
		[self.loader load];
		QTMovie *aMovie = self.loader.qtMovie;
		
		QTTime qttime = [aMovie duration];
		[aDurations addObject:[NSValue valueWithQTTime:qttime]];
		id t = [NSValueTransformer valueTransformerForName:@"XspfQTTimeDateTransformer"];
		[track setCurrentTrackDuration:[t transformedValue:[NSValue valueWithQTTime:qttime]]];
		
		QTTimeRange aMovieRange = QTMakeTimeRange(QTZeroTime, [aMovie duration]);		
		if(firstTime) {
			[aMovie setSelection:aMovieRange];
			[theMovie appendSelectionFromMovie:aMovie];
		} else {			
			QTTime insertPoint = [theMovie duration];
			insertPoint = QTTimeDecrement(insertPoint, QTMakeTimeWithTimeInterval(0.05));
			[theMovie insertSegmentOfMovie:aMovie timeRange:aMovieRange atTime:insertPoint];
		}
		firstTime = NO;
	}
	
	[self buildStartPositionsWithDurations:aDurations];
	
	self.playingMovie = theMovie;
}

- (void)moveToStartPointNuber:(id)number
{
	NSUInteger index = [[self.trackList children] indexOfObject:number];
	QTTime time = [[durations objectAtIndex:index] QTTimeValue];
	[self.playingMovie setCurrentTime:time];
}
- (void)observeValueForKeyPath:(NSString *)keyPath
					  ofObject:(id)object
						change:(NSDictionary *)change
					   context:(void *)context
{
	if([keyPath isEqualToString:XspfQTCurrentTrackKey]) {
		if(self.didJoin) {
			if(ignoreChangeTrackEvent) return;
			id number = [change objectForKey:NSKeyValueChangeNewKey];
			[self moveToStartPointNuber:number];
			[self.playingMovie play];
		} else {
			self.didJoin = YES;
			[self joinMovie];
		}
	}
}


- (void)notifee:(id)notification
{
	HMXSPFComponent *track = self.trackList.currentTrack;
	NSNumber *rateValue = [[notification userInfo] objectForKey:QTMovieRateDidChangeNotificationParameter];
	if(rateValue) {
		float rate = [rateValue floatValue];
		if(rate == 0) {
			track.isPlayed = NO;
			[timer suspend:self];
		} else {
			track.isPlayed = YES;
			[timer resume:self];
		}
	}
}

// call from XspfQTMovieTimer.
- (void)fire
{
	// 現在のdurationを取得
	QTTime duration = [self.playingMovie currentTime];
	
	// 選択トラックを取得
	HMXSPFComponent *currentTrack = self.trackList.currentTrack;
	
	// 選択トラックが再生中か？
	// durationに合うトラックを取得
	NSUInteger index = [self.trackList indexOfChild:currentTrack];
	NSUInteger playingIndex = NSNotFound;
	
	NSUInteger i = 0;
	for(id time in durations) {
		QTTime qtTime = [time QTTimeValue];
		if(QTTimeCompare(qtTime, duration) == NSOrderedDescending) {
			playingIndex = i - 1;
			break;
		}
		i++;
	}
	// 再生中ならreturn
	if(index == playingIndex) return;
	
	// 再生中トラックを選択
	ignoreChangeTrackEvent = YES;
	self.trackList.selectionIndex = playingIndex;
	ignoreChangeTrackEvent = NO;
}
@end
