//
//  OutputNode.m
//  Cog
//
//  Created by Vincent Spader on 8/2/05.
//  Copyright 2005 Vincent Spader. All rights reserved.
//

#import "OutputNode.h"
#import "AudioPlayer.h"
#import "BufferChain.h"
#import "OutputCoreAudio.h"

#import "Logging.h"

@implementation OutputNode

- (void)setup {
	amountPlayed = 0.0;
	amountPlayedInterval = 0.0;

	paused = YES;
	started = NO;
	intervalReported = NO;

	output = [[OutputCoreAudio alloc] initWithController:self];

	[output setup];
}

- (void)seek:(double)time {
	//	[output pause];
	[self resetBuffer];

	amountPlayed = time;
}

- (void)process {
	paused = NO;
	[output start];
}

- (void)pause {
	paused = YES;
	[output pause];
}

- (void)resume {
	paused = NO;
	[output resume];
}

- (void)incrementAmountPlayed:(double)seconds {
	amountPlayed += seconds;
	amountPlayedInterval += seconds;
	if(!intervalReported && amountPlayedInterval >= 60.0) {
		intervalReported = YES;
		[controller reportPlayCount];
	}
}

- (void)resetAmountPlayed {
	amountPlayed = 0;
}

- (void)resetAmountPlayedInterval {
	amountPlayedInterval = 0;
	intervalReported = NO;
}

- (void)endOfInputPlayed {
	if(!intervalReported) {
		intervalReported = YES;
		[controller reportPlayCount];
	}
	[controller endOfInputPlayed];
	[self resetAmountPlayedInterval];
}

- (BOOL)chainQueueHasTracks {
	return [controller chainQueueHasTracks];
}

- (double)secondsBuffered {
	return [buffer listDuration];
}

- (AudioChunk *)readChunk:(size_t)amount {
	@autoreleasepool {
		[self setPreviousNode:[[controller bufferChain] finalNode]];

		AudioChunk *ret = [super readChunk:amount];

		/*	if (n == 0) {
		        DLog(@"Output Buffer dry!");
		    }
		*/
		return ret;
	}
}

- (double)amountPlayed {
	return amountPlayed;
}

- (double)amountPlayedInterval {
	return amountPlayedInterval;
}

- (AudioStreamBasicDescription)format {
	return format;
}

- (uint32_t)config {
	return config;
}

- (void)setFormat:(AudioStreamBasicDescription *)f channelConfig:(uint32_t)channelConfig {
	format = *f;
	config = channelConfig;
	// Calculate a ratio and add to double(seconds) instead, as format may change
	// double oldSampleRatio = sampleRatio;
	BufferChain *bufferChain = [controller bufferChain];
	if(bufferChain) {
		ConverterNode *converter = [bufferChain converter];
		if(converter) {
			// This clears the resampler buffer, but not the input buffer
			// We also have to jump the play position ahead accounting for
			// the data we are flushing
			amountPlayed += [[converter buffer] listDuration];

			AudioStreamBasicDescription inf = [bufferChain inputFormat];
			uint32_t config = [bufferChain inputConfig];

			format.mChannelsPerFrame = inf.mChannelsPerFrame;
			format.mBytesPerFrame = ((inf.mBitsPerChannel + 7) / 8) * format.mChannelsPerFrame;
			format.mBytesPerPacket = format.mBytesPerFrame * format.mFramesPerPacket;
			channelConfig = config;

			[converter setOutputFormat:format
			              outputConfig:channelConfig];
			[converter inputFormatDidChange:[bufferChain inputFormat] inputConfig:[bufferChain inputConfig]];
		}
	}
}

- (void)close {
	[output stop];
	output = nil;
}

- (void)setVolume:(double)v {
	[output setVolume:v];
}

- (void)setShouldContinue:(BOOL)s {
	[super setShouldContinue:s];

	//	if (s == NO)
	//		[output stop];
}

- (BOOL)isPaused {
	return paused;
}

- (void)beginEqualizer:(AudioUnit)eq {
	[controller beginEqualizer:eq];
}

- (void)refreshEqualizer:(AudioUnit)eq {
	[controller refreshEqualizer:eq];
}

- (void)endEqualizer:(AudioUnit)eq {
	[controller endEqualizer:eq];
}

- (void)sustainHDCD {
	[output sustainHDCD];
}

- (void)restartPlaybackAtCurrentPosition {
	[controller restartPlaybackAtCurrentPosition];
}

@end
