/*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 "CharacterPreview.hpp"
#include "Engines/Resources/TextureManager.hpp"
#include "Structs/Box.hpp"

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

CharacterPreview::CharacterPreview() : Drawable(), m_selected(false)
{

}

void CharacterPreview::draw()
{
    //Update matrix
    Drawable::pushMatrix();
    Drawable::updateMatrix();

    if (m_selected) m_selectedDrawer.draw();
    else m_defaultDrawer.draw();

    Drawable::popMatrix();
}

void CharacterPreview::update(float frameTime)
{
    Animation &anim = m_selected ? m_selectedAnim : m_defaultAnim;

    if (anim.atEndedState())
        anim.goToTime(0.f);

    anim.goForward(frameTime / 1000.f);
}

void CharacterPreview::load(const std::string &characterName,
                            TextureManager &manager)
{
    loadAnimations(characterName, manager);
}

void CharacterPreview::select()
{
    m_selected = true;
}

void CharacterPreview::unselect()
{
    m_selected = false;
}

float CharacterPreview::getWidth() const
{
    const Animation &anim = m_selected ? m_selectedAnim : m_defaultAnim;
    return anim.getWidth();
}

float CharacterPreview::getHeight() const
{
    const Animation &anim = m_selected ? m_selectedAnim : m_defaultAnim;
    return anim.getHeight();
}

Box CharacterPreview::getBodyBox() const
{
    const Animation &anim = m_selected ? m_selectedAnim : m_defaultAnim;

    Box bodyBox;
    anim.getBodyBox(bodyBox);

    return bodyBox;
}

void CharacterPreview::loadAnimation(const pugi::xml_node &animNode,
                                     Animation &dst) const
{
    //Main parameters
    const float duration = animNode.attribute("duration").as_float(0.f);
    dst.setDuration(duration);

    //Frames
    pugi::xml_node frameNode;
    for (frameNode = animNode.child("frame");
         frameNode;
         frameNode = frameNode.next_sibling("frame"))
    {
        const unsigned int repeat = frameNode.attribute("repeat").as_uint(1);

        const int srcX = frameNode.attribute("x").as_int(0),
                  srcY = frameNode.attribute("y").as_int(0),
                  srcWidth = frameNode.attribute("width").as_int(0),
                  srcHeight = frameNode.attribute("height").as_int(0);

        const float bodyX = frameNode.attribute("bodyX").as_float(0.f),
            bodyY = frameNode.attribute("bodyY").as_float(0.f),
            bodyWidth = frameNode.attribute("bodyWidth").as_float(0.f),
            bodyHeight = frameNode.attribute("bodyHeight").as_float(0.f);

        const Frame frame(Box(static_cast<float>(srcX),
                              static_cast<float>(srcY),
                              static_cast<float>(srcWidth),
                              static_cast<float>(srcHeight)),
                          Box(bodyX, bodyY, bodyWidth, bodyHeight));

        for (unsigned int i = 0; i < repeat; i++)
            dst.addFrame(frame);
    }
}

void CharacterPreview::loadAnimations(const std::string &player,
                                      TextureManager &manager)
{
    //Locate absolute path to xml data
    const std::string xmlPath = BuildValues::data("gfx/characters/" + player +
                                            "/data.xml");
    const std::string animationsRelPath = "gfx/characters/" + player + "/";

    //pugixml initialization
    pugi::xml_document xmlFile;
    if (!xmlFile.load_file(xmlPath.c_str()))
        return;

    pugi::xml_node baseNode = xmlFile.child("main").child("data");
    pugi::xml_node defaultNode = baseNode.child("default").child("animation"),
                   crouchedNode = baseNode.child("crouched").child("animation");

    loadAnimation(defaultNode, m_defaultAnim);
    loadAnimation(crouchedNode, m_selectedAnim);

    //Load textures and drawers
    Texture &textureDefault = manager.getTexture(animationsRelPath +
        std::string(defaultNode.attribute("path").value()) + ".png");
    Texture &textureSelected = manager.getTexture(animationsRelPath +
        std::string(crouchedNode.attribute("path").value()) + ".png");

    m_defaultDrawer.attachTo(m_defaultAnim, textureDefault);
    m_selectedDrawer.attachTo(m_selectedAnim, textureSelected);
}
