// SPDX-FileCopyrightText: 2019 Jeremy Lainé <jeremy.laine@m4x.org>
// SPDX-FileCopyrightText: 2019 Linus Jahn <lnj@kaidan.im>
//
// SPDX-License-Identifier: LGPL-2.1-or-later

#ifndef QXMPPPUBSUBBASEITEM_H
#define QXMPPPUBSUBBASEITEM_H

#include "QXmppGlobal.h"

#include <QDomElement>
#include <QMetaType>
#include <QSharedDataPointer>

class QXmlStreamWriter;
class QXmppPubSubBaseItemPrivate;

class QXMPP_EXPORT QXmppPubSubBaseItem
{
public:
    QXmppPubSubBaseItem(const QString &id = {}, const QString &publisher = {});
    QXmppPubSubBaseItem(const QXmppPubSubBaseItem &) noexcept;
    QXmppPubSubBaseItem(QXmppPubSubBaseItem &&) noexcept;
    virtual ~QXmppPubSubBaseItem() noexcept;

    QXmppPubSubBaseItem &operator=(const QXmppPubSubBaseItem &) noexcept;
    QXmppPubSubBaseItem &operator=(QXmppPubSubBaseItem &&) noexcept;

    QString id() const;
    void setId(const QString &id);

    QString publisher() const;
    void setPublisher(const QString &publisher);

    void parse(const QDomElement &element);
    void toXml(QXmlStreamWriter *writer) const;

    static bool isItem(const QDomElement &element);

protected:
    virtual void parsePayload(const QDomElement &payloadElement);
    virtual void serializePayload(QXmlStreamWriter *writer) const;

    template<typename PayloadChecker>
    static bool isItem(const QDomElement &element, PayloadChecker isPayloadValid);

private:
    QSharedDataPointer<QXmppPubSubBaseItemPrivate> d;
};

/*!
    Returns true, if \a element is a valid PubSub item and (if existant) the
    payload is correct.

    \a element is the element to be checked to be an &lt;item/&gt; element.
    \a isPayloadValid is a function that validates the payload element (first
    child element). The functions needs to return true, if the payload is valid.
    In case there is no payload, the function is not called.

    Here is an example covering how this could be used to check for the
    \xep{0118}{User Tune} payload:
    \code
    auto isPayloadValid = [](const QDomElement &payload) -> bool {
    return payload.tagName() == "tune" && payload.namespaceURI() == ns_tune;
    };

    bool valid = QXmppPubSubItem::isItem(itemElement, isPayloadValid);
    \endcode
*/
template<typename PayloadChecker>
bool QXmppPubSubBaseItem::isItem(const QDomElement &element, PayloadChecker isPayloadValid)
{
    if (!isItem(element)) {
        return false;
    }

    const QDomElement payload = element.firstChildElement();

    // we can only check the payload if it's existant
    if (!payload.isNull()) {
        return isPayloadValid(payload);
    }
    return true;
}

Q_DECLARE_METATYPE(QXmppPubSubBaseItem)

#endif  // QXMPPPUBSUBBASEITEM_H
