/*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 "CharacterSelectionPanel.hpp"

#include "Tools/ScaledPixel.hpp"

namespace
{
    constexpr float CHARACTER_BOX_WIDTH = 175.f;
    constexpr float CHARACTER_BOX_HEIGHT = 305.f;
    constexpr float CHARACTER_BOX_PADDING = 10.f;
    constexpr float CHARACTER_BOX_MARGIN = 20.f;
}

CharacterSelectionPanel::CharacterSelectionPanel() :
Tab(100.f, 100.f, Color()), m_viewWidth(0.f) {}

CharacterSelectionPanel::CharacterSelectionPanel(Font &textFont,
                                                 std::size_t charactersNo,
                                                 float viewWidth) :
Tab(static_cast<float>(charactersNo) *
        (ScaledPixel{viewWidth}(CHARACTER_BOX_WIDTH) +
         ScaledPixel{viewWidth}(CHARACTER_BOX_MARGIN)) -
        ScaledPixel{viewWidth}(CHARACTER_BOX_MARGIN),
    ScaledPixel{viewWidth}(CHARACTER_BOX_HEIGHT),
    Color(0, 0, 0, 0)),
m_knownCharacters(Character::fetchNames()),
m_viewWidth(viewWidth)
{
    m_characters.reserve(charactersNo);
    for (std::size_t i = 0; i < charactersNo; i++)
    {
        m_characters.emplace_back();

        m_characters.back().name.setFont(textFont);
        m_characters.back().name.setText(
            m_characters.back().character.getFullName());
        m_characters.back().name.setColor(Color(255, 255, 255),
                                          Color(0, 0, 0));
        m_characters.back().background =
            Polygon::rectangle(ScaledPixel{viewWidth}(CHARACTER_BOX_WIDTH),
                               ScaledPixel{viewWidth}(CHARACTER_BOX_HEIGHT),
                               Color(22, 65, 108, 75));
        m_characters.back().background.setBorderSize(0.f);

        updatePosition(i);
    }
}

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

    m_background.draw();
    for (CharacterData &character : m_characters)
    {
        character.background.draw();
        character.preview.draw();
        character.name.draw();
    }

    Drawable::popMatrix();
}

void CharacterSelectionPanel::update(float frameTime)
{
    for (CharacterData &character : m_characters)
    {
        character.preview.update(frameTime);
        updatePreviewOrigin(character.preview);
    }
}

void CharacterSelectionPanel::setCharacter(std::size_t ix,
                                           const Character &character,
                                           TextureManager &textureManager)
{
    if (ix >= m_characters.size() || m_characters[ix].character == character)
        return;

    m_characters[ix].character = character;
    m_characters[ix].name.setText(character.getFullName());

    if (Character::validateName(m_knownCharacters, character.name))
    {
        m_characters[ix].preview = CharacterPreview();
        m_characters[ix].preview.load(character.name, textureManager);
        m_characters[ix].preview.setScale(
            ScaledPixel{m_viewWidth}(.53f, false));
    }

    updatePosition(ix);
}

void CharacterSelectionPanel::resetCharacter(std::size_t ix)
{
    if (ix >= m_characters.size())
        return;

    const Character defaultCharacter = Character();

    m_characters[ix].character = defaultCharacter;
    m_characters[ix].name.setText(defaultCharacter.getFullName());
    m_characters[ix].preview = CharacterPreview();

    updatePosition(ix);
}

Character CharacterSelectionPanel::getCharacter(std::size_t ix) const
{
    return ix < m_characters.size() ? m_characters[ix].character : Character();
}

bool CharacterSelectionPanel::readyCharacter(std::size_t ix)
{
    if (ix < m_characters.size() &&
        Character::validateName(m_knownCharacters,
                                m_characters[ix].character.name))
    {
        m_characters[ix].preview.select();
        updatePosition(ix);
        return true;
    }

    return false;
}

void CharacterSelectionPanel::unreadyCharacter(std::size_t ix)
{
    if (ix >= m_characters.size())
        return;

    m_characters[ix].preview.unselect();
    updatePosition(ix);
}

std::size_t CharacterSelectionPanel::getSize() const
{
    return m_characters.size();
}

bool CharacterSelectionPanel::mouseRelease(const Vector &mouseCoords)
{
    return Widget::contains( Widget::localCoords(mouseCoords) );
}

bool CharacterSelectionPanel::mouseClick(const Vector &mouseCoords)
{
    return Widget::contains( Widget::localCoords(mouseCoords) );
}

bool CharacterSelectionPanel::mouseMove(const Vector &mouseCoords)
{
    return Widget::contains( Widget::localCoords(mouseCoords) );
}

void CharacterSelectionPanel::updatePosition(std::size_t ix)
{
    if (ix >= m_characters.size())
        return;

    const ScaledPixel sp(m_viewWidth);

    const float baseX = static_cast<float>(ix) *
        (sp(CHARACTER_BOX_WIDTH) + sp(CHARACTER_BOX_MARGIN));

    m_characters[ix].background.setXPosition(baseX);

    ShadowText &name = m_characters[ix].name;
    name.setPosition(
        baseX + (sp(CHARACTER_BOX_WIDTH) - name.getWidth()) / 2.f,
        sp(CHARACTER_BOX_HEIGHT) - name.getHeight() -
        sp(CHARACTER_BOX_PADDING));

    CharacterPreview &preview = m_characters[ix].preview;

    preview.setPosition(baseX + sp(CHARACTER_BOX_PADDING) * 2.f,
                        name.getYPosition() - sp(CHARACTER_BOX_PADDING));

    updatePreviewOrigin(preview);
}

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