#ifndef SOUND_HPP_
#define SOUND_HPP_

#include <string>
#include <fstream>
#include <unordered_map>

#include <Utilities/Extern.hpp>

/**
 * @brief Represents a loaded sound.
 */
class Sound
{
private:
    static std::unordered_map<std::string, Sound*> soundTable;

    ALuint buffer;
    uint16_t channels;

    Sound();

    static bool loadHeader(
        std::ifstream& ifs,
        uint16_t& channels,
        int32_t& sampleRate,
        uint16_t& bitsPerSample,
        ALsizei& size
    );

public:
    /**
     * @brief The name of the sound.
     */
    std::string name;

    /**
     * @brief Represents the lack of a sound.
     */
    static Sound NONE;

    /**
     * @brief Construct the sound.
     * 
     * This does not actually load the sound, only sets its name. To add a new sound
     * to the game, modify `SoundList.hpp`, and the preloader will automatically call
     * `load()` to perform the loading.
     * 
     * @param name 
     */
    Sound(std::string name);

    /**
     * @brief Perform the loading.
     */
    void load();

    /**
     * @brief Returns true if this sound is `Sound::NONE`.
     */
    bool isNone();

    /**
     * @brief Play this sound once, from start to finish.
     * 
     * @param pos The position in the world to play from.
     * @param vel The velocity of the source.
     */
    void play(glm::vec3 pos, glm::vec3 vel = glm::vec3(0.0f), float pitch = 1.0f, float gain = 1.0f);

    /**
     * @brief Play this sound, non-positioned, from start to finish.
     */
    void play();

    /**
     * @brief Get the sound given a name. Returns `Sound::NONE` if name is not recognised.
     */
    static Sound& byName(std::string name);

    #define DECL_SOUND(name) static Sound name
    #include <Sound/SoundList.hpp>

    friend class AudioSource;
};

#endif