#include srle.js
#include utility.js
#include audio/buffer.js
#include audio/source.js

const MamiDetectAutoPlaySource = '/+NIxA!!FhpbmcA#PA$wA@fgAV$#q$#/$#A#OUxBTUUzLjEwMAIeA!)UCCQC8CIA@gA@H49wpKWgA!%&/+MYxA$NIA$ExBTUUzLjEwMFV^%/+MYxDsA@NIA$FV&&/+MYxHYA@NIA$FV&&';

const MamiDetectAutoPlay = async () => {
    try {
        const audio = $e('audio', { src: 'data:audio/mpeg;base64,' + MamiSRLE.decode(MamiDetectAutoPlaySource) });

        try {
            await audio.play();
        } catch(ex) {
            if('name' in ex && ex.name !== 'NotAllowedError' && ex.name !== 'AbortError') {
                console.error(ex);
                throw ex;
            }

            return false;
        }
    } catch(ex) {}

    return true;
};

const MamiAudioContext = function() {
    const pub = {};

    let volume = null,
        isMuted = false;

    const ctxArgs = { latencyHint: 'playback' };
    let ctx = null,
        mainGain = null;
    const init = function() {
        const audObj = window.AudioContext || window.webkitAudioContext;
        try {
            ctx = new audObj(ctxArgs);
        } catch(ex) {
            ctx = new audObj;
        }
        mainGain = ctx.createGain();

        if(volume === null) {
            volume = mainGain.gain.defaultValue;
            isMuted = false;
        } else
            mainGain.gain.value = isMuted ? 0 : volume;

        mainGain.connect(ctx.destination);
    };

    init();
    pub.getContext = function() { return ctx; };
    pub.resetContext = init;

    pub.useGain = function(callback) {
        callback.call(pub, mainGain.gain);
    };

    pub.getVolume = function() {
        return volume;
    };
    pub.setVolume = function(vol) {
        volume = vol;
        if(!isMuted)
            mainGain.gain.value = volume;
    };
    pub.isMuted = function() {
        return isMuted;
    };
    pub.setMuted = function(mute) {
        mainGain.gain.value = (isMuted = mute) ? 0 : volume;
    };

    pub.createBuffer = function(url, callback) {
        $x.get(url, { type: 'arraybuffer' })
            .then(resp => {
                try {
                    ctx.decodeAudioData(
                        resp.body(),
                        buffer => callback.call(pub, true, new MamiAudioBuffer(pub, buffer)),
                        error => callback.call(pub, false, error)
                    );
                } catch(ex) {
                    callback.call(pub, false, ex);
                }
            })
            .catch(err => callback.call(pub, false, err));
    };

    const createSource = function(buffer) {
        const gain = ctx.createGain();
        gain.connect(mainGain);

        const source = ctx.createBufferSource();
        source.buffer = buffer;
        source.connect(gain);

        return new MamiAudioSource(source, gain);
    };
    pub.createSource = createSource;

    return pub;
};
