/*
 * bookmarkmanagedlg.cpp - manage groupchat room bookmarks
 * Copyright (C) 2008  Michail Pishchagin
 *
 * 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 (at your option) 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 <https://www.gnu.org/licenses/>.
 *
 */

#include "bookmarkmanagedlg.h"

#include "bookmarkmanager.h"
#include "fileutil.h"
#include "iconset.h"
#include "psiaccount.h"

#include <QAction>
#include <QFile>
#include <QMessageBox>
#include <QPushButton>
#include <QStandardItemModel>

BookmarkManageDlg::BookmarkManageDlg(PsiAccount *account) : QDialog(), account_(account), model_(nullptr)
{
    setAttribute(Qt::WA_DeleteOnClose, true);
    setWindowFlags(Qt::Dialog | Qt::WindowTitleHint | Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint
                   | Qt::CustomizeWindowHint);
    ui_.setupUi(this);
    setWindowIcon(IconsetFactory::icon("psi/bookmarks").icon());

    account_->dialogRegister(this);

    QAction *removeBookmarkAction = new QAction(this);
    connect(removeBookmarkAction, SIGNAL(triggered()), SLOT(removeBookmark()));
    removeBookmarkAction->setShortcuts(QKeySequence::Delete);
    ui_.listView->addAction(removeBookmarkAction);

    ui_.autoJoin->addItems(ConferenceBookmark::joinTypeNames());

    ui_.pb_import->setIcon(IconsetFactory::icon("psi/import").icon());
    ui_.pb_export->setIcon(IconsetFactory::icon("psi/export").icon());
    connect(ui_.pb_import, SIGNAL(clicked()), SLOT(importBookmarks()));
    connect(ui_.pb_export, SIGNAL(clicked()), SLOT(exportBookmarks()));

    addButton_    = ui_.bookmarkButtonBox->addButton(tr("&Add"), QDialogButtonBox::ActionRole);
    removeButton_ = ui_.bookmarkButtonBox->addButton(tr("&Remove"), QDialogButtonBox::DestructiveRole);
    joinButton_   = ui_.bookmarkButtonBox->addButton(tr("&Join"), QDialogButtonBox::ActionRole);
    connect(addButton_, SIGNAL(clicked()), SLOT(addBookmark()));
    connect(removeButton_, SIGNAL(clicked()), SLOT(removeBookmark()));
    connect(joinButton_, SIGNAL(clicked()), SLOT(joinCurrentRoom()));

    model_ = new QStandardItemModel(this);
    ui_.listView->setModel(model_);
    connect(ui_.listView->itemDelegate(), SIGNAL(closeEditor(QWidget *, QAbstractItemDelegate::EndEditHint)),
            SLOT(closeEditor(QWidget *, QAbstractItemDelegate::EndEditHint)));
    connect(ui_.listView->selectionModel(), SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)),
            SLOT(selectionChanged(const QItemSelection &, const QItemSelection &)));

    connect(ui_.host, SIGNAL(textEdited(const QString &)), SLOT(updateCurrentItem()));
    connect(ui_.room, SIGNAL(textEdited(const QString &)), SLOT(updateCurrentItem()));
    connect(ui_.nickname, SIGNAL(textEdited(const QString &)), SLOT(updateCurrentItem()));
    connect(ui_.password, SIGNAL(textEdited(const QString &)), SLOT(updateCurrentItem()));
    connect(ui_.autoJoin, SIGNAL(currentIndexChanged(int)), SLOT(updateCurrentItem()));

    loadBookmarks();

    QItemSelection dummy;
    selectionChanged(dummy, dummy);
}

BookmarkManageDlg::~BookmarkManageDlg() { account_->dialogUnregister(this); }

void BookmarkManageDlg::reject() { QDialog::reject(); }

void BookmarkManageDlg::accept()
{
    QStandardItem *item = model_->item(ui_.listView->currentIndex().row());
    if (item)
        if (item->data(Qt::DisplayRole).toString().isEmpty())
            item->setData(QVariant(item->data(JidRole)), Qt::DisplayRole);

    if (account_->checkConnected(this)) {
        saveBookmarks();
        QDialog::accept();
    }
}

void BookmarkManageDlg::loadBookmarks()
{
    model_->clear();

    for (const ConferenceBookmark &c : account_->bookmarkManager()->conferences()) {
        QStandardItem *item = new QStandardItem(c.name());
        item->setData(QVariant(c.jid().full()), JidRole);
        item->setData(QVariant(c.autoJoin()), AutoJoinRole);
        item->setData(QVariant(c.nick()), NickRole);
        item->setData(QVariant(c.password()), PasswordRole);
        appendItem(item);
    }
}

ConferenceBookmark BookmarkManageDlg::bookmarkFor(const QModelIndex &index) const
{
    return ConferenceBookmark(index.data(Qt::DisplayRole).toString(), index.data(JidRole).toString(),
                              ConferenceBookmark::JoinType(index.data(AutoJoinRole).toInt()),
                              index.data(NickRole).toString(), index.data(PasswordRole).toString());
}

void BookmarkManageDlg::saveBookmarks()
{
    QList<ConferenceBookmark> conferences;
    for (int row = 0; row < model_->rowCount(); ++row) {
        QModelIndex index = model_->index(row, 0, QModelIndex());
        conferences += bookmarkFor(index);
    }

    account_->bookmarkManager()->setBookmarks(conferences);
}

void BookmarkManageDlg::addBookmark()
{
    QStandardItem *item = new QStandardItem(tr("Unnamed"));
    appendItem(item);
    ui_.listView->reset(); // ensure that open editors won't get in our way
    ui_.listView->setCurrentIndex(item->index());
    ui_.listView->edit(item->index());
}

void BookmarkManageDlg::removeBookmark() { model_->removeRow(currentIndex().row()); }

void BookmarkManageDlg::closeEditor(QWidget *editor, QAbstractItemDelegate::EndEditHint hint)
{
    Q_UNUSED(editor);

    if (hint == QAbstractItemDelegate::SubmitModelCache) {
        QList<QLineEdit *> lineEdits;
        lineEdits << ui_.host << ui_.room << ui_.nickname;
        for (QLineEdit *lineEdit : qAsConst(lineEdits)) {
            if (lineEdit->text().isEmpty()) {
                lineEdit->setFocus();
                break;
            }
        }
    }
}

void BookmarkManageDlg::selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
{
    QModelIndex current;
    if (!selected.indexes().isEmpty())
        current = selected.indexes().first();

    if (!deselected.isEmpty()) {
        QStandardItem *item = model_->item(deselected.indexes().first().row());
        if (item)
            if (item->data(Qt::DisplayRole).toString().isEmpty())
                item->setData(QVariant(item->data(JidRole)), Qt::DisplayRole);
    }

    XMPP::Jid jid = XMPP::Jid(current.data(JidRole).toString());
    ui_.host->setText(jid.domain());
    ui_.room->setText(jid.node());
    ui_.nickname->setText(current.data(NickRole).toString());
    ui_.password->setText(current.data(PasswordRole).toString());
    ui_.autoJoin->setCurrentIndex(current.data(AutoJoinRole).toInt());
    QList<QWidget *> editors;
    editors << ui_.host << ui_.room << ui_.nickname << ui_.password << ui_.autoJoin;
    for (QWidget *w : qAsConst(editors)) {
        w->setEnabled(current.isValid());
    }

    removeButton_->setEnabled(current.isValid());
    updateCurrentItem();
}

XMPP::Jid BookmarkManageDlg::jid() const { return XMPP::Jid(ui_.room->text(), ui_.host->text()); }

void BookmarkManageDlg::updateCurrentItem()
{
    joinButton_->setEnabled(!jid().domain().isEmpty() && !jid().node().isEmpty() && !ui_.nickname->text().isEmpty());

    QStandardItem *item = model_->item(currentIndex().row());
    if (item) {
        item->setData(QVariant(jid().full()), JidRole);
        item->setData(QVariant(ui_.autoJoin->currentIndex()), AutoJoinRole);
        item->setData(QVariant(ui_.nickname->text()), NickRole);
        item->setData(QVariant(ui_.password->text()), PasswordRole);
    }
}

QModelIndex BookmarkManageDlg::currentIndex() const
{
    if (!ui_.listView->selectionModel()->selectedIndexes().isEmpty())
        return ui_.listView->selectionModel()->selectedIndexes().first();
    return QModelIndex();
}

void BookmarkManageDlg::joinCurrentRoom() { account_->actionJoin(bookmarkFor(currentIndex()), true); }

void BookmarkManageDlg::appendItem(QStandardItem *item)
{
    item->setDragEnabled(true);
    item->setDropEnabled(false);
    model_->invisibleRootItem()->appendRow(item);
}

void BookmarkManageDlg::importBookmarks()
{
    QString fileName = FileUtil::getOpenFileName(this, tr("Import bookmarks"));
    if (fileName.isEmpty())
        return;

    QFile file(fileName);
    if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        QDomDocument doc;
        QString      error;
        if (doc.setContent(&file, &error)) {
            QDomElement root = doc.firstChildElement("bookmarks");
            if (root.isNull())
                return;
            QDomElement elem = root.firstChildElement("conference");
            while (!elem.isNull()) {
                ConferenceBookmark c(elem);

                QStandardItem *item = new QStandardItem(c.name());
                item->setData(QVariant(c.jid().full()), JidRole);
                item->setData(QVariant(c.autoJoin()), AutoJoinRole);
                item->setData(QVariant(c.nick()), NickRole);
                item->setData(QVariant(c.password()), PasswordRole);
                appendItem(item);

                elem = elem.nextSiblingElement("conference");
            }
        } else {
            QMessageBox::warning(this, tr("Error!"), error);
        }
    }
}

void BookmarkManageDlg::exportBookmarks()
{
    QString fileName = FileUtil::getSaveFileName(this, tr("Export bookmarks"), "bookmarks.txt");
    if (fileName.isEmpty())
        return;

    QFile file(fileName);
    if (file.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text)) {
        QDomDocument doc;
        QDomElement  root = doc.createElement("bookmarks");
        doc.appendChild(root);
        for (int row = 0; row < model_->rowCount(); ++row) {
            QModelIndex        index = model_->index(row, 0, QModelIndex());
            ConferenceBookmark cb    = bookmarkFor(index);
            root.appendChild(cb.toXml(doc));
        }
        file.write(doc.toString().toLocal8Bit());
    }
}
