import { EventDispatcher, Event } from "../../2d/events";
import { SoundChannel } from "../SoundChannel";
import { WebAudioDecode } from "./WebAudioSound";
import { $popSoundChannel } from "../Sound";

interface AudioBufferSourceNodeEgret {
    buffer: any;
    context: any;
    onended: Function;
    stop(when?: number): void;
    noteOff(when?: number): void;
    addEventListener(type: string, listener: Function, useCapture?: boolean);
    removeEventListener(type: string, listener: Function, useCapture?: boolean);
    disconnect();
}


export class WebAudioSoundChannel extends EventDispatcher implements SoundChannel {


    /**
     * @private
     */
    $url: string;
    /**
     * @private
     */
    $loops: number;
    /**
     * @private
     */
    $startTime: number = 0;

    /**
     * @private
     * audio音频对象
     * @member {any} egret.Sound#audio
     */
    $audioBuffer: AudioBuffer;
    /**
     * @private
     */
    private gain;
    /**
     * @private
     */
    private bufferSource: AudioBufferSourceNodeEgret = null;

    /**
     * @private
     */
    private context = WebAudioDecode.ctx;

    //声音是否已经播放完成
    private isStopped: boolean = false;

    /**
     * @private
     */
    constructor() {
        super();

        if (this.context["createGain"]) {
            this.gain = this.context["createGain"]();
        }
        else {
            this.gain = this.context["createGainNode"]();
        }
    }

    /**
     * @private
     */
    private _currentTime: number = 0;
    /**
     * @private
     */
    private _volume: number = 1;

    $play(): void {
        if (this.isStopped) {
            console.error("")
            return;
        }
alert(111231)
        if (this.bufferSource) {
            this.bufferSource.onended = null;
            this.bufferSource = null;
        }
        let context = this.context;
        let gain = this.gain;
        let bufferSource = context.createBufferSource();
        this.bufferSource = bufferSource;
        bufferSource.buffer = this.$audioBuffer;
        bufferSource.connect(gain);
        gain.connect(context.destination);
        bufferSource.onended = this.onPlayEnd;

        this._startTime = Date.now();
        this.gain.gain.value = this._volume;
        bufferSource.start(0, this.$startTime);
        this._currentTime = 0;
    }

    public stop(): void {
        if (this.bufferSource) {
            let sourceNode = this.bufferSource;
            if (sourceNode.stop) {
                sourceNode.stop(0);
            }
            else {
                sourceNode.noteOff(0);
            }
            sourceNode.onended = null;
            sourceNode.disconnect();
            this.bufferSource = null;

            this.$audioBuffer = null;
        }

        if (!this.isStopped) {
            $popSoundChannel(this);
        }

        this.isStopped = true;
    }

    /**
     * @private
     */
    private onPlayEnd = () => {
        if (this.$loops == 1) {
            this.stop();
            this.dispatchEvent(Event.COMPLETE);
            return;
        }

        if (this.$loops > 0) {
            this.$loops--;
        }

        /////////////
        this.$play();
    };

    /**
     * @private
     * @inheritDoc
     */
    public get volume(): number {
        return this._volume;
    }

    /**
     * @inheritDoc
     */
    public set volume(value: number) {
        if (this.isStopped) {
            console.error("")
            return;
        }

        this._volume = value;
        this.gain.gain.value = value;
    }

    /**
     * @private
     */
    private _startTime: number = 0;
    /**
     * @private
     * @inheritDoc
     */
    public get position(): number {
        if (this.bufferSource) {
            return (Date.now() - this._startTime) / 1000 + this.$startTime;
        }
        return 0;
    }
}