/*
 *  The ManaPlus Client
 *  Copyright (C) 2008-2009  The Mana World Development Team
 *  Copyright (C) 2009-2010  The Mana Developers
 *  Copyright (C) 2011-2017  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/widgets/tabs/setup_relations.h"

#include "actormanager.h"

#include "being/localplayer.h"

#include "gui/models/ignorechoiceslistmodel.h"
#include "gui/models/playertablemodel.h"

#include "gui/widgets/button.h"
#include "gui/widgets/checkbox.h"
#include "gui/widgets/containerplacer.h"
#include "gui/widgets/dropdown.h"
#include "gui/widgets/label.h"
#include "gui/widgets/layouthelper.h"
#include "gui/widgets/scrollarea.h"
#include "gui/widgets/guitable.h"

#include "utils/delete2.h"

#include "debug.h"

static const int COLUMNS_NR = 2;  // name plus listbox
static const int NAME_COLUMN = 0;
static const unsigned int NAME_COLUMN_WIDTH = 230;
static const unsigned int RELATION_CHOICE_COLUMN = 1;
static const unsigned int RELATION_CHOICE_COLUMN_WIDTH = 80;

static const std::string ACTION_DELETE("delete");
static const std::string ACTION_TABLE("table");
static const std::string ACTION_STRATEGY("strategy");

static const char *const table_titles[COLUMNS_NR] =
{
    // TRANSLATORS: relations table header
    N_("Name"),
    // TRANSLATORS: relations table header
    N_("Relation")
};

Setup_Relations::Setup_Relations(const Widget2 *const widget) :
    SetupTab(widget),
    PlayerRelationsListener(),
    mPlayerTableTitleModel(new StaticTableModel(1, COLUMNS_NR)),
    mPlayerTableModel(new PlayerTableModel(this)),
    mPlayerTable(new GuiTable(this, mPlayerTableModel)),
    mPlayerTitleTable(new GuiTable(this, mPlayerTableTitleModel)),
    mPlayerScrollArea(new ScrollArea(this, mPlayerTable)),
    // TRANSLATORS: relation dialog button
    mDefaultTrading(new CheckBox(this, _("Allow trading"),
        (playerRelations.getDefault() & PlayerRelation::TRADE) != 0u)),
    // TRANSLATORS: relation dialog button
    mDefaultWhisper(new CheckBox(this, _("Allow whispers"),
       (playerRelations.getDefault() & PlayerRelation::WHISPER) != 0u)),
    // TRANSLATORS: relation dialog button
    mDeleteButton(new Button(this, _("Delete"), ACTION_DELETE, this)),
    mIgnoreActionChoicesModel(new IgnoreChoicesListModel),
    mIgnoreActionChoicesBox(new DropDown(widget, mIgnoreActionChoicesModel))
{
    // TRANSLATORS: relation dialog name
    setName(_("Relations"));

    mPlayerTable->setOpaque(Opaque_false);

    mPlayerTableTitleModel->fixColumnWidth(NAME_COLUMN, NAME_COLUMN_WIDTH);
    mPlayerTableTitleModel->fixColumnWidth(RELATION_CHOICE_COLUMN,
                                           RELATION_CHOICE_COLUMN_WIDTH);
    mPlayerTitleTable->setBackgroundColor(getThemeColor(
        ThemeColorId::TABLE_BACKGROUND));
    mPlayerTitleTable->setSelectableGui(false);

    for (int i = 0; i < COLUMNS_NR; i++)
    {
        mPlayerTableTitleModel->set(0, i, new Label(
            this, gettext(table_titles[i])));
    }

    mPlayerTitleTable->setLinewiseSelection(true);

    mPlayerScrollArea->setHorizontalScrollPolicy(ScrollArea::SHOW_NEVER);
    mPlayerTable->setActionEventId(ACTION_TABLE);
    mPlayerTable->setLinewiseSelection(true);
    mPlayerTable->addActionListener(this);

    // TRANSLATORS: relation dialog label
    Label *const ignore_action_label = new Label(this, _("When ignoring:"));

    mIgnoreActionChoicesBox->setActionEventId(ACTION_STRATEGY);
    mIgnoreActionChoicesBox->addActionListener(this);

    int ignore_strategy_index = 0;  // safe default

    if (playerRelations.getPlayerIgnoreStrategy() != nullptr)
    {
        ignore_strategy_index = playerRelations.getPlayerIgnoreStrategyIndex(
            playerRelations.getPlayerIgnoreStrategy()->mShortName);
        if (ignore_strategy_index < 0)
            ignore_strategy_index = 0;
    }
    mIgnoreActionChoicesBox->setSelected(ignore_strategy_index);
    mIgnoreActionChoicesBox->adjustHeight();

    reset();

    // Do the layout
    LayoutHelper h(this);
    ContainerPlacer place = h.getPlacer(0, 0);

    place(0, 0, mPlayerTitleTable, 6);
    place(0, 1, mPlayerScrollArea, 6, 4).setPadding(2);
    place(0, 5, mDeleteButton);
    place(3, 5, ignore_action_label, 1);
    place(4, 5, mIgnoreActionChoicesBox, 2).setPadding(2);
    place(3, 6, mDefaultTrading, 3);
    place(3, 7, mDefaultWhisper, 3);

    playerRelations.addListener(this);

    setDimension(Rect(0, 0, 500, 350));
}

Setup_Relations::~Setup_Relations()
{
    playerRelations.removeListener(this);
    delete2(mIgnoreActionChoicesModel);
}


void Setup_Relations::reset()
{
    // We now have to search through the list of ignore choices to find the
    // current selection. We could use an index into the table of config
    // options in playerRelations instead of strategies to sidestep this.
    int selection = 0;
    for (size_t i = 0, sz = playerRelations.getPlayerIgnoreStrategies()
         ->size(); i < sz; ++ i)
    {
        if ((*playerRelations.getPlayerIgnoreStrategies())[i] ==
            playerRelations.getPlayerIgnoreStrategy())
        {
            selection = CAST_S32(i);
            break;
        }
    }
    mIgnoreActionChoicesBox->setSelected(selection);
}

void Setup_Relations::apply()
{
    playerRelations.store();

    const unsigned int old_default_relations = playerRelations.getDefault() &
        ~(PlayerRelation::TRADE | PlayerRelation::WHISPER);
    playerRelations.setDefault(old_default_relations
        | (mDefaultTrading->isSelected() ? PlayerRelation::TRADE : 0)
        | (mDefaultWhisper->isSelected() ? PlayerRelation::WHISPER : 0));

    if (actorManager != nullptr)
        actorManager->updatePlayerNames();

    if (localPlayer != nullptr)
        localPlayer->setCheckNameSetting(true);
}

void Setup_Relations::cancel()
{
}

void Setup_Relations::action(const ActionEvent &event)
{
    const std::string &eventId = event.getId();
    if (eventId == ACTION_TABLE)
    {
        // temporarily eliminate ourselves: we are fully aware of this change,
        // so there is no need for asynchronous updates.  (In fact, thouse
        // might destroy the widet that triggered them, which would be rather
        // embarrassing.)
        playerRelations.removeListener(this);

        const int row = mPlayerTable->getSelectedRow();
        if (row >= 0)
            mPlayerTableModel->updateModelInRow(row);

        playerRelations.addListener(this);
    }
    else if (eventId == ACTION_DELETE)
    {
        const int player_index = mPlayerTable->getSelectedRow();

        if (player_index < 0)
            return;

        playerRelations.removePlayer(mPlayerTableModel->getPlayerAt(
            player_index));
    }
    else if (eventId == ACTION_STRATEGY)
    {
        const int sel = mIgnoreActionChoicesBox->getSelected();
        if (sel < 0)
            return;
        PlayerIgnoreStrategy *const s =
            (*playerRelations.getPlayerIgnoreStrategies())[sel];

        playerRelations.setPlayerIgnoreStrategy(s);
    }
}

void Setup_Relations::updatedPlayer(const std::string &name A_UNUSED)
{
    mPlayerTableModel->playerRelationsUpdated();
    mDefaultTrading->setSelected(
            (playerRelations.getDefault() & PlayerRelation::TRADE) != 0u);
    mDefaultWhisper->setSelected(
            (playerRelations.getDefault() & PlayerRelation::WHISPER) != 0u);
    if (localPlayer != nullptr)
        localPlayer->updateName();
}

void Setup_Relations::updateAll()
{
    PlayerTableModel *const model = new PlayerTableModel(this);
    mPlayerTable->setModel(model);
    delete mPlayerTableModel;
    mPlayerTableModel = model;
    int ignore_strategy_index = 0;  // safe default

    if (playerRelations.getPlayerIgnoreStrategy() != nullptr)
    {
        ignore_strategy_index = playerRelations.getPlayerIgnoreStrategyIndex(
                playerRelations.getPlayerIgnoreStrategy()->mShortName);
        if (ignore_strategy_index < 0)
            ignore_strategy_index = 0;
    }
    mIgnoreActionChoicesBox->setSelected(ignore_strategy_index);
    mIgnoreActionChoicesBox->adjustHeight();
    reset();
}
void Setup_Relations::externalUpdated()
{
    mDefaultTrading->setSelected(
        (playerRelations.getDefault() & PlayerRelation::TRADE) != 0u);
    mDefaultWhisper->setSelected(
        (playerRelations.getDefault() & PlayerRelation::WHISPER) != 0u);
}
