import { EventDispatcher, Event } from "../2d/events";
import { GlobalLoader } from "../2d/loader";
import { SoundChannel } from "./SoundChannel";

/**
 * 淘宝小程序的音频
 */
export interface InnerAudioContext {
    src: string	//音频的数据链接，用于直接播放。 支持音频格式：aac，mp3 src支持的协议如下： HTTP和HTTPS: http://taobao.com/videoSource/test.mp3 apFilePath
    startTime: number	//音频开始播放时间，单位秒
    autoplay: boolean	//是否自动开始播放，默认 false
    loop: boolean	//是否循环播放，默认 false
    obeyMuteSwitch: boolean	//是否遵循系统静音开关，当此参数为 false 时，即使用户打开了静音开关，也能继续发出声音，默认值 true (仅 iOS支持)
    duration: number	//当前音频的长度（单位：s），只有在当前有合法的 src 时返回
    currentTime: number	//当前音频的播放位置（单位：s），只有在当前有合法的 src 时返回，时间不取整
    paused: boolean	//当前是是否暂停或停止状态，true 表示暂停或停止，false 表示正在播放
    buffered: number	//音频缓冲的时间点，仅保证当前播放时间点到此时间点内容已缓冲。
    volume: number	//音量。范围 0~1。
    isRecordAudioPlayState: boolean	//暂不支持
    play: () => void	//播放
    pause: () => void	//暂停
    stop: void	//停止
    seek: (postion:number) => void	//跳转到指定位置，单位 s
    destroy: void	//销毁当前实例
    onCanplay: (fun: () => void) => void	//可以播放事件
    onPlay: (fun: () => void) => void	//音频开始播放事件
    onPause: (fun: () => void) => void	//音频暂停播放事件
    onStop: (fun: () => void) => void	//音频停止播放事件
    onEnded: (fun: () => void) => void	//音频结束播放事件
    onTimeUpdate: (fun: () => void) => void	//音频播放进度更新事件
    onError: (fun: () => void) => void	//音频播放错误事件
    onWaiting: (fun: () => void) => void	//音频缓冲事件
    onSeeking: (fun: () => void) => void	//音频跳转事件
    onSeeked: (fun: () => void) => void	//音频跳转结束事件
}

let usingChannel: Array<SoundChannel> = [];

/**
 * @private
 * @param channel
 */
export function $pushSoundChannel(channel: SoundChannel): void {
    if (usingChannel.indexOf(channel) < 0) {
        usingChannel.push(channel);
    }
}

/**
 * @private
 * @param channel
 */
export function $popSoundChannel(channel: SoundChannel): boolean {
    let index: number = usingChannel.indexOf(channel);
    if (index >= 0) {
        usingChannel.splice(index, 1);
        return true;
    }
    return false;
}

export class Sound extends EventDispatcher {
    /**
     * 记录的路径
     */
    private url: string;
    /**
     * 有url了，貌似就没必要了
     */
    private originAudio: InnerAudioContext;
    /**
     * @private
     */
    private loaded: boolean = false;

    constructor() {
        super();
    }

    public get length(): number {
        if (this.originAudio) {
            return this.originAudio.duration;
        }

        throw new Error("sound not loaded!");

        //return 0;
    }


    public load(url: string): void {
        this.url = url;
        GlobalLoader.loadAudio((s, audio) => {
            this.originAudio = audio;
            if (s) {
                Sound.$recycle(this.url, audio);
                this.loaded = true;
                this.dispatchEvent(Event.COMPLETE);
            } else {
                this.dispatchEvent(Event.ERROR);
            }
        }, url)
        if (Sound.clearAudios[this.url]) {
            delete Sound.clearAudios[this.url];
        }
    }

    /**
     * @inheritDoc
     */
    public play(startTime?: number, loops?: number): SoundChannel {
        startTime = +startTime || 0;
        loops = +loops || 0;

        let audio: InnerAudioContext = Sound.$pop(this.url);
        if (audio == null) {//没有就新建
            //@ts-ignore
            audio = <InnerAudioContext>my.createInnerAudioContext();
            audio.src = this.url;
        }
        else {
            //audio.load();
        }
        audio.autoplay = true;

        let channel = new SoundChannel(audio);
        channel.$url = this.url;
        channel.$loops = loops;
        channel.$startTime = startTime;
        channel.$play();

        //为了能处理所有加入的sound用
        $pushSoundChannel(channel);

        return channel;
    }

    /**
     * @inheritDoc
     */
    public close() {
        if (this.loaded == false && this.originAudio) this.originAudio.src = "";
        if (this.originAudio) this.originAudio = null;
        Sound.$clear(this.url);
    }

    /**
     * @private
     */
    private static audios: Object = {};
    private static clearAudios: Object = {};

    static $clear(url: string): void {
        Sound.clearAudios[url] = true;
        let array: InnerAudioContext[] = Sound.audios[url];
        if (array) {
            array.length = 0;
        }
    }

    static $pop(url: string): InnerAudioContext {
        let array: InnerAudioContext[] = Sound.audios[url];
        if (array && array.length > 0) {
            return array.pop();
        }
        return null;
    }

    static $recycle(url: string, audio: InnerAudioContext): void {
        if (Sound.clearAudios[url]) {
            return;
        }
        let array: InnerAudioContext[] = Sound.audios[url];
        if (Sound.audios[url] == null) {
            array = Sound.audios[url] = [];
        }
        array.push(audio);
    }
}