/*
 * filetransfer.h - File Transfer
 * Copyright (C) 2004  Justin Karneges
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library.  If not, see <https://www.gnu.org/licenses/>.
 *
 */

#ifndef XMPP_FILETRANSFER_H
#define XMPP_FILETRANSFER_H

#include "xmpp/jid/jid.h"
#include "xmpp_task.h"
#include "xmpp_thumbs.h"

namespace XMPP {
class BSConnection;
class BytestreamManager;
class Client;
class FileTransferManager;
struct FTRequest;
class Thumbnail;

/*class AbstractFileTransfer
{
    public:
        // Receive
        virtual Jid peer() const = 0;
        virtual QString fileName() const = 0;
        virtual qlonglong fileSize() const = 0;
        virtual QString description() const { return ""; }
        virtual bool rangeSupported() const { return false; }
        virtual void accept(qlonglong offset=0, qlonglong length=0) = 0;
};*/

class FileTransfer : public QObject /*, public AbstractFileTransfer */
{
    Q_OBJECT
public:
    enum { ErrReject, ErrNeg, ErrConnect, ErrProxy, ErrStream, Err400 };
    enum { Idle, Requesting, Connecting, WaitingForAccept, Active };
    ~FileTransfer();

    FileTransfer *copy() const;

    void setProxy(const Jid &proxy);

    // send
    void      sendFile(const Jid &to, const QString &fname, qlonglong size, const QString &desc, Thumbnail &thumb);
    qlonglong offset() const;
    qlonglong length() const;
    int       dataSizeNeeded() const;
    void      writeFileData(const QByteArray &a);
    const Thumbnail &thumbnail() const;

    // receive
    Jid       peer() const;
    QString   fileName() const;
    qlonglong fileSize() const;
    QString   description() const;
    bool      rangeSupported() const;
    void      accept(qlonglong offset = 0, qlonglong length = 0);

    // both
    void          close();              // reject, or stop sending/receiving
    BSConnection *bsConnection() const; // active link

signals:
    void accepted(); // indicates BSConnection has started
    void connected();
    void readyRead(const QByteArray &a);
    void bytesWritten(qint64);
    void error(int);

private slots:
    void ft_finished();
    void stream_connected();
    void stream_connectionClosed();
    void stream_readyRead();
    void stream_bytesWritten(qint64);
    void stream_error(int);
    void doAccept();
    void reset();

private:
    class Private;
    Private *d;

    friend class FileTransferManager;
    FileTransfer(FileTransferManager *, QObject *parent = nullptr);
    FileTransfer(const FileTransfer &other);
    void man_waitForAccept(const FTRequest &req, const QString &streamType);
    void takeConnection(BSConnection *c);
};

class FileTransferManager : public QObject {
    Q_OBJECT
public:
    FileTransferManager(Client *);
    ~FileTransferManager();

    bool isActive(const FileTransfer *ft) const;
    void setDisabled(const QString &ns, bool state = true);

    Client *      client() const;
    FileTransfer *createTransfer();
    FileTransfer *takeIncoming();

signals:
    void incomingReady();

private slots:
    void pft_incoming(const FTRequest &req);

private:
    class Private;
    Private *d;

    friend class Client;
    void stream_incomingReady(BSConnection *);

    friend class FileTransfer;
    BytestreamManager *streamManager(const QString &ns) const;
    QStringList        streamPriority() const;
    QString            link(FileTransfer *);
    void               con_accept(FileTransfer *);
    void               con_reject(FileTransfer *);
    void               unlink(FileTransfer *);
};

class JT_FT : public Task {
    Q_OBJECT
public:
    JT_FT(Task *parent);
    ~JT_FT();

    void      request(const Jid &to, const QString &id, const QString &fname, qlonglong size, const QString &desc,
                      const QStringList &streamTypes, Thumbnail &thumb);
    qlonglong rangeOffset() const;
    qlonglong rangeLength() const;
    QString   streamType() const;

    void onGo();
    bool take(const QDomElement &);

private:
    class Private;
    Private *d;
};

struct FTRequest {
    Jid         from;
    QString     iq_id, id;
    QString     fname;
    qlonglong   size;
    QString     desc;
    bool        rangeSupported;
    QStringList streamTypes;
    Thumbnail   thumbnail;
};
class JT_PushFT : public Task {
    Q_OBJECT
public:
    JT_PushFT(Task *parent);
    ~JT_PushFT();

    void respondSuccess(const Jid &to, const QString &id, qlonglong rangeOffset, qlonglong rangeLength,
                        const QString &streamType);
    void respondError(const Jid &to, const QString &id, Stanza::Error::ErrorCond cond, const QString &str);

    bool take(const QDomElement &);

signals:
    void incoming(const FTRequest &req);
};
} // namespace XMPP

#endif // XMPP_FILETRANSFER_H
