#include sound/sndlibrary.js

const MamiSoundPack = function(name, isReadOnly, title, events) {
    name = (name || '').toString();
    isReadOnly = !!isReadOnly;
    title = (title || '').toString();
    events = events || new Map;

    const hasEventSound = eventName => events.has(eventName);

    return {
        getName: () => name,
        isReadOnly: () => isReadOnly,
        getTitle: () => title,
        setTitle: newTitle => {
            if(isReadOnly)
                throw 'Cannot edit read only sound pack.';
            title = (newTitle || '').toString();
        },
        getEventNames: () => Array.from(events.keys()),
        hasEventSound: hasEventSound,
        getEventSound: eventNames => {
            let event;

            if(Array.isArray(eventNames)) {
                for(const name of eventNames)
                    if(hasEventSound(name)) {
                        event = name;
                        break;
                    }
            } else if(hasEventSound(eventNames)) {
                event = eventNames;
            }

            if(event === undefined)
                return;

            return events.get(event);
        },
        setEventSound: (eventName, soundName) => {
            events.set(
                (eventName || '').toString(),
                (soundName || '').toString()
            );
        },
        removeEventSound: eventName => {
            events.delete(eventName);
        },
        clearEventSounds: () => {
            events.clear();
        },
        clone: (newName, readOnly) => {
            return new MamiSoundPack(newName, readOnly, 'Clone of ' + title, new Map(events));
        },
    };
};

const MamiSoundPacks = function() {
    const packs = new Map;

    const registerPack = (packInfo, readOnly) => {
        if(Array.isArray(packInfo)) {
            for(const info of packInfo)
                registerPack(info, readOnly);
            return;
        }

        if(typeof packInfo !== 'object')
            throw 'packInfo must be an object';
        if(typeof packInfo.name !== 'string')
            throw 'packInfo must contain a name field';
        if(typeof packInfo.events !== 'object')
            throw 'packInfo must contain a events field';
        if(packs.has(packInfo.name))
            throw 'a pack with that name has already been registered';

        const events = new Map;
        for(const eventName in packInfo.events) {
            if(typeof packInfo.events[eventName] !== 'string')
                continue;
            events.set(eventName, packInfo.events[eventName]);
        }

        if(events.size < 1)
            throw 'packInfo does not contain any valid events';

        packInfo = new MamiSoundPack(packInfo.name, readOnly, packInfo.title, events);
        packs.set(packInfo.getName(), packInfo);

        return packInfo;
    };

    const getPack = name => {
        if(!packs.has(name))
            throw 'No pack with this name has been registered.';
        return packs.get(name);
    };

    return {
        register: registerPack,
        unregister: name => {
            packs.delete(name);
        },
        clear: () => {
            packs.clear();
        },
        info: name => getPack(name),
        names: () => Array.from(packs.keys()),
        has: name => packs.has(name),
        get: getPack,
    };
};
