/*
    SPDX-FileCopyrightText: 2007 Joris Guisson <joris.guisson@gmail.com>
    SPDX-License-Identifier: GPL-2.0-or-later
*/

#include "groupview.h"

#include <QAction>
#include <QDragEnterEvent>
#include <QDropEvent>
#include <QHeaderView>
#include <QInputDialog>
#include <QMenu>
#include <QTreeWidgetItemIterator>

#include <KActionCollection>
#include <KConfigGroup>
#include <KLocalizedString>
#include <KMessageBox>

#include "core.h"
#include "grouppolicydlg.h"
#include "gui.h"
#include "view/view.h"
#include <groups/group.h>
#include <groups/groupmanager.h>
#include <groups/torrentgroup.h>
#include <interfaces/torrentactivityinterface.h>
#include <interfaces/torrentinterface.h>
#include <util/log.h>

using namespace bt;

namespace kt
{
GroupView::GroupView(GroupManager *gman, View *view, Core *core, GUI *gui, QWidget *parent)
    : QTreeView(parent)
    , gui(gui)
    , core(core)
    , view(view)
    , gman(gman)
    , model(new GroupTreeModel(gman, parent))
{
    setRootIsDecorated(false);
    setContextMenuPolicy(Qt::CustomContextMenu);
    setModel(model);
    header()->hide();

    connect(this, &GroupView::clicked, this, &GroupView::onItemClicked);
    connect(this, &GroupView::customContextMenuRequested, this, &GroupView::showContextMenu);
    connect(this, &GroupView::currentGroupChanged, view, &View::onCurrentGroupChanged);
    connect(gman, &GroupManager::customGroupChanged, this, &GroupView::updateGroupCount);
    connect(model, &GroupTreeModel::addTorrentSelectionToGroup, this, &GroupView::addTorrentSelectionToGroup);

    setAcceptDrops(true);
    setDropIndicatorShown(true);
    setDragDropMode(QAbstractItemView::DropOnly);
}

GroupView::~GroupView()
{
}

void GroupView::setupActions(KActionCollection *col)
{
    open_in_new_tab = new QAction(QIcon::fromTheme(QStringLiteral("list-add")), i18n("Open In New Tab"), this);
    connect(open_in_new_tab, &QAction::triggered, this, &GroupView::openInNewTab);
    col->addAction(QStringLiteral("open_in_new_tab"), open_in_new_tab);

    new_group = new QAction(QIcon::fromTheme(QStringLiteral("document-new")), i18n("New Group"), this);
    connect(new_group, &QAction::triggered, this, &GroupView::addGroup);
    col->addAction(QStringLiteral("new_group"), new_group);

    edit_group = new QAction(QIcon::fromTheme(QStringLiteral("insert-text")), i18n("Edit Name"), this);
    connect(edit_group, &QAction::triggered, this, &GroupView::editGroupName);
    col->addAction(QStringLiteral("edit_group_name"), edit_group);

    remove_group = new QAction(QIcon::fromTheme(QStringLiteral("edit-delete")), i18n("Remove Group"), this);
    connect(remove_group, &QAction::triggered, this, &GroupView::removeGroup);
    col->addAction(QStringLiteral("remove_group"), remove_group);

    edit_group_policy = new QAction(QIcon::fromTheme(QStringLiteral("preferences-other")), i18n("Group Policy"), this);
    connect(edit_group_policy, &QAction::triggered, this, &GroupView::editGroupPolicy);
    col->addAction(QStringLiteral("edit_group_policy"), edit_group_policy);
}

void GroupView::addGroup()
{
    addNewGroup();
}

Group *GroupView::addNewGroup()
{
    bool ok = false;
    QString name = QInputDialog::getText(this, QString(), i18n("Please enter the group name."), QLineEdit::Normal, QString(), &ok);

    if (name.isEmpty() || name.length() == 0 || !ok)
        return nullptr;

    if (gman->find(name)) {
        KMessageBox::error(this, i18n("The group %1 already exists.", name));
        return nullptr;
    }

    Group *g = gman->newGroup(name);
    gman->saveGroups();
    return g;
}

void GroupView::removeGroup()
{
    Group *g = model->groupForIndex(selectionModel()->currentIndex());
    if (g) {
        gman->removeGroup(g);
        gman->saveGroups();
    }
}

void GroupView::editGroupName()
{
    edit(selectionModel()->currentIndex());
}

void GroupView::showContextMenu(const QPoint &p)
{
    Group *g = model->groupForIndex(selectionModel()->currentIndex());

    bool enable = gman->canRemove(g);
    edit_group->setEnabled(enable);
    remove_group->setEnabled(enable);
    edit_group_policy->setEnabled(enable);

    open_in_new_tab->setEnabled(g != nullptr);

    QMenu *menu = gui->getTorrentActivity()->part()->menu(QStringLiteral("GroupsMenu"));
    if (menu)
        menu->popup(viewport()->mapToGlobal(p));
}

void GroupView::onItemClicked(const QModelIndex &index)
{
    Group *g = model->groupForIndex(index);
    if (g)
        Q_EMIT currentGroupChanged(g);
}

void GroupView::editGroupPolicy()
{
    Group *g = model->groupForIndex(selectionModel()->currentIndex());
    if (g) {
        GroupPolicyDlg dlg(g, this);
        if (dlg.exec() == QDialog::Accepted)
            gman->saveGroups();
    }
}

void GroupView::saveState(KSharedConfigPtr cfg)
{
    KConfigGroup g = cfg->group(QStringLiteral("GroupView"));
    g.writeEntry("expanded", expandedGroupPaths());
    g.writeEntry("visible", isVisible());
}

void GroupView::loadState(KSharedConfigPtr cfg)
{
    KConfigGroup g = cfg->group(QStringLiteral("GroupView"));
    QStringList default_expanded;
    default_expanded << QStringLiteral("/all") << QStringLiteral("/all/downloads") << QStringLiteral("/all/uploads") << QStringLiteral("/all/active")
                     << QStringLiteral("/all/passive") << QStringLiteral("/all/custom");
    QStringList slist = g.readEntry("expanded", default_expanded);
    expandGroups(slist);
    setVisible(g.readEntry("visible", true));
    expand(model->index(0, 0));
}

QStringList GroupView::expandedGroupPaths() const
{
    QStringList groupPaths;
    expandedGroupPaths(groupPaths, model->index(0, 0));
    return groupPaths;
}

void GroupView::expandedGroupPaths(QStringList &groups, const QModelIndex &index) const
{
    if (model->rowCount(index) == 0 || !isExpanded(index)) {
        return;
    }

    groups << model->data(index, GroupTreeModel::PathRole).toString();

    for (int row = 0; row < model->rowCount(index); ++row) {
        expandedGroupPaths(groups, model->index(row, 0, index));
    }
}

void GroupView::expandGroups(const QStringList &groupPaths)
{
    for (const auto &groupPath : groupPaths) {
        const auto indexMatches = model->match(model->index(0, 0), GroupTreeModel::PathRole, groupPath, 1, Qt::MatchRecursive | Qt::MatchExactly);
        if (!indexMatches.isEmpty() && indexMatches.first().isValid()) {
            expand(indexMatches.first());
        }
    }
}

void GroupView::keyPressEvent(QKeyEvent *event)
{
    if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return)
        onItemClicked(selectionModel()->currentIndex());
    else
        QTreeView::keyPressEvent(event);
}

void GroupView::updateGroupCount()
{
    model->updateGroupCount(model->index(0, 0));
}

void GroupView::openInNewTab()
{
    Group *g = model->groupForIndex(selectionModel()->currentIndex());
    if (g)
        Q_EMIT openTab(g);
}
}

#include "moc_groupview.cpp"
