// SPDX-FileCopyrightText: 2010 Jeremy Lainé <jeremy.laine@m4x.org>
//
// SPDX-License-Identifier: LGPL-2.1-or-later

#include "QXmppByteStreamIq.h"

#include "QXmppConstants_p.h"
#include "QXmppUtils_p.h"

#include "StringLiterals.h"
#include "XmlWriter.h"

#include <QDomElement>

using namespace QXmpp::Private;

template<>
struct Enums::Data<QXmppByteStreamIq::Mode> {
    static constexpr auto NullValue = QXmppByteStreamIq::None;
    static constexpr auto Values = makeValues<QXmppByteStreamIq::Mode>({
        { QXmppByteStreamIq::None, {} },
        { QXmppByteStreamIq::Tcp, u"tcp" },
        { QXmppByteStreamIq::Udp, u"udp" },
    });
};

/*!
    \enum QXmppByteStreamIq::Mode

    Used to select the transport layer protocol (TCP or UDP).

    \value None No transport protocol selected.
    \value Tcp TCP transport.
    \value Udp UDP transport.
*/

/*!
    \class QXmppByteStreamIq::StreamHost
    \inmodule QXmpp

    StreamHost represents information about a specific SOCKS5 bytestreams host.
*/

/*! Returns the host address of the stream host. */
QString QXmppByteStreamIq::StreamHost::host() const
{
    return m_host;
}

/*! Sets the \a host address of the stream host. */
void QXmppByteStreamIq::StreamHost::setHost(const QString &host)
{
    m_host = host;
}

/*! Returns the JID of the stream host. */
QString QXmppByteStreamIq::StreamHost::jid() const
{
    return m_jid;
}

/*!
    Sets the JID of the stream host.

    \a jid.
*/
void QXmppByteStreamIq::StreamHost::setJid(const QString &jid)
{
    m_jid = jid;
}

/*! Returns the port of the stream host. */
quint16 QXmppByteStreamIq::StreamHost::port() const
{
    return m_port;
}

/*! Sets the \a port of the stream host. */
void QXmppByteStreamIq::StreamHost::setPort(quint16 port)
{
    m_port = port;
}

/*! Returns the zero-configuration service available for bytestreaming. */
QString QXmppByteStreamIq::StreamHost::zeroconf() const
{
    return m_zeroconf;
}

/*!
    Sets the zero-configuration service available for bytestreaming.

    \a zeroconf.
*/
void QXmppByteStreamIq::StreamHost::setZeroconf(const QString &zeroconf)
{
    m_zeroconf = zeroconf;
}

std::optional<QXmppByteStreamIq::StreamHost> QXmppByteStreamIq::StreamHost::fromDom(const QDomElement &el)
{
    StreamHost streamHost;
    streamHost.setHost(el.attribute(u"host"_s));
    streamHost.setJid(el.attribute(u"jid"_s));
    streamHost.setPort(parseInt<quint16>(el.attribute(u"port"_s)).value_or(0));
    streamHost.setZeroconf(el.attribute(u"zeroconf"_s));
    return streamHost;
}

void QXmppByteStreamIq::StreamHost::toXml(QXmlStreamWriter *writer) const
{
    XmlWriter(writer).write(Element {
        XmlTag,
        OptionalAttribute { u"host", m_host },
        OptionalAttribute { u"jid", m_jid },
        Attribute { u"port", m_port },
        OptionalAttribute { u"zeroconf", m_zeroconf },
    });
}

/*!
    \class QXmppByteStreamIq
    \inmodule QXmpp

    QXmppByteStreamIq represents a SOCKS5 bytestreams negoatiation IQ as defined
    by \xep{0065}{SOCKS5 Bytestreams}.
*/

/*! Returns the protocol type (UDP or TCP). */
QXmppByteStreamIq::Mode QXmppByteStreamIq::mode() const
{
    return m_mode;
}

/*!
    Sets the protocol type (UDP or TCP).

    \a mode.
*/
void QXmppByteStreamIq::setMode(QXmppByteStreamIq::Mode mode)
{
    m_mode = mode;
}

/*! Returns the bytestream stream ID. */
QString QXmppByteStreamIq::sid() const
{
    return m_sid;
}

/*!
    Sets the bytestream stream ID.

    \a sid.
*/
void QXmppByteStreamIq::setSid(const QString &sid)
{
    m_sid = sid;
}

/*! Returns the jid of the target. */
QString QXmppByteStreamIq::activate() const
{
    return m_activate;
}

/*!
    Sets the jid of the target.

    \a activate.
*/
void QXmppByteStreamIq::setActivate(const QString &activate)
{
    m_activate = activate;
}

/*! Returns available SOCKS5 stream hosts. */
QList<QXmppByteStreamIq::StreamHost> QXmppByteStreamIq::streamHosts() const
{
    return m_streamHosts;
}

/*!
    Sets available SOCKS5 stream hosts.

    \a streamHosts.
*/
void QXmppByteStreamIq::setStreamHosts(const QList<QXmppByteStreamIq::StreamHost> &streamHosts)
{
    m_streamHosts = streamHosts;
}

/*! Returns the JID of the used stream host. */
QString QXmppByteStreamIq::streamHostUsed() const
{
    return m_streamHostUsed;
}

/*!
    Sets the JID of the used stream host.

    \a jid.
*/
void QXmppByteStreamIq::setStreamHostUsed(const QString &jid)
{
    m_streamHostUsed = jid;
}

void QXmppByteStreamIq::parseElementFromChild(const QDomElement &element)
{
    auto queryElement = firstChildElement(element, u"query", ns_bytestreams);
    m_sid = queryElement.attribute(u"sid"_s);
    const auto modeStr = queryElement.attribute(u"mode"_s);
    if (modeStr == u"tcp") {
        m_mode = Tcp;
    } else if (modeStr == u"udp") {
        m_mode = Udp;
    } else {
        m_mode = None;
    }

    m_streamHosts = parseChildElements<QList<StreamHost>>(queryElement);
    m_activate = firstChildElement(queryElement, u"activate").text();
    m_streamHostUsed = firstChildElement(queryElement, u"streamhost-used").attribute(u"jid"_s);
}

void QXmppByteStreamIq::toXmlElementFromChild(QXmlStreamWriter *writer) const
{
    XmlWriter(writer).write(Element {
        { u"query", ns_bytestreams },
        OptionalAttribute { u"sid", m_sid },
        OptionalAttribute { u"mode", m_mode == Tcp ? u"tcp"_s : m_mode == Udp ? u"udp"_s
                                                                              : QString() },
        m_streamHosts,
        OptionalTextElement { u"activate", m_activate },
        SingleAttributeElements { u"streamhost-used", u"jid", QList<QString> { m_streamHostUsed } },
    });
}
