/*Copyright (C) 2010-2020 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 "ArenaChooser.hpp"

ArenaChooser::ArenaChooser(Font &textFont, TextureManager &manager, float width, unsigned int rows, const Color &color) :
Tab(width, (rows + 1) * (ROW_HEIGHT + ROW_SPACE) + ROW_HEIGHT, color), m_selectedButton(NULL), m_textureManager(&manager),
m_font(&textFont), m_rows(rows), m_scrollingDirection(NO_SCROLLING), m_achievedMove(0.f), m_scrollingLevel(0)
{

}

void ArenaChooser::draw()
{
    //Update matrix
    Drawable::pushMatrix();
    Drawable::updateMatrix();
    
    m_background.draw();
    
    for (unsigned int i = 0; i < m_arenaButtons.size(); i++)
    {
        TextButton &arenaButton = m_arenaButtons[i];
        
        //Only show arena buttons that should be visible
        if (isShown(arenaButton))
            arenaButton.draw();
    }
    
    m_upArrow.draw();
    m_downArrow.draw();
    
    Drawable::popMatrix();
}

void ArenaChooser::update(float frameTime)
{
    float move = frameTime * SCROLLING_SPEED;
    if (m_scrollingDirection != NO_SCROLLING)
    {
        bool ended = false;
        
        if (m_achievedMove + move > ROW_HEIGHT + ROW_SPACE)
        {
            move = ROW_HEIGHT + ROW_SPACE - m_achievedMove;
            m_achievedMove = 0.f;
            
            ended = true;
        }
        else
            m_achievedMove += move;
        
        std::vector<TextButton>::iterator it;
        for (it = m_arenaButtons.begin(); it != m_arenaButtons.end(); it++)
                it->setYPosition( it-> getYPosition() + m_scrollingDirection * move );
        
        if (ended)
        {
            if (m_scrollingDirection == SCROLLING_UP)
                m_scrollingLevel--;
            else if (m_scrollingDirection == SCROLLING_DOWN)
                m_scrollingLevel++;
            
            m_scrollingDirection = NO_SCROLLING;
        }
    }
}

void ArenaChooser::initialize(const std::vector< std::pair<std::string, std::string> > &data, ArenaPreviewCallback &callback)
{
    m_selectedButton = NULL;
    m_previewCallback = &callback;
    
    Texture &ui = (*m_textureManager->getTexture("gfx/ui/ui.png"));
    
    Sprite ui_default( ui, Box(0, 0, 240.f / 512, 60.f / 512) ),
    ui_hover( ui, Box(0, 64.f / 512, 240.f / 512, 60.f / 512) ),
    ui_selected( ui, Box(0, 128.f / 512, 1.f / 512, 1.f / 512) );
    
    Sprite arrow_default( ui, Box(10.f / 512, 128.f / 512, 1.f / 512, 1.f / 512) ),
    arrow_hover( ui, Box(0, 128.f / 512, 1.f / 512, 1.f / 512) );
    
    SkinBox arrowSkin(Tab::getWidth(), ROW_HEIGHT + 5, arrow_default, arrow_hover);
    SkinBox rowSkin(Tab::getWidth(), ROW_HEIGHT, ui_default, ui_hover, ui_selected);
    
    m_upArrow = TextButton("<", arrowSkin);
    m_upArrow.setTextFont(*m_font);
    m_upArrow.setPosition( (Tab::getWidth() - m_upArrow.getWidth()) / 2, 0 );
    
    m_downArrow = TextButton(">", arrowSkin);
    m_downArrow.setTextFont(*m_font);
    m_downArrow.setPosition( (Tab::getWidth() - m_downArrow.getWidth()) / 2,
                                Tab::getHeight() - m_downArrow.getHeight() );
    
    for (unsigned int i = 0; i < data.size(); i++)
    {
        const std::string &arenaName = data[i].first;
        
        TextButton arenaButton = TextButton(arenaName, rowSkin);
        arenaButton.setTextFont(*m_font);
        arenaButton.setPosition( (Tab::getWidth() - arenaButton.getWidth()) / 2,
                                    (i+1) * (ROW_HEIGHT + ROW_SPACE));
        
        m_arenaButtons.push_back( arenaButton );
    }
    
    //Initialize selection
    if (!m_arenaButtons.empty())
    {
        m_arenaButtons[0].select(true);
        m_selectedButton = &m_arenaButtons[0];
        
        m_previewCallback->previewChanged(0);
    }
}

bool ArenaChooser::mouseClick(const Vector &mouseCoords)
{
    Vector localMouse = Widget::localCoords(mouseCoords);
    
    if (m_upArrow.mouseClick(localMouse) && m_scrollingLevel > 0)
    {
        if (m_scrollingDirection == SCROLLING_DOWN) //Canceling the ongoing opposite-sided scroll.
        {
            m_achievedMove = ROW_HEIGHT + ROW_SPACE - m_achievedMove;
            m_scrollingLevel++;
        }
        
        m_scrollingDirection = SCROLLING_UP;
    }
    else if (m_downArrow.mouseClick(localMouse) && m_scrollingLevel < static_cast<int>(m_arenaButtons.size() - m_rows))
    {
        if (m_scrollingDirection == SCROLLING_UP)
        {
            m_achievedMove = ROW_HEIGHT + ROW_SPACE - m_achievedMove;
            m_scrollingLevel--;
        }
        
        m_scrollingDirection = SCROLLING_DOWN;
    }
    
    for (unsigned int i = 0; i < m_arenaButtons.size(); i++)
    {
        TextButton &button = m_arenaButtons[i];
        if (isClickable(button))
        {
            if (button.mouseClick(localMouse))
            {
                m_selectedButton->select(false);
                
                m_selectedButton = &button;
                button.select(true);
                
                m_previewCallback->previewChanged(i);
            }
        }
    }
    
    return Widget::contains(localMouse);
}

bool ArenaChooser::mouseMove(const Vector &mouseCoords)
{
    Vector localMouse = Widget::localCoords(mouseCoords);
    
    m_upArrow.mouseMove(localMouse);
    m_downArrow.mouseMove(localMouse);
    
    std::vector<TextButton>::iterator it;
    for (it = m_arenaButtons.begin(); it != m_arenaButtons.end(); it++)
    {
        if (isClickable((*it)))
        {
            it->mouseMove(localMouse);
        }
    }
    
    return Widget::contains(localMouse);
}

bool ArenaChooser::isShown(TextButton &button) const
{
    return button.getYPosition() + button.getHeight() >
            m_upArrow.getYPosition() + m_upArrow.getHeight() &&
            button.getYPosition() < m_downArrow.getYPosition();
}

bool ArenaChooser::isClickable(TextButton &button) const
{
    return button.getYPosition() > m_upArrow.getYPosition() + m_upArrow.getHeight() &&
            button.getYPosition() + button.getHeight() < m_downArrow.getYPosition();
}
