/*
    knewstuff3/provider.h
    This file is part of KNewStuff2.
    SPDX-FileCopyrightText: 2009 Jeremy Whiting <jpwhiting@kde.org>
    SPDX-FileCopyrightText: 2009 Frederik Gladhorn <gladhorn@kde.org>

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

#ifndef KNEWSTUFF3_PROVIDER_P_H
#define KNEWSTUFF3_PROVIDER_P_H

#include <QList>
#include <QString>
#include <QUrl>
#include <QDebug>

#include <memory>

#include "entryinternal.h"
#include "errorcode.h"

#include "knewstuffcore_export.h"

class KJob;

namespace KNSCore
{
struct Comment;
/**
 * @short KNewStuff Base Provider class.
 *
 * This class provides accessors for the provider object.
 * It should not be used directly by the application.
 * This class is the base class and will be instantiated for
 * static website providers.
 *
 * @author Jeremy Whiting <jpwhiting@kde.org>
 *
 * @internal
 */
class KNEWSTUFFCORE_EXPORT Provider: public QObject
{
    Q_OBJECT
public:
    typedef QList<Provider *> List;

    enum SortMode {
        Newest,
        Alphabetical,
        Rating,
        Downloads,
    };
    Q_ENUM(SortMode)

    enum Filter {
        None,
        Installed,
        Updates,
        ExactEntryId
    };
    Q_ENUM(Filter)

    /**
     * used to keep track of a search
     */
    struct SearchRequest {
        SortMode sortMode;
        Filter filter;
        QString searchTerm;
        QStringList categories;
        int page;
        int pageSize;

        SearchRequest(SortMode sortMode_ = Newest, Filter filter_ = None, const QString &searchTerm_ = QString(), const QStringList &categories_ = QStringList(), int page_ = -1, int pageSize_ = 20)
            : sortMode(sortMode_), filter(filter_), searchTerm(searchTerm_), categories(categories_), page(page_), pageSize(pageSize_)
        {}

        QString hashForRequest() const;
    };

    /**
     * Describes a category: id/name/disaplayName
     */
    struct CategoryMetadata {
        QString id;
        QString name;
        QString displayName;
    };

    /**
     * Constructor.
     */
    Provider();

    /**
     * Destructor.
     */
    virtual ~Provider();

    /**
     * A unique Id for this provider (the url in most cases)
     */
    virtual QString id() const = 0;

    /**
     * Set the provider data xml, to initialize the provider.
     * The Provider needs to have it's ID set in this function and cannot change it from there on.
     */
    virtual bool setProviderXML(const QDomElement &xmldata) = 0;

    virtual bool isInitialized() const = 0;

    virtual void setCachedEntries(const KNSCore::EntryInternal::List &cachedEntries) = 0;

    /**
     * Retrieves the common name of the provider.
     *
     * @return provider name
     */
    virtual QString name() const;

    /**
     * Retrieves the icon URL for this provider.
     *
     * @return icon URL
     */
    virtual QUrl icon() const; // FIXME use QIcon::fromTheme or pixmap?

    /**
     * load the given search and return given page
     * @param sortMode string to select the order in which the results are presented
     * @param searchstring string to search with
     * @param page         page number to load
     *
     * Note: the engine connects to loadingFinished() signal to get the result
     */
    virtual void loadEntries(const KNSCore::Provider::SearchRequest &request) = 0;
    virtual void loadEntryDetails(const KNSCore::EntryInternal &) {}
    virtual void loadPayloadLink(const EntryInternal &entry, int linkId) = 0;
    /**
     * Request a loading of comments from this provider. The engine listens to the
     * commentsLoaded() signal for the result
     *
     * @note Implementation detail: All subclasses should connect to this signal
     * and point it at a slot which does the actual work, if they support comments.
     *
     * TODO: KF6 This should be a virtual function, but can't do it now because BIC
     * @see commentsLoaded(const QList<shared_ptr<KNSCore::Comment>> comments)
     * @since 5.63
     */
    Q_SIGNAL void loadComments(const EntryInternal &entry, int commentsPerPage, int page);
    /**
     * Request loading of the details for a specific person with the given username.
     * The engine listens to the personLoaded() for the result
     *
     * @note Implementation detail: All subclasses should connect to this signal
     * and point it at a slot which does the actual work, if they support comments.
     *
     * TODO: KF6 This should be a virtual function, but can't do it now because BIC
     * @since 5.63
     */
    Q_SIGNAL void loadPerson(const QString &username);

    virtual bool userCanVote()
    {
        return false;
    }
    virtual void vote(const EntryInternal &entry, uint rating)
    {
        Q_UNUSED(entry) Q_UNUSED(rating)
    }

    virtual bool userCanBecomeFan()
    {
        return false;
    }
    virtual void becomeFan(const EntryInternal &entry)
    {
        Q_UNUSED(entry)
    }

    /**
     * Set the tag filter used for entries by this provider
     * @param tagFilter The new list of filters
     * @see Engine::setTagFilter(QStringList)
     * @since 5.51
     */
    void setTagFilter(const QStringList &tagFilter);
    /**
     * The tag filter used for downloads by this provider
     * @return The list of filters
     * @see Engine::setTagFilter(QStringList)
     * @since 5.51
     */
    QStringList tagFilter() const;
    /**
     * Set the tag filter used for download items by this provider
     * @param downloadTagFilter The new list of filters
     * @see Engine::setDownloadTagFilter(QStringList)
     * @since 5.51
     */
    void setDownloadTagFilter(const QStringList &downloadTagFilter);
    /**
     * The tag filter used for downloads by this provider
     * @return The list of filters
     * @see Engine::setDownloadTagFilter(QStringList)
     * @since 5.51
     */
    QStringList downloadTagFilter() const;

Q_SIGNALS:
    void providerInitialized(KNSCore::Provider *);

    void loadingFinished(const KNSCore::Provider::SearchRequest &, const KNSCore::EntryInternal::List &) const;
    void loadingFailed(const KNSCore::Provider::SearchRequest &);

    void entryDetailsLoaded(const KNSCore::EntryInternal &);
    void payloadLinkLoaded(const KNSCore::EntryInternal &);
    /**
     * Fired when new comments have been loaded
     * @param comments The list of newly loaded comments, in a depth-first order
     * @since 5.63
     */
    void commentsLoaded(const QList<std::shared_ptr<KNSCore::Comment>> comments);
    /**
     * Fired when the details of a person have been loaded
     * @param author The person we've just loaded data for
     * @since 5.63
     */
    void personLoaded(const std::shared_ptr<KNSCore::Author> author);

    void signalInformation(const QString &) const;
    void signalError(const QString &) const;
    void signalErrorCode(const KNSCore::ErrorCode &errorCode, const QString &message, const QVariant &metadata) const;

    void categoriesMetadataLoded(const QList<CategoryMetadata> &categories);

protected:
    QString mName;
    QUrl mIcon;

private:
    Q_DISABLE_COPY(Provider)
};

KNEWSTUFFCORE_EXPORT QDebug operator<<(QDebug, const Provider::SearchRequest &);
}

#endif
