/*
 * Copyright (C) 2001-2002  Justin Karneges
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library.  If not, see <https://www.gnu.org/licenses/>.
 *
 */

#include "xmpp_discoinfotask.h"

#include "xmpp/jid/jid.h"
#include "xmpp_caps.h"
#include "xmpp_client.h"
#include "xmpp_discoitem.h"
#include "xmpp_task.h"
#include "xmpp_xmlcommon.h"

#include <QDomElement>
#include <QString>
#include <QTimer>

using namespace XMPP;

class DiscoInfoTask::Private {
public:
    bool                allowCache = true;
    Jid                 jid;
    QString             node;
    DiscoItem::Identity ident;
    DiscoItem           item;
};

DiscoInfoTask::DiscoInfoTask(Task *parent) : Task(parent) { d = new Private; }

DiscoInfoTask::~DiscoInfoTask() { delete d; }

void DiscoInfoTask::setAllowCache(bool allow) { d->allowCache = allow; }

void DiscoInfoTask::get(const DiscoItem &item)
{
    DiscoItem::Identity id;
    if (item.identities().count() == 1)
        id = item.identities().first();
    get(item.jid(), item.node(), id);
}

void DiscoInfoTask::get(const Jid &j, const QString &node, DiscoItem::Identity ident)
{
    d->item = DiscoItem(); // clear item

    d->jid   = j;
    d->node  = node;
    d->ident = ident;
}

/**
 * Original requested jid.
 * Is here because sometimes the responder does not include this information
 * in the reply.
 */
const Jid &DiscoInfoTask::jid() const { return d->jid; }

/**
 * Original requested node.
 * Is here because sometimes the responder does not include this information
 * in the reply.
 */
const QString &DiscoInfoTask::node() const { return d->node; }

const DiscoItem &DiscoInfoTask::item() const { return d->item; }

void DiscoInfoTask::onGo()
{
    if (d->allowCache && client()->capsManager()->isEnabled()) {
        d->item = client()->capsManager()->disco(d->jid);
        if (!d->item.features().isEmpty() || d->item.identities().count()) {
            QTimer::singleShot(0, this, SLOT(cachedReady())); // to be consistent with network requests
            return;
        }
    }

    QDomElement iq    = createIQ(doc(), "get", d->jid.full(), id());
    QDomElement query = doc()->createElementNS("http://jabber.org/protocol/disco#info", "query");
    if (!d->node.isEmpty())
        query.setAttribute("node", d->node);

#if 0 // seems like disco#info get request was misinterpreted. xep-0030 says it has to be an EMPTY query.
    if ( !d->ident.category.isEmpty() && !d->ident.type.isEmpty() ) {
        QDomElement i = doc()->createElement("item");

        i.setAttribute("category", d->ident.category);
        i.setAttribute("type", d->ident.type);
        if ( !d->ident.name.isEmpty() )
            i.setAttribute("name", d->ident.name);

        query.appendChild( i );

    }
#endif
    iq.appendChild(query);
    send(iq);
}

void DiscoInfoTask::cachedReady()
{
    d->item.setJid(d->jid);
    setSuccess();
}

bool DiscoInfoTask::take(const QDomElement &x)
{
    if (!iqVerify(x, d->jid, id()))
        return false;

    if (x.attribute("type") == "result") {
        d->item = DiscoItem::fromDiscoInfoResult(queryTag(x));
        d->item.setJid(d->jid);
        if (d->allowCache && client()->capsManager()->isEnabled()) {
            client()->capsManager()->updateDisco(d->jid, d->item);
        }

        setSuccess();
    } else {
        setError(x);
    }

    return true;
}
