const MamiAudioSource = function(source, gain, buffer) {
    const pub = {};

    let volume = 1,
        isMuted = false;

    let hasDisconnected = false;

    pub.getSource = function() { return source; };

    const play = function() {
        source.start();
    };
    pub.play = play;

    const disconnect = function() {
        if(hasDisconnected)
            return;
        hasDisconnected = true;

        gain.disconnect();
        source.disconnect();
    };

    const stop = function() {
        source.stop();
        disconnect();
    };
    pub.stop = stop;

    pub.useGain = function(callback) {
        callback.call(pub, gain.gain);
    };
    pub.usePlaybackRate = function(callback) {
        callback.call(pub, source.playbackRate);
    };
    pub.useDetune = function(callback) {
        callback.call(pub, source.detune);
    };

    pub.getRate = function(rate) {
        return source.playbackRate.value;
    };
    pub.setRate = function(rate) {
        source.playbackRate.value = Math.min(
            source.playbackRate.maxValue,
            Math.max(
                source.playbackRate.minValue,
                rate
            )
        );
    };
    pub.getDetune = function(rate) {
        return source.detune.value;
    };
    pub.setDetune = function(rate) {
        source.detune.value = Math.min(
            source.detune.maxValue,
            Math.max(
                source.detune.minValue,
                rate
            )
        );
    };

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

    pub.setLoop = function(loop) {
        if(typeof loop !== 'boolean')
            loop = true;
        source.loop = loop;
    };
    pub.setLoopStart = function(start) {
        if(typeof start !== 'number')
            start = 0;
        source.loopStart = start;
    };
    pub.setLoopEnd = function(end) {
        if(typeof end !== 'number')
            end = 0;
        source.loopEnd = end;
    };

    pub.whenEnded = function(handler) {
        source.addEventListener('ended', handler.bind(pub));
    };

    source.addEventListener('ended', function() {
        disconnect();
    });

    return pub;
};
