/*
 *  Extended support for activating emotes
 *  Copyright (C) 2009  Aethyra Development Team
 *  Copyright (C) 2009  The Mana World Development Team
 *  Copyright (C) 2009-2010  The Mana Developers
 *  Copyright (C) 2011  The ManaPlus Developers
 *
 *  This file is part of The ManaPlus Client.
 *
 *  This program 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 2 of the License, or
 *  any later version.
 *
 *  This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "gui/emotepopup.h"

#include "animatedsprite.h"
#include "configuration.h"
#include "emoteshortcut.h"
#include "graphics.h"
#include "localplayer.h"
#include "log.h"

#include "gui/theme.h"

#include "resources/emotedb.h"
#include "resources/image.h"
#include "resources/iteminfo.h"

#include "utils/dtor.h"

#include <guichan/mouseinput.hpp>
#include <guichan/selectionlistener.hpp>

const int EmotePopup::gridWidth = 34;  // emote icon width + 4
const int EmotePopup::gridHeight = 36; // emote icon height + 4

static const int MAX_COLUMNS = 6;

EmotePopup::EmotePopup():
    mSelectedEmoteIndex(-1),
    mHoveredEmoteIndex(-1),
    mRowCount(1),
    mColumnCount(1)
{
    // Setup emote sprites
    for (int i = 0; i <= EmoteDB::getLast(); ++i)
    {
        const AnimatedSprite *sprite = EmoteDB::getAnimation(i, true);
        if (sprite)
            mEmotes.push_back(sprite);
    }

    mSelectionImage = Theme::getImageFromTheme("selection.png");
    if (!mSelectionImage)
        logger->log1("Error: Unable to load selection.png");

    if (mSelectionImage)
        mSelectionImage->setAlpha(Client::getGuiAlpha());

    addMouseListener(this);
    recalculateSize();
    setVisible(true);
}

EmotePopup::~EmotePopup()
{
    if (mSelectionImage)
        mSelectionImage->decRef();
}

void EmotePopup::draw(gcn::Graphics *graphics)
{
    Popup::draw(graphics);

    if (!mColumnCount)
        return;

    const unsigned int emoteCount = static_cast<unsigned>(mEmotes.size());
    const unsigned int emotesLeft
        = static_cast<unsigned>(mEmotes.size() % mColumnCount);

    for (unsigned int i = 0; i < emoteCount ; i++)
    {
        int row = i / mColumnCount;
        int column = i % mColumnCount;

        unsigned int emoteX = 4 + column * gridWidth;
        unsigned int emoteY = 4 + row * gridHeight;

        // Center the last row when there are less emotes than columns
        if (emotesLeft > 0 && row == mRowCount - 1)
            emoteX += (mColumnCount - emotesLeft) * gridWidth / 2;

        // Draw selection image below hovered item
        if (mSelectionImage && static_cast<int>(i) == mHoveredEmoteIndex)
        {
            static_cast<Graphics*>(graphics)->drawImage(
                    mSelectionImage, emoteX, emoteY + 4);
        }

        // Draw emote icon
        if (mEmotes[i])
            mEmotes[i]->draw(static_cast<Graphics*>(graphics), emoteX, emoteY);
    }
}

void EmotePopup::mousePressed(gcn::MouseEvent &event)
{
    if (event.getButton() != gcn::MouseEvent::LEFT)
        return;

    const int index = getIndexAt(event.getX(), event.getY());
    if (index != -1)
    {
        setSelectedEmoteIndex(index);
        if (emoteShortcut)
        {
            emoteShortcut->setEmoteSelected(
                static_cast<unsigned char>(index + 1));
        }
    }
}

void EmotePopup::mouseMoved(gcn::MouseEvent &event)
{
    Popup::mouseMoved(event);

    mHoveredEmoteIndex = getIndexAt(event.getX(), event.getY());
}

int EmotePopup::getSelectedEmote() const
{
    return 1 + mSelectedEmoteIndex;
}

void EmotePopup::setSelectedEmoteIndex(int index)
{
    if (index == mSelectedEmoteIndex)
        return;

    mSelectedEmoteIndex = index;
    distributeValueChangedEvent();
}

int EmotePopup::getIndexAt(int x, int y) const
{
    if (!gridWidth || !gridHeight)
        return -1;

    const unsigned int emotesLeft
        = static_cast<unsigned>(mEmotes.size() % mColumnCount);
    const unsigned int row = y / gridHeight;
    unsigned int column;

    // Take into account that the last row is centered
    if (emotesLeft > 0 && static_cast<signed>(row) == mRowCount - 1)
    {
        int unsigned emotesMissing = mColumnCount - emotesLeft;
        column = std::min((x - emotesMissing * gridWidth / 2) / gridWidth,
                          emotesLeft - 1);
    }
    else
    {
        column = std::min(x / gridWidth, mColumnCount - 1);
    }

    int unsigned index = column + (row * mColumnCount);

    if (index < mEmotes.size())
        return index;

    return -1;
}

void EmotePopup::recalculateSize()
{
    const unsigned emoteCount = static_cast<unsigned>(mEmotes.size());

    mRowCount = emoteCount / MAX_COLUMNS;
    if (emoteCount % MAX_COLUMNS > 0)
        ++mRowCount;

    if (mRowCount)
        mColumnCount = emoteCount / mRowCount;
    else
        mColumnCount = 1;

    if (emoteCount % mRowCount > 0)
        ++mColumnCount;

    setContentSize(mColumnCount * gridWidth, mRowCount * gridHeight);
}

void EmotePopup::distributeValueChangedEvent()
{
    gcn::SelectionEvent event(this);
    Listeners::const_iterator i_end = mListeners.end();
    Listeners::const_iterator i;

    for (i = mListeners.begin(); i != i_end; ++i)
    {
        if (*i)
            (*i)->valueChanged(event);
    }
}