#import "AnonymousTerminator.h"
#import "CallAudioManager.h"
#import "PreferencesUtil.h"
#import "ThreadManager.h"
#import "Util.h"

#define SAFETY_FACTOR_FOR_COMPUTE_DELAY 3.0

@implementation CallAudioManager

+(CallAudioManager*) callAudioManagerStartedWithAudioSocket:(AudioSocket*)audioSocket
                                            andErrorHandler:(ErrorHandlerBlock)errorHandler
                                             untilCancelled:(id<CancelToken>)untilCancelledToken {
    require(audioSocket != nil);
    
    AudioProcessor* processor = [AudioProcessor audioProcessor];
    
    CallAudioManager* newCallAudioManagerInstance = [CallAudioManager new];
    newCallAudioManagerInstance->audioProcessor = processor;
    newCallAudioManagerInstance->audioSocket = audioSocket;
    
    [newCallAudioManagerInstance startWithErrorHandler:errorHandler untilCancelled:untilCancelledToken];
    
    return newCallAudioManagerInstance;
}

-(void) startWithErrorHandler:(ErrorHandlerBlock)errorHandler untilCancelled:(id<CancelToken>)untilCancelledToken {
    require(errorHandler != nil);
    require(untilCancelledToken != nil);
    @synchronized(self) {
        requireState(!started);
        started = true;
        if ([untilCancelledToken isAlreadyCancelled]) return;
        audioInterface = [RemoteIOAudio remoteIOInterfaceStartedWithDelegate:self untilCancelled:untilCancelledToken];
        PacketHandlerBlock handler = ^(EncodedAudioPacket* packet) {
            [audioProcessor receivedPacket:packet];
        };
        [audioSocket startWithHandler:[PacketHandler packetHandler:handler
                                                  withErrorHandler:errorHandler]
                       untilCancelled:untilCancelledToken];
    }
}

-(void) handlePlaybackOccurredWithBytesRequested:(NSUInteger)requested andBytesRemaining:(NSUInteger)bytesRemaining {
    if (bytesInPlaybackBuffer >= requested) {
        bytesInPlaybackBuffer -= requested;
    }
    
    NSUInteger bytesAddedIfPullMore = [audioProcessor.codec decodedFrameSizeInBytes];
    double minSafeBufferSize = MAX(requested, bytesAddedIfPullMore)*SAFETY_FACTOR_FOR_COMPUTE_DELAY;
    while (bytesInPlaybackBuffer < minSafeBufferSize) {
        NSData* decodedAudioData = [audioProcessor tryDecodeOrInferFrame];
        if (decodedAudioData == nil) break;
        [audioInterface populatePlaybackQueueWithData:decodedAudioData];
        bytesInPlaybackBuffer += [decodedAudioData length];
    }
}

-(void) handleNewDataRecorded:(CyclicalBuffer*)recordingQueue {
    NSArray* encodedPackets = [audioProcessor encodeAudioPacketsFromBuffer:recordingQueue];
    for (EncodedAudioPacket* packet in encodedPackets) {
        [audioSocket send:packet];
    }
}

-(BOOL) toggleMute {
	return [audioInterface toggleMute];
}

@end
