const MamiSoundInfo = function(name, isReadOnly, title, sources) {
    name = (name || '').toString();
    isReadOnly = !!isReadOnly;
    title = (title || ('Nameless Sound (' + name + ')')).toString();
    sources = sources || {};

    return {
        getName: function() {
            return name;
        },
        isReadOnly: function() {
            return isReadOnly;
        },
        getTitle: function() {
            return title;
        },
        getSources: function() {
            return sources;
        },
    };
};

const MamiSoundLibrary = function() {
    const sounds = new Map;

    const addSound = function(soundInfo) {
        if(sounds.has(soundInfo.getName()))
            throw 'a sound with that name has already been registered';
        sounds.set(soundInfo.getName(), soundInfo);
    };

    const loadSoundFormats = ['opus', 'caf', 'ogg', 'mp3', 'wav'];
    const loadSound = function(soundInfo, readOnly) {
        if(typeof soundInfo !== 'object')
            throw 'soundInfo must be an object';
        if(typeof soundInfo.name !== 'string')
            throw 'soundInfo must contain a name field';
        if(typeof soundInfo.sources !== 'object')
            throw 'soundInfo must contain a sources field';

        let sources = {},
            sCount = 0;
        for(const fmt of loadSoundFormats) {
            if(typeof soundInfo.sources[fmt] !== 'string')
                continue;
            sources[fmt] = soundInfo.sources[fmt];
            ++sCount;
        }

        if(sCount < 1)
            throw 'soundInfo does not contain any valid sources';

        addSound(new MamiSoundInfo(soundInfo.name, readOnly, soundInfo.title, sources));
    };

    return {
        addSound: addSound,
        loadSound: loadSound,
        loadSounds: function(soundInfos, readOnly) {
            for(const soundInfo of soundInfos)
                loadSound(soundInfo, readOnly);
        },
        removeSound: function(name) {
            sounds.delete(name);
        },
        clearSounds: function() {
            sounds.clear();
        },
        forEachSound: function(body) {
            if(typeof body !== 'function')
                return;
            sounds.forEach(body);
        },
        hasSound: function(name) {
            return sounds.has(name);
        },
        getSound: function(name) {
            if(!sounds.has(name))
                throw 'No sound with this name has been registered.';
            return sounds.get(name);
        }
    };
};
