/*
  This file is part of libkldap.
  SPDX-FileCopyrightText: 2004-2006 Szombathelyi György <gyurco@freemail.hu>

  SPDX-License-Identifier: LGPL-2.0-or-later
*/

#pragma once

#include <QByteArray>

#include "kldap_core_export.h"
#include <memory>
// clazy:excludeall=copyable-polymorphic

namespace KLDAPCore
{
/*!
 * \class KLDAPCore::Ber
 * \inmodule LdapCore
 * \inheaderfile KLDAPCore/Ber
 *
 * This class allows encoding and decoding Qt structures using Basic
 * Encoding Rules.
 */
class KLDAP_CORE_EXPORT Ber
{
public:
    /*!
     * Constructs a Ber object.
     */
    Ber();
    /*!
     * Constructs a Ber object from the given value.
     * \param value the QByteArray value to initialize from
     */
    explicit Ber(const QByteArray &value);
    /*!
     * Destroys the Ber object.
     */
    ~Ber();

    Ber(const Ber &that);

    /*!
     * Assigns the given Ber object to this object.
     * \param that the Ber object to assign
     * \return a reference to this object
     */
    Ber &operator=(const Ber &that);

    /*!
     * Returns the Ber object as a flat QByteArray.
     * \return the encoded QByteArray
     */
    [[nodiscard]] QByteArray flatten() const;

    /*!
     * Appends the data with the specified format to the Ber object.
     * This function works like printf, except that it's appending the
     * parameters, not replacing them. The allowed format characters and
     * the expected parameter types are:
     * <ul>
     *   <li>
     *     b  Boolean.  An int parameter should be supplied.
     *     A boolean element is output.
     *   </li>
     *   <li>
     *     e  Enumeration.  An int parameter should be supplied.
     *     An  enumeration  element is output.
     *   </li>
     *   <li>
     *     i  Integer.   An int parameter should be supplied.
     *     An integer element is output.
     *   </li>
     *   <li>
     *     B  Bitstring.  A pointer to a QByteArray which contains the
     *     bitstring is supplied, followed by the number of bits in the
     *     bitstring.  A bitstring element is output.
     *   </li>
     *   <li>
     *     n  Null.  No parameter is required. A null element is output.
     *   </li>
     *   <li>
     *     O,o,s  Octet  string.  A QByteArray * is supplied.
     *     An octet string element is output.
     *         Due to versatility of Qt's QByteArray, these three format
     *         strings are all accepts the same parameter, but using the 's'
     *         format the string will be encoded only to the first zero
     *         character (a null terminated string)!
     *   </li>
     *   <li>
     *     t  Tag.  An int specifying the tag to give the next element
     *     is provided. This works across calls.
     *   </li>
     *   <li>
     *     v,V  Several octet strings. A QList<QByteArray>* is supplied.
     *     Note that a construct like ’{v}’ is required to get an actual
     *     SEQUENCE OF octet strings. Also note that the 'v' format recognizes
     *     the QByteArray only to the first zero character, so it's not
     *     appropriate for binary data, just only for null terminated strings!
     *   </li>
     *   <li>
     *     {  Begin sequence. No parameter is required.
     *   </li>
     *   <li>
     *     }  End sequence.  No parameter is required.
     *   </li>
     *   <li>
     *     [  Begin set.  No parameter is required.
     *   </li>
     *   <li>
     *     ]  End set.  No parameter is required.
     *   </li>
     * </ul>
     * \param format the format string
     * \return the number of bytes appended
     */
    int printf(QString format, ...); // Passing by-value since it's used by va_start

    /*!
     * Scans from the Ber object according to the given format string.
     * \param format the format string
     * \return the number of bytes scanned
     */
    int scanf(QString format, ...);

    /*!
     * Peeks at the next tag without removing it.
     * \param size the size of the tag (output parameter)
     * \return the tag value
     */
    unsigned int peekTag(int &size);

    /*!
     * Skips the next tag.
     * \param size the size of the tag (output parameter)
     * \return the tag value
     */
    unsigned int skipTag(int &size);

private:
    class BerPrivate;
    std::unique_ptr<BerPrivate> const d;
};
}
