#include utility.js
#include sound/sndlibrary.js
#include sound/sndpacks.js

const MamiSoundManager = function(context) {
    const supported = [], fallback = [],
        formats = {
            opus: 'audio/ogg;codecs=opus',
            ogg: 'audio/ogg;codecs=vorbis',
            mp3: 'audio/mpeg;codecs=mp3',
            caf: 'audio/x-caf;codecs=opus',
            wav: 'audio/wav',
        };

    const loaded = new Map;

    (function() {
        const elem = $e('audio');
        for(const name in formats) {
            const format = formats[name], support = elem.canPlayType(format);
            if(support === 'probably')
                supported.push(name);
            else if(support === 'maybe')
                fallback.push(name);
        }
    })();

    const pub = {};

    const findSupportedUrl = function(urls) {
        if(typeof urls === 'string')
            return urls;

        // lol we're going backwards again
        if(Array.isArray(urls)) {
            const tmp = urls;
            urls = {};

            for(const item of tmp) {
                let type = null;
                
                if(item.type)
                    type = item.type;
                else {
                    switch(item.format) {
                        case 'audio/mpeg':
                        case 'audio/mp3':
                            type = 'mp3';
                            break;
                        case 'audio/ogg': // could also be opus, oops!
                            type = 'ogg';
                            break;
                        case 'audio/opus': // isn't real lol
                            type = 'opus';
                            break;
                        case 'audio/x-caf':
                            type = 'caf';
                            break;
                    }
                }

                if(type === null || type === undefined)
                    continue;

                urls[type] = item.url;
            }
        }

        // check "probably" formats
        let url = null;
        for(const type of supported) {
            if(type in urls) {
                url = urls[type];
                break;
            }
        }

        // check "maybe" formats
        if(url === null)
            for(const type of fallback) {
                if(type in urls) {
                    url = urls[type];
                    break;
                }
            }

        return url;
    };

    pub.findSupportedUrl = findSupportedUrl;

    pub.loadAnonymous = function(urls, callback) {
        const url = findSupportedUrl(urls);
        if(url === null) {
            callback.call(pub, false, 'No supported audio format could be determined.');
            return;
        }

        context.createBuffer(url, function(success, buffer) {
            callback.call(pub, success, buffer);
        });
    };

    pub.load = function(name, urls, callback) {
        const hasCallback = typeof callback === 'function';

        if(loaded.has(name)) {
            if(hasCallback)
                callback.call(pub, true, loaded.get(name));
            return;
        }

        const url = findSupportedUrl(urls);
        if(url === null) {
            const msg = 'No supported audio format could be determined.';
            if(hasCallback)
                callback.call(pub, false, msg);
            else
                throw msg;
            return;
        }

        context.createBuffer(url, function(success, buffer) {
            if(!success) {
                if(hasCallback)
                    callback.call(pub, success, buffer);
                else // not actually sure if this will do anything but maybe it'll show in the console
                    throw buffer;
                return;
            }

            loaded.set(name, buffer);

            if(hasCallback)
                callback.call(pub, success, buffer);
        });
    };

    pub.unload = function(name) {
        loaded.delete(name);
    };
    pub.reset = function() {
        loaded.clear();
    };

    pub.play = function(name) {
        if(loaded.has(name))
            loaded.get(name).createSource().play();
    };

    pub.isLoaded = function(name) {
        return loaded.has(name);
    };

    pub.get = function(name) {
        if(!loaded.has(name))
            return null;
        return loaded.get(name).createSource();
    };

    return pub;
};
