
import { HtmlSoundChannel } from "./HtmlSoundChannel";
import { EventDispatcher, Event } from "../../2d/events";
import { Sound, $pushSoundChannel } from "../Sound";
import { SoundChannel } from "../SoundChannel";


/**
 * 白鹭的，只管html的，不管其他音频数据
 * 到时考虑用AudioContext,优先，否则就先用howler  "howler":"^2.1.3",
 */
export class HtmlSound extends EventDispatcher implements Sound {
    /**
     * @private
     */
    private url: string;
    /**
     * @private
     */
    private originAudio: HTMLAudioElement;
    /**
     * @private
     */
    private loaded: boolean = false;
    /**
     * 默认用loader加载好的，而不用load方法加载
     * @param audio 
     */
    constructor(/*audio?: HTMLAudioElement*/) {
        super();
        // if (audio) {
        //     this.originAudio = audio;
        //     this.url = audio.src;
        //     this.loaded = true;
        // }
    }

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

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

        //return 0;
    }


    public load(url: string): void {
        let self = this;

        this.url = url;

        let audio = new Audio(url);
        audio.addEventListener("canplaythrough", onAudioLoaded);
        audio.addEventListener("error", onAudioError);

        let ua: string = navigator.userAgent.toLowerCase();
        if (ua.indexOf("firefox") >= 0) {//火狐兼容
            audio.autoplay = !0;
            audio.muted = true;
        }
        if (ua.indexOf("edge") >= 0) {//Edge兼容
            document.body.appendChild(audio);
        }
        audio.load();
        this.originAudio = audio;
        if (HtmlSound.clearAudios[this.url]) {
            delete HtmlSound.clearAudios[this.url];
        }

        function onAudioLoaded(): void {
            HtmlSound.$recycle(this.url, audio);
            removeListeners();
            if (ua.indexOf("firefox") >= 0) {//火狐兼容
                audio.pause();
                audio.muted = false;
            }

            self.loaded = true;
            self.dispatchEvent(Event.COMPLETE);
        }

        function onAudioError(): void {
            removeListeners();
            self.dispatchEvent(Event.ERROR);
        }

        function removeListeners(): void {
            audio.removeEventListener("canplaythrough", onAudioLoaded);
            audio.removeEventListener("error", onAudioError);
            if (ua.indexOf("edge") >= 0) {//Edge兼容
                document.body.removeChild(audio);
            }
        }
    }

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

        let audio = HtmlSound.$pop(this.url);
        if (audio == null) {
            audio = <HTMLAudioElement>this.originAudio.cloneNode();
        }
        else {
            //audio.load();
        }
        audio.autoplay = true;

        let channel = new HtmlSoundChannel(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;
        HtmlSound.$clear(this.url);
    }

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

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

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

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