/*Copyright (C) 2010-2023 Duncan Deveaux

This file is part of Hikou no mizu.

Hikou no mizu is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Hikou no mizu is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Hikou no mizu.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "SoundEffectsList.hpp"

#include "Tools/BuildValues.hpp" ///< Generated at build time
#include <pugixml.hpp>
#include <cstddef>

SoundEffectsList::SoundEffectsList() :
m_generator(std::random_device{}())
{

}

bool SoundEffectsList::load(const std::string &xmlRelPath)
{
    m_soundEffects.clear();

    //pugixml initialization
    //Locate absolute path to xml data
    std::string xmlPath = BuildValues::data(xmlRelPath);

    pugi::xml_document xmlFile;
    if (!xmlFile.load_file(xmlPath.c_str()))
        return false;

    pugi::xml_node soundEffectNode;
    for (soundEffectNode = xmlFile.child("main").child("soundeffect");
         soundEffectNode;
         soundEffectNode = soundEffectNode.next_sibling("soundeffect"))
    {
        //Get sound effect attributes
        const std::string effectName(soundEffectNode.attribute("name").value());
        const std::string characterName(soundEffectNode.attribute("character")
            .as_string(CHARACTER_AGNOSTIC));

        float pitchVariation(soundEffectNode.attribute("pitchVariation")
            .as_float(.15f));
        if (pitchVariation > .8f) pitchVariation = .8f;
        else if (pitchVariation < 0.f) pitchVariation = 0.f;

        //Browse associated sound paths
        std::vector<SoundData> sounds;
        pugi::xml_node soundNode;
        for (soundNode = soundEffectNode.child("sound");
             soundNode;
             soundNode = soundNode.next_sibling("sound"))
        {
            sounds.emplace_back(
                std::string("audio/sfx/") + soundNode.attribute("path").value(),
                pitchVariation);
        }

        if (!sounds.empty())
            m_soundEffects[effectName].emplace(characterName,
                                               std::move(sounds));
    }

    return true;
}

bool SoundEffectsList::getSoundData(const std::string &effect,
                                    const std::string &characterName,
                                    SoundData &target)
{
    if (m_soundEffects.count(effect) > 0)
    {
        if (m_soundEffects[effect].count(characterName) > 0)
        {
            //A character-specific set of sound paths is available
            chooseSoundAmong(m_soundEffects[effect][characterName],
                             target);
            return true;
        }
        else if (m_soundEffects[effect].count(CHARACTER_AGNOSTIC) > 0)
        {
            //A character-agnostic set of sound paths is available
            chooseSoundAmong(m_soundEffects[effect][CHARACTER_AGNOSTIC],
                             target);
            return true;
        }
    }

    return false;
}

bool SoundEffectsList::chooseSoundAmong(const std::vector<SoundData> &sounds,
                                        SoundData &target)
{
    if (!sounds.empty())
    {
        std::uniform_int_distribution<std::size_t> distribution(0,
                                                    sounds.size()-1);
        target = sounds[ distribution(m_generator) ];
        return true;
    }

    return false;
}
