/******************************************************************************
**
** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtKnx module.
**
** $QT_BEGIN_LICENSE:GPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 or (at your option) any later version
** approved by the KDE Free Qt Foundation. The licenses are as published by
** the Free Software Foundation and appearing in the file LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
******************************************************************************/

#include "qknxnetiptunnelingfeatureinfo.h"
#include "qknxbuilderdata_p.h"

QT_BEGIN_NAMESPACE

/*!
    \class QKnxNetIpTunnelingFeatureInfoProxy

    \since 5.12
    \inmodule QtKnx
    \ingroup qtknx-netip
    \ingroup qtknx-tunneling

    \brief The QKnxNetIpTunnelingFeatureInfoProxy class provides the means to
    access the information carried by a generic tunneling feature-info service
    \l QKnxNetIpFrame frame and to create a KNXnet/IP frame based on the
    information.

    A tunneling feature-info service frame contains the ID of the communication
    channel between a KNXnet/IP client and server, the sequence number of the
    frame, the \l {QKnx::InterfaceFeature} {interface feature} that changed,
    and the feature value as a byte array.

    The tunneling server only sends the tunneling feature-info service frame
    if the interface feature \e {interface feature info service enable} has
    the value \c enable set. If enabled, the tunneling server initiates the
    tunneling feature-info service to report on any relevant change of an
    interface feature to the tunneling client.

    The tunneling server by default reports for all its supported interface
    features. There is no standard way for the tunneling client to disable the
    reporting of an individual interface feature. This may be possible through
    the normal configuration of the tunneling server device by a management
    client (MaC), e.g. over KNXnet/IP device management.

    The tunneling server addresses the tunneling feature-info service frame
    to the data endpoint of the established tunneling connection.

    \note When using QKnxNetIpTunnelingFeatureInfoProxy, care must be taken to
    ensure that the referenced KNXnet/IP frame outlives the proxy on all code
    paths, lest the proxy ends up referencing deleted data.

    The following code sample illustrates how to read the tunneling
    feature-info service information sent by a KNXnet/IP server:

    \code
        auto netIpFrame = QKnxNetIpFrame::fromBytes(...);

        const QKnxNetIpTunnelingFeatureInfoProxy proxy(netIpFrame);
        if (!proxy.isValid())
            return;

        auto id = proxy.featureIdentifier();
        auto value = proxy.featureValue();
    \endcode

    \sa builder(), QKnxNetIpTunnelingFeatureGetProxy,
    QKnxNetIpTunnelingFeatureSetProxy,
    {Qt KNX Tunneling Classes}, {Qt KNXnet/IP Connection Classes}
*/

/*!
    \fn QKnxNetIpTunnelingFeatureInfoProxy::QKnxNetIpTunnelingFeatureInfoProxy()
    \internal
*/

/*!
    \fn QKnxNetIpTunnelingFeatureInfoProxy::~QKnxNetIpTunnelingFeatureInfoProxy()
    \internal
*/

/*!
    \fn QKnxNetIpTunnelingFeatureInfoProxy::QKnxNetIpTunnelingFeatureInfoProxy(const QKnxNetIpFrame &&)
    \internal
*/

/*!
    Constructs a proxy object to read the tunneling feature-info service
    information carried by the specified KNXnet/IP frame \a frame.
*/
QKnxNetIpTunnelingFeatureInfoProxy::QKnxNetIpTunnelingFeatureInfoProxy(const QKnxNetIpFrame &frame)
    : m_frame(frame)
{}

/*!
    Returns \c true if the frame contains initialized values and is in itself
    valid, otherwise returns \c false. A valid KNXnet/IP frame consists of
    at least a valid header and a size in bytes corresponding to the total size
    of the KNXnet/IP frame header.

    \sa QKnxNetIpFrameHeader::totalSize()
*/
bool QKnxNetIpTunnelingFeatureInfoProxy::isValid() const
{
    return m_frame.isValid() && m_frame.size() >= 13 && QKnx::isInterfaceFeature(featureIdentifier())
        && m_frame.serviceType() == QKnxNetIp::ServiceType::TunnelingFeatureInfo;
}

/*!
    Returns the ID of the communication channel between a KNXnet/IP client and
    server.
*/
quint8 QKnxNetIpTunnelingFeatureInfoProxy::channelId() const
{
    return m_frame.channelId();
}

/*!
    Returns the sequence number of a tunneling feature-info service frame.
*/
quint8 QKnxNetIpTunnelingFeatureInfoProxy::sequenceNumber() const
{
    return m_frame.sequenceNumber();
}

/*!
    Returns the tunneling interface feature identifier of a tunneling
    feature-info frame.
*/
QKnx::InterfaceFeature QKnxNetIpTunnelingFeatureInfoProxy::featureIdentifier() const
{
    return QKnx::InterfaceFeature(m_frame.constData().value(0));
}

/*!
    Returns the tunneling interface feature value of a tunneling feature-info
    service frame.
*/
QKnxByteArray QKnxNetIpTunnelingFeatureInfoProxy::featureValue() const
{
    return m_frame.constData().mid(2);
}

/*!
    Returns a builder object to create a KNXnet/IP tunneling feature-info
    service frame.
*/
QKnxNetIpTunnelingFeatureInfoProxy::Builder QKnxNetIpTunnelingFeatureInfoProxy::builder()
{
    return QKnxNetIpTunnelingFeatureInfoProxy::Builder();
}


/*!
    \class QKnxNetIpTunnelingFeatureInfoProxy::Builder

    \inmodule QtKnx
    \inheaderfile QKnxNetIpTunnelingFeatureInfoProxy

    \brief The QKnxNetIpTunnelingFeatureInfoProxy::Builder class provides
    the means to create a KNXnet/IP tunneling feature-info service frame.

    A tunneling feature-info service frame contains the ID of the communication
    channel between a KNXnet/IP client and server, the sequence number of the
    frame, the \l {QKnx::InterfaceFeature} {interface feature} that changed,
    and the feature value as a byte array.

    The tunneling server only sends the tunneling feature-info service frame
    if the interface feature \e {interface feature info service enable} has
    the value \c enable set. If enabled, the tunneling server initiates the
    tunneling feature-info service to report on any relevant change of an
    interface feature to the tunneling client.

    The tunneling server by default reports for all its supported interface
    features. There is no standard way for the tunneling client to disable the
    reporting of an individual interface feature. This may be possible through
    the normal configuration of the tunneling server device by a management
    client (MaC), e.g. over KNXnet/IP device management.

    The tunneling server addresses the tunneling feature-info service frame
    to the data endpoint of the established tunneling connection.

    The common way to create a tunneling feature-info service frame is:
    \code
        auto frame = QKnxNetIpTunnelingFeatureInfoProxy::builder()
            .setChannelId(15)
            .setSequenceNumber(10)
            .setFeatureIdentifier(QKnx::InterfaceFeature::IndividualAddress)
            .setFeatureValue(QKnxAddress::Individual::Unregistered.bytes())
            .create();
    \endcode
*/

/*!
    Creates a new empty tunneling feature-info service frame builder object.
*/
QKnxNetIpTunnelingFeatureInfoProxy::Builder::Builder()
    : d_ptr(new QKnxFeatureBuilderPrivate)
{}

/*!
    Destroys the object and frees any allocated resources.
*/
QKnxNetIpTunnelingFeatureInfoProxy::Builder::~Builder() = default;

/*!
    Sets the ID of the communication channel between a KNXnet/IP client and
    server to \a channelId and returns a reference to the builder.
*/
QKnxNetIpTunnelingFeatureInfoProxy::Builder &
    QKnxNetIpTunnelingFeatureInfoProxy::Builder::setChannelId(quint8 channelId)
{
    d_ptr->m_channelId = channelId;
    return *this;
}

/*!
    Sets the sequence number of a tunneling feature-info service frame to
    \a sequenceNumber and returns a reference to the builder.
*/
QKnxNetIpTunnelingFeatureInfoProxy::Builder &
    QKnxNetIpTunnelingFeatureInfoProxy::Builder::setSequenceNumber(quint8 sequenceNumber)
{
    d_ptr->m_sequenceNumber = sequenceNumber;
    return *this;
}

/*!
    Sets the interface feature identifier of a tunneling feature-info service
    frame to \a id and returns a reference to the builder.

    Does nothing if \a id is not a \l QKnx::InterfaceFeature.
*/
QKnxNetIpTunnelingFeatureInfoProxy::Builder &
    QKnxNetIpTunnelingFeatureInfoProxy::Builder::setFeatureIdentifier(QKnx::InterfaceFeature id)
{
    if (QKnx::isInterfaceFeature(id))
        d_ptr->m_if = id;
    return *this;
}

/*!
    Sets the feature value of a tunneling feature-info service frame to
    \a value and returns a reference to the builder.
*/
QKnxNetIpTunnelingFeatureInfoProxy::Builder &
    QKnxNetIpTunnelingFeatureInfoProxy::Builder::setFeatureValue(const QKnxByteArray &value)
{
    d_ptr->m_featureValue = value;
    return *this;
}

/*!
    Creates and returns a KNXnet/IP tunneling feature-info service frame.

    \note The returned frame may be invalid depending on the values used during
    setup.

    \sa isValid()
*/
QKnxNetIpFrame QKnxNetIpTunnelingFeatureInfoProxy::Builder::create() const
{
    return { QKnxNetIp::ServiceType::TunnelingFeatureInfo,
        { d_ptr->m_channelId, d_ptr->m_sequenceNumber }, /* connection header */
        QKnxByteArray { quint8(d_ptr->m_if) , 0x00 } /* interface feature identifier */
        + d_ptr->m_featureValue
    };
}

/*!
    Constructs a copy of \a other.
*/
QKnxNetIpTunnelingFeatureInfoProxy::Builder::Builder(const Builder &other)
    : d_ptr(other.d_ptr)
{}

/*!
    Assigns the specified \a other to this object.
*/
QKnxNetIpTunnelingFeatureInfoProxy::Builder &
    QKnxNetIpTunnelingFeatureInfoProxy::Builder::operator=(const Builder &other)
{
    d_ptr = other.d_ptr;
    return *this;
}

QT_END_NAMESPACE
