/*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 "LobbyCharacter.hpp"
#include "Engines/Resources/TextureManager.hpp"
#include "Engines/Sound/SoundEngine.hpp"

#include "Tools/ScaledPixel.hpp"

LobbyCharacter::LobbyCharacter(const std::vector<std::string> &characterNames,
                               const std::string &initialCharacter,
                               TextureManager &textureManager,
                               SoundEngine &soundEngine,
                               float viewWidth) :
Tab(ScaledPixel{viewWidth}(260.f),
    ScaledPixel{viewWidth}(320.f),
    Color(0, 0, 0, 0)),
m_characterIx(0)
{
    const ScaledPixel sp(viewWidth);
    const float characterScale = sp.lower(.64f, 1.f);

    std::size_t i = 0;
    m_characters.reserve(characterNames.size());
    for (const std::string &name : characterNames)
    {
        m_characters.emplace_back();
        m_characters.back().name = name;
        m_characters.back().preview.load(name, textureManager);
        m_characters.back().preview.setScale(sp(.64f, false));

        if (name == initialCharacter)
            m_characterIx = i;

        i++;
    }

    const float arrowPadding = sp(10.f),
                arrowWidth = sp(100.f / 3.f),
                arrowHeight = sp(128.f / 3.f);

    const SkinSound soundSkin(soundEngine, "audio/ui/menuFocus.ogg",
                              "audio/ui/menuClick.ogg");

    const SkinBox leftArrowSkin(arrowWidth, arrowHeight,
        Sprite(textureManager.getTexture("gfx/ui/ui.png",
                                         Texture::MinMagFilter::Linear),
               Box(110.f / 512.f, 265.f / 512.f, 100.f / 512.f, 128.f / 512.f)),
        Sprite(textureManager.getTexture("gfx/ui/ui.png",
                                         Texture::MinMagFilter::Nearest),
               Box(0.f / 512.f, 265.f / 512.f, 100.f / 512.f, 128.f / 512.f)));

    const SkinBox rightArrowSkin(arrowWidth, arrowHeight,
        Sprite(textureManager.getTexture("gfx/ui/ui.png"),
               Box(110.f / 512.f, 133.f / 512.f, 100.f / 512.f, 128.f / 512.f)),
        Sprite(textureManager.getTexture("gfx/ui/ui.png"),
               Box(0.f / 512.f, 133.f / 512.f, 100.f / 512.f, 128.f / 512.f)));

    m_leftArrow.setSkin(leftArrowSkin);
    m_leftArrow.setSoundSkin(soundSkin);

    m_rightArrow.setSkin(rightArrowSkin);
    m_rightArrow.setSoundSkin(soundSkin);

    //Position arrows and characters
    m_leftArrow.setPosition(arrowPadding, (getHeight() - arrowHeight) / 2.f);
    m_rightArrow.setPosition(getWidth() - arrowWidth - arrowPadding,
                            (getHeight() - arrowHeight) / 2.f);

    for (CharacterItem &character : m_characters)
    {

        character.preview.setPosition(
            (getWidth() - character.preview.getWidth() * characterScale) / 2.f,
            (getHeight() + character.preview.getHeight() * characterScale) / 2.f);
        updatePreviewOrigin(character.preview);
    }
}

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

    m_background.draw();

    if (m_characterIx < m_characters.size())
        m_characters[m_characterIx].preview.draw();

    m_leftArrow.draw();
    m_rightArrow.draw();

    Drawable::popMatrix();
}

void LobbyCharacter::update(float frameTime)
{
    if (m_characterIx < m_characters.size())
    {
        m_characters[m_characterIx].preview.update(frameTime);
        updatePreviewOrigin(m_characters[m_characterIx].preview);
    }
}

bool LobbyCharacter::mouseRelease(const Vector &mouseCoords)
{
    Vector localMouse = Widget::localCoords(mouseCoords);

    if (m_rightArrow.mouseRelease(localMouse) && m_characters.size() > 0)
    {
        m_characterIx = (m_characterIx + 1) % m_characters.size();
        return true;
    }
    else if (m_leftArrow.mouseRelease(localMouse) && m_characters.size() > 0)
    {
        m_characterIx = m_characterIx > 0 ? m_characterIx - 1
                                          : m_characters.size() - 1;
        return true;
    }

    return false;
}

bool LobbyCharacter::mouseClick(const Vector &mouseCoords)
{
    Vector localMouse = Widget::localCoords(mouseCoords);

    m_leftArrow.mouseClick(localMouse);
    m_rightArrow.mouseClick(localMouse);

    return Widget::contains(localMouse);
}

bool LobbyCharacter::mouseMove(const Vector &mouseCoords)
{
    Vector localMouse = Widget::localCoords(mouseCoords);

    m_leftArrow.mouseMove(localMouse);
    m_rightArrow.mouseMove(localMouse);

    return Widget::contains(localMouse);
}

std::string LobbyCharacter::getCharacter() const
{
    if (m_characterIx < m_characters.size())
        return m_characters[m_characterIx].name;

    return "Hikou";
}

void LobbyCharacter::updatePreviewOrigin(CharacterPreview &preview)
{
    const Box bodyBox = preview.getBodyBox();
    preview.setYOrigin((bodyBox.top + bodyBox.height) * preview.getYScale());
}
