/*
 * adduserdlg.cpp - dialog for adding contacts
 * Copyright (C) 2001-2002  Justin Karneges
 *
 * 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 "adduserdlg.h"

#include "busywidget.h"
#include "common.h"
#include "iconwidget.h"
#include "infodlg.h"
#include "psiaccount.h"
#include "psiiconset.h"
#include "tasklist.h"
#include "vcardfactory.h"
#include "xmpp_client.h"
#include "xmpp_tasks.h"
#include "xmpp_vcard.h"

#include <QCheckBox>
#include <QComboBox>
#include <QLabel>
#include <QLayout>
#include <QLineEdit>
#include <QMessageBox>
#include <QPushButton>
#include <QStringList>

class AddUserDlg::Private {
public:
    Private() = default;

    PsiAccount *pa    = nullptr;
    BusyWidget *busy  = nullptr;
    JT_Gateway *jt    = nullptr;
    TaskList *  tasks = nullptr;

    QStringList services;
};

AddUserDlg::AddUserDlg(const QStringList &services, const QStringList &names, const QStringList &groups,
                       PsiAccount *pa) :
    QDialog(nullptr)
{
    init(groups, pa);
    d->services = services;

    cb_service->setItemIcon(0, IconsetFactory::icon("psi/xmpp").icon());
    QStringList::ConstIterator it1 = services.begin();
    QStringList::ConstIterator it2 = names.begin();
    for (; it1 != services.end(); ++it1, ++it2)
        cb_service->addItem(PsiIconset::instance()->status(*it1, STATUS_ONLINE).icon(), *it2);
    connect(cb_service, SIGNAL(activated(int)), SLOT(serviceActivated(int)));

    connect(le_transPrompt, SIGNAL(textChanged(const QString &)), SLOT(le_transPromptChanged(const QString &)));
    pb_transGet->setEnabled(false);
}

AddUserDlg::AddUserDlg(const XMPP::Jid &jid, const QString &nick, const QString &group, const QStringList &groups,
                       PsiAccount *pa)
{
    init(groups, pa);

    le_jid->setText(jid.full()); // TODO: do we want to encourage adding jids with resource?
    le_nick->setText(nick);

    QStringList suggestedGroups = groups.filter(group, Qt::CaseInsensitive);
    if (suggestedGroups.size() > 0) {
        cb_group->lineEdit()->setText(suggestedGroups[0]);
    } else {
        cb_group->lineEdit()->setText(group);
    }

    QSize s(tb_info->width(), w_serviceTranslation->sizeHint().height());
    w_serviceTranslation->hide();
    w_serviceTranslation->setEnabled(false);
    tb_info->hide();

    resize(size() - s);
}

void AddUserDlg::init(const QStringList &groups, PsiAccount *pa)
{
    setupUi(this);
    setModal(false);
    setAttribute(Qt::WA_DeleteOnClose);
    d     = new Private;
    d->pa = pa;
    d->pa->dialogRegister(this);
    d->jt    = nullptr;
    d->tasks = new TaskList;
    connect(d->tasks, SIGNAL(started()), busy, SLOT(start()));
    connect(d->tasks, SIGNAL(finished()), busy, SLOT(stop()));

    setWindowTitle(CAP(windowTitle()));
    setWindowIcon(IconsetFactory::icon("psi/addContact").icon());
    setWindowFlags(Qt::Dialog | Qt::WindowTitleHint | Qt::WindowMinimizeButtonHint | Qt::WindowCloseButtonHint
                   | Qt::CustomizeWindowHint);

    d->busy = busy;

    QString str = tr("<None>");
    cb_group->addItem(str);
    QStringList temp = groups;
    temp.sort();
    cb_group->addItems(temp);
    str = tr("Hidden");
    if (!groups.contains(str)) {
        cb_group->addItem(str);
    }

    pb_add->setDefault(true);
    connect(pb_add, SIGNAL(clicked()), SLOT(ok()));
    connect(pb_close, SIGNAL(clicked()), SLOT(cancel()));
    connect(pb_transGet, SIGNAL(clicked()), SLOT(getTransID()));

    connect(tb_vCard, SIGNAL(clicked()), SLOT(getVCardActivated()));
    connect(tb_resolveNick, SIGNAL(clicked()), SLOT(resolveNickActivated()));

    connect(le_jid, SIGNAL(textChanged(QString)), SLOT(jid_Changed()));

    ck_authreq->setChecked(true);
    ck_close->setChecked(true);

    le_jid->setFocus();
}

AddUserDlg::~AddUserDlg()
{
    delete d->tasks;
    d->pa->dialogUnregister(this);
    delete d;
}

Jid AddUserDlg::jid() const { return Jid(le_jid->text().trimmed()); }

void AddUserDlg::cancel()
{
    le_jid->setText("");
    le_nick->setText("");
    cb_group->setCurrentIndex(0);
    reject();
}

void AddUserDlg::ok()
{
    if (!d->pa->checkConnected()) {
        return;
    }

    if (le_jid->text().isEmpty()) {
        QMessageBox::information(this, tr("Add User: Error"),
                                 tr("Please fill in the XMPP address of the person you wish to add."));
        return;
    }
    if (!jid().isValid()) {
        QMessageBox::information(
            this, tr("Add User: Error"),
            tr("The XMPP address you entered is not valid!\nMake sure you enter a fully qualified XMPP address."));
        return;
    }

    QString     gname = cb_group->currentText();
    QStringList list;
    if (gname != tr("<None>")) {
        list += gname;
    }

    emit add(jid(), le_nick->text(), list, ck_authreq->isChecked());

    QMessageBox::information(this, tr("Add User: Success"), tr("Added %1 to your roster.").arg(jid().full()));
    le_jid->setText("");
    le_nick->setText("");
    if (ck_close->isChecked()) {
        cb_group->setCurrentIndex(0);
        accept();
    } else {
        le_jid->setFocus();
    }
}

void AddUserDlg::serviceActivated(int x)
{
    if (d->jt) {
        delete d->jt;
        d->jt = nullptr;
        d->busy->stop();
    }
    gb_trans->setEnabled(false);
    le_transPrompt->setText("");

    // XMPP entry
    if (x == 0)
        return;
    --x;

    if (x >= 0 && x < int(d->services.count())) {
        d->jt = new JT_Gateway(d->pa->client()->rootTask());
        connect(d->jt, SIGNAL(finished()), SLOT(jt_getFinished()));
        d->jt->get(Jid(d->services[x]));
        d->jt->go(true);
        d->tasks->append(d->jt);
    }
}

void AddUserDlg::le_transPromptChanged(const QString &str) { pb_transGet->setEnabled(!str.isEmpty()); }

void AddUserDlg::getTransID()
{
    cb_service->setEnabled(false);
    le_transPrompt->setEnabled(false);
    pb_transGet->setEnabled(false);

    d->jt = new JT_Gateway(d->pa->client()->rootTask());
    connect(d->jt, SIGNAL(finished()), SLOT(jt_setFinished()));
    d->jt->set(Jid(d->services[cb_service->currentIndex() - 1]), le_transPrompt->text());
    d->jt->go(true);
    d->tasks->append(d->jt);
}

void AddUserDlg::jt_getFinished()
{
    JT_Gateway *jt = d->jt;
    d->jt          = nullptr;

    if (jt->success()) {
        gb_trans->setEnabled(true);
        lb_transDesc->setText(jt->desc());
    } else {
        errorGateway(cb_service->currentText(), jt->statusString());
    }
}

void AddUserDlg::jt_setFinished()
{
    cb_service->setEnabled(true);
    le_transPrompt->setEnabled(true);
    pb_transGet->setEnabled(true);

    JT_Gateway *jt = d->jt;
    d->jt          = nullptr;

    if (jt->success()) {
        QString jid = jt->translatedJid().full();
        if (jid.isEmpty()) {
            jid = jt->prompt();
            // we used to read only prompt() in the past,
            // and many gateways still send it
        }
        le_jid->setText(jid);
        le_nick->setText(le_transPrompt->text());
        le_transPrompt->setText("");
        le_jid->setCursorPosition(0);
        le_nick->setCursorPosition(0);

        le_nick->setFocus();
        le_nick->selectAll();
    } else {
        errorGateway(cb_service->currentText(), jt->statusString());
        le_transPrompt->setFocus();
    }
}

void AddUserDlg::errorGateway(const QString &str, const QString &err)
{
    QMessageBox::information(this, CAP(tr("Error")),
                             tr("<qt>\n"
                                "There was an error getting the Service ID translation information from \"%1\".<br>"
                                "Reason: %2<br>"
                                "<br>"
                                "The service may not support this feature.  In this case you "
                                "will need to enter the XMPP address manually for the contact you wish "
                                "to add.  Examples:<br>"
                                "<br>"
                                "&nbsp;&nbsp;xmppUser@somehost.com<br>"
                                "&nbsp;&nbsp;1234567@[XMPP address of Transport]<br>"
                                "&nbsp;&nbsp;joe%gmail.com@[XMPP address of Transport]<br>"
                                "</qt>")
                                 .arg(str, QString(err).replace('\n', "<br>")));
}

void AddUserDlg::getVCardActivated()
{
    const VCard vcard = VCardFactory::instance()->vcard(jid());

    InfoDlg *w = new InfoDlg(InfoWidget::Contact, jid(), vcard, d->pa, nullptr, false);
    w->show();

    // automatically retrieve info if it doesn't exist
    if (!vcard)
        w->infoWidget()->doRefresh();
}

void AddUserDlg::resolveNickActivated()
{
    JT_VCard *jt = VCardFactory::instance()->getVCard(
        jid(), d->pa->client()->rootTask(), this,
        [this]() {
            JT_VCard *jt = static_cast<JT_VCard *>(sender());

            if (jt->success()) {
                QString           nickname;
                const XMPP::VCard vcard = jt->vcard();
                if (!vcard.nickName().isEmpty()) {
                    nickname = vcard.nickName();
                } else if (!vcard.fullName().isEmpty()) {
                    nickname = vcard.fullName();
                } else {
                    nickname = vcard.givenName();
                    if (nickname.isEmpty()) {
                        nickname = vcard.middleName();
                    } else if (!vcard.middleName().isEmpty()) {
                        nickname += " " + vcard.middleName();
                    }
                    if (nickname.isEmpty()) {
                        nickname = vcard.familyName();
                    } else if (!vcard.familyName().isEmpty()) {
                        nickname += " " + vcard.familyName();
                    }
                }

                if (nickname.isEmpty()) {
                    nickname = jt->jid().bare();
                }
                le_nick->setText(nickname);
            }
        },
        false);
    d->tasks->append(jt);
}

/**
 * Called when the Jid changes to enable the vcard and nick resolution buttons.
 */
void AddUserDlg::jid_Changed()
{
    bool enableVCardButtons = jid().isValid();
    tb_vCard->setEnabled(enableVCardButtons);
    tb_resolveNick->setEnabled(enableVCardButtons);
}
