/*
 * Squawk messenger. 
 * Copyright (C) 2019  Yury Gubich <blue@macaw.me>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once

#include <QObject>
#include <QString>
#include <QStandardPaths>
#include <QImage>
#include <QPainter>
#include <QBuffer>

#include <list>

#include <QXmppVCardIq.h>
#include <QXmppPresence.h>

#include "shared/enums.h"
#include "shared/message.h"
#include "shared/vcard.h"
#include "components/archive.h"
#include "adapterfunctions.h"

namespace Core {

/**
 * @todo write docs
 */
class RosterItem : public QObject
{
    Q_OBJECT
public:
    enum ArchiveState {
        empty,              //have no messages stored for this contact
        chunk,              //have some chunk of history, don't have the beginning nor have the end
        beginning,          //have the history from the very beginning, don't have the end
        end,                //have the history to the end, but don't have the beginning
        complete            //have full history locally stored
    };
    
    RosterItem(const QString& pJid, const QString& account, QObject* parent = 0);
    ~RosterItem();
    
    ArchiveState getArchiveState() const;
    QString getName() const;
    void setName(const QString& n);
    QString getServer() const;
    bool isMuc() const;
    Shared::EncryptionProtocol encryption() const;
    void setEncryption(Shared::EncryptionProtocol value);
    
    void addMessageToArchive(const Shared::Message& msg);
    void correctMessageInArchive(const QString& originalId, const Shared::Message& msg);
    void appendMessageToArchive(const Shared::Message& msg);
    void flushMessagesToArchive(bool finished, const QString& firstId, const QString& lastId);
    void requestHistory(int count, const QString& before);
    QString avatarPath(const QString& resource = "") const;
    QString folderPath() const;
    bool readAvatarInfo(Archive::AvatarInfo& target, const QString& resource = "") const;
    virtual bool setAutoGeneratedAvatar(const QString& resource = "");
    virtual void handleResponseVCard(const QXmppVCardIq& card, const QString& resource, Shared::VCard& out);
    virtual void handlePresence(const QXmppPresence& pres) = 0;
    
    bool changeMessage(const QString& id, const QMap<QString, QVariant>& data);
    void clearArchiveRequests();
    void downgradeDatabaseState();
    virtual QMap<QString, QVariant> getInfo() const;
    
    Shared::Message getMessage(const QString& id);
    
signals:
    void nameChanged(const QString& name) const;
    void subscriptionStateChanged(Shared::SubscriptionState state) const;
    void historyResponse(const std::list<Shared::Message>& messages, bool last) const;
    void needHistory(const QString& before, const QString& after, const QDateTime& afterTime = QDateTime()) const;
    void avatarChanged(Shared::Avatar, const QString& path) const;
    void requestVCard(const QString& jid) const;
    void encryptionChanged(Shared::EncryptionProtocol value) const;
    
public:
    const QString jid;
    const QString account;
    
protected:
    virtual bool setAvatar(const QByteArray& data, Archive::AvatarInfo& info, const QString& resource = "");
    virtual bool setAutoGeneratedAvatar(Archive::AvatarInfo& info, const QString& resource = "");
    void careAboutAvatar(
        bool hasAvatar,
        const Archive::AvatarInfo& info,
        QMap<QString, QVariant>& output,
        const QString& resource = "",
        const QString& subject = ""
    ) const;
    
protected:
    QString name;
    ArchiveState archiveState;
    Archive* archive;

    bool syncronizing;
    int requestedCount;
    QString requestedBefore;
    std::list<Shared::Message> hisoryCache;
    std::list<Shared::Message> appendCache;
    std::list<Shared::Message> responseCache;
    std::list<std::pair<int, QString>> requestCache;
    std::map<QString, Shared::Message> toCorrect;
    bool muc;
    
private:
    void nextRequest();
    void performRequest(int count, const QString& before);
    QString getId(const Shared::Message& msg);
};

}