import { StreamingAudioChannel } from './StreamingAudioChannel';
import { WebAudioChannel } from './WebAudioChannel';
import { IAudioChannel } from './IAudioChannel';
import { EventAudioChannel } from './EventAudioChannel';
import { IAudioChannelClass } from './IAudioChannelClass';

export class AudioManager {
	private static isIE: boolean=!!navigator.userAgent.match(/Trident/g) || !!navigator.userAgent.match(/MSIE/g);
	//todo: make AudioPlaybackManager keep track of active sounds + implement global playback control
	private static _externalSoundInterface: any=null;

	private static _channelGroupVolumes: number[]=[1];
	private static _channelGroupPanning: number[]=[0.5];

	public static setVolume(value: number, channelGroup: number = -1): void {
		if (channelGroup < 0) {
			const len: number = AudioManager._channelGroupVolumes.length;
			for (let j: number = 0; j < len; j++) {
				AudioManager._channelGroupVolumes[j] = value;
			}
		} else {
			AudioManager._channelGroupVolumes[channelGroup] = value;
		}
		WebAudioChannel.setChannelGroupVolume(value, channelGroup);
		StreamingAudioChannel.setChannelGroupVolume(value, channelGroup);
		EventAudioChannel.setChannelGroupVolume(value, channelGroup);

	}

	public static getVolume(channelGroup: number = 0): number {
		return AudioManager._channelGroupVolumes[channelGroup];
	}

	public static setExternalSoundInterface(new_obj: any): number {
		if (new_obj.startSound == null) {
			console.log('Could not set the externalSoundInterface, ' +
						'because it does not provide a \'startSound\' function');
			return;
		}
		if (new_obj.stopSound == null) {
			console.log('Could not set the externalSoundInterface, ' +
						'because it does not provide a \'stopSound\' function');
			return;
		}
		AudioManager._externalSoundInterface = new_obj;
	}

	public static getExternalSoundInterface(): any {
		return AudioManager._externalSoundInterface;
	}

	public static stopAllSounds() {
		WebAudioChannel.stopAllSounds();
		StreamingAudioChannel.stopAllSounds();
		EventAudioChannel.stopAllSounds();
		//AudioChannel.stopAllSounds();
	}

	public static getChannel(byteLength: number, channelGroup: number = 0): IAudioChannel {
		//choose best audio channel by bytelength
		//todo: StreamingAudioChannel doesnt seem to be working. no error, but also no sound is playing
		let channelClass: IAudioChannelClass = (byteLength > 50000000) ? StreamingAudioChannel : WebAudioChannel;
		if (AudioManager.isIE) {
			channelClass = EventAudioChannel;
		}
		//var channelClass:IAudioChannelClass = WebAudioChannel;

		let i: number = 0;
		while (channelClass._channels[i] && channelClass._channels[i].isPlaying())
			i++;

		if (i == channelClass.maxChannels) {
			//pick the oldest channel to reuse, ignoring looping channels
			let channel: IAudioChannel;
			const len: number = channelClass._channels.length;
			for (let j: number = 0; j < len; j++) {
				channel = channelClass._channels[j];
				if (!channel.isLooping() && !channel.isDecoding()) {
					channel.groupID = channelGroup;
					channel.groupVolume = AudioManager._channelGroupVolumes[channelGroup];
					channel.groupPan = AudioManager._channelGroupPanning[channelGroup];
					channelClass._channels.push(channelClass._channels.splice(j, 1)[0]);
					channel.stop();
					return channel;
				}
			}

			//do not return channel until one is freed up
			return null;
		}

		return  (channelClass._channels[i] = new channelClass(channelGroup,
			AudioManager._channelGroupVolumes[channelGroup],
			AudioManager._channelGroupPanning[channelGroup]));
	}

}