/*
    SPDX-FileCopyrightText: 2005 Joris Guisson <joris.guisson@gmail.com>

    SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef BTBENCODER_H
#define BTBENCODER_H

#include <ktorrent_export.h>
#include <util/file.h>

class QIODevice;

namespace bt
{
class File;

/*!
 * \headerfile bcodec/bencoder.h
 * \author Joris Guisson
 *
 * \brief Interface for classes which wish to receive the output from a BEncoder.
 */
class KTORRENT_EXPORT BEncoderOutput
{
public:
    virtual ~BEncoderOutput()
    {
    }
    /*!
     * Write a string of characters.
     * \param str The string
     */
    virtual void write(QByteArrayView str) = 0;
};

/*!
 * \headerfile bcodec/bencoder.h
 * \brief Writes the output of a BEncoder to a file.
 */
class KTORRENT_EXPORT BEncoderFileOutput : public BEncoderOutput
{
    File *fptr;

public:
    BEncoderFileOutput(File *fptr);

    void write(QByteArrayView str) override;
};

/*!
 * \headerfile bcodec/bencoder.h
 * \brief Writes the output of a BEncoder to a QByteArray.
 *
 * The encoder will write to the beginning of the array, and any pre-existing contents will be overwritten.
 */
class KTORRENT_EXPORT BEncoderBufferOutput : public BEncoderOutput
{
    QByteArray &data;

public:
    BEncoderBufferOutput(QByteArray &data);

    void write(QByteArrayView str) override;
};

/*!
 * \headerfile bcodec/bencoder.h
 * \brief Writes the output of a BEncoder to a QIODevice.
 */
class KTORRENT_EXPORT BEncoderIODeviceOutput : public BEncoderOutput
{
    QIODevice *dev;

public:
    BEncoderIODeviceOutput(QIODevice *dev);

    void write(QByteArrayView str) override;
};

/*!
 * \headerfile bcodec/bencoder.h
 * \author Joris Guisson
 * \brief Bencodes data.
 *
 * For more details about b-encoding, see the BitTorrent protocol docs.
 * The data gets written to a BEncoderOutput.
 */
class KTORRENT_EXPORT BEncoder
{
    std::unique_ptr<BEncoderOutput> out;

public:
    /*!
     * Constructor, output gets written to a file.
     * \param fptr The File to write to
     */
    BEncoder(File *fptr);

    /*!
     * Constructor, output gets written to a BEncoderOutput object.
     * \param out The BEncoderOutput
     */
    BEncoder(std::unique_ptr<BEncoderOutput> out);

    /*!
     * Constructor, output gets written to a QIODevice object.
     * \param dev The QIODevice
     */
    BEncoder(QIODevice *dev);

    virtual ~BEncoder();

    /*!
     * Begin a dictionary.Should have a corresponding end call.
     */
    void beginDict();

    /*!
     * Begin a list. Should have a corresponding end call.
     */
    void beginList();

    template<class T>
    void write(QByteArrayView key, T val)
    {
        write(key);
        write(val);
    }

    /*!
     * Write a boolean (is encoded as an intà
     * \param val
     */
    void write(bool val);

    /*!
     * Write a float
     * \param val
     */
    void write(float val);

    /*!
     * Write an int
     * \param val
     */
    void write(Uint32 val);

    /*!
     * Write an int64
     * \param val
     */
    void write(Uint64 val);

    /*!
     * Write a string
     * \param data
     */
    void write(QByteArrayView data);

    /*!
     * \internal
     * Write a string. This function exists because QByteArray is implicitly convertible to both bool and QByteArrayView.
     * \param data
     */
    void write(const QByteArray &data)
    {
        write(QByteArrayView{data});
    }

    /*!
     * \internal
     * Write a string. This function exists because char * is implicitly convertible to bool.
     * \param data
     */
    void write(const char *data)
    {
        write(QByteArrayView{data});
    }

    /*!
     * End a beginDict or beginList call.
     */
    void end();
};

}

#endif
