/*
 * Copyright 2015 Luca Beltrame <lbeltrame@kde.org>
 *
 * This file is part of Danbooru Client.
 *
 * Danbooru Client 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.
 *
 * Danbooru Client 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 Danbooru Client. If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef DANBOORUSERVICE_H
#define DANBOORUSERVICE_H

/**
 * @brief Classes to interact with Danbooru boards
 * @file danbooruservice.h
 *
**/

// Qt

#include <QObject>
#include <QString>
#include <QStringList>
#include <QSet>

// KDE

#include <QUrl>
#include <kio/storedtransferjob.h>
#include <KImageCache>

// Own

#include "danbooru.h"
#include "danboorupost.h"
#include "danboorutag.h"

class QPixmap;
class QUrl;
class KJob;

using Danbooru::DanbooruTag;

namespace Danbooru
{

class DanbooruPool;

using KIO::StoredTransferJob;

/**
 * @brief A class which provides a wrapper around Danbooru's RESTful API.
 *
 * This class provides access to Danbooru-based image boards
 * by making the appropriate RESTful calls to the service and then
 * retrieving and parsing the reuslts.
 *
 * @author Luca Beltrame (lbeltrame@kde.org)
 *
 *
 **/
class DanbooruService : public QObject
{
    Q_OBJECT

private:

    // URL fragments

    static const QString POST_URL;
    static const QString TAG_URL;
    static const QString POOL_URL;
    static const QString ARTIST_URL;
    static const QString POOL_DATA_URL;
    static const QString RELATED_TAG_URL;

    // member variables

    QUrl m_url;
    QString m_username;
    QString m_password;
    QSet<QString> m_blacklist;
    DanbooruPost::Ratings m_maxRating;
    int m_maxPosts;
    int m_currentPage;
    QStringList m_tags;

    unsigned int m_postsToFetch; // To tell when to quit

    KImageCache *m_cache; // Pixmap cache

public:

    /**
     * @brief Construct a default instance of the service.
     *
     * @param boardUrl The URL to connect to.
     * @param username Username to use (optional)
     * @param password Password to use (optional)
     * @param cache A pointer to a KImageCache instance to enable caching
     *              of downloaded pixmaps.
     * @param parent The parent QObject
     *
     **/
    DanbooruService(QUrl boardUrl = QUrl(), QString username = QString(),
                    QString password = QString(), KImageCache *cache = 0,
                    QObject *parent = 0);

    /**
     * Default destructor.
     **/
    ~DanbooruService();

    int currentPage() const;

    /**
     * @brief Get posts from a the board.
     *
     * @param page The page containing posts (default: 1)
     * @param tags The specific tags to query for (default: all tags)
     * @param limit The number of posts to fetch (maximum 100)
     *
     **/
    Q_INVOKABLE void getPostList();

    /**
     * @brief Get a list of pools from the board.
     *
     **/
    void getPoolList();

    /**
     * @brief Get the posts associated with a specific pool ID.
     *
     * @param poolId The ID of the pool to fetch posts from.
     * @param page The page of the pool posts (if > 100)
     *
     **/
    void getPool(int poolId, int page = 1);

    /**
     * @brief Get a list of tags from the board
     *
     * If name is supplied, a list of tags including the exact name of the
     * tag is fetched from Danbooru, otherwise the most recent tags are
     * retrieved.
     *
     * The tagDownloaded signal is emitted every time a tag has been
     * retrieved.
     *
     * @param limit The number of tags to get.
     * @param name The name of the tag to retrieve, or an empty string
     *
     **/
    void getTagList(int limit = 10, QString name = "");

    /**
     * @brief Get tags related to a specific, user supplied list.
     *
     * @param tags The tags to query for related terms
     * @param tagType The type of tag to query for
     **/
    void getRelatedTags(const QStringList &tags, DanbooruTag::TagType tagType = DanbooruTag::General);

    /**
     * @return The currently allowed ratings when downloading posts.
     **/
    const QStringList allowedRatings() const;

    /**
     * @return The maximum allowed rating for a post.
     **/
    const DanbooruPost::Ratings maximumAllowedRating() const;

    /**
     * @return The currently blacklisted tags.
     **/
    const QSet<QString> blacklist() const;

    /**
     * @return The number of posts downloaded for each page (max 100)
     **/
    int maxPosts() const;

    /**
     * @brief Fetches the next page of posts.
     **/
    Q_INVOKABLE void nextPostPage();

    /**
     * @brief Fetches the next page of pools.
     **/
    Q_INVOKABLE void nextPoolPage();

    /**
     * @return A QStringList containing the currently-selected tags
     **/
    QStringList postTags() const;

    /**
     * @brief Resets the service to the default state, clearing the page counters.
     **/
    void reset();

    /**
     * @brief Set blacklisted tags.
     *
     * Posts with blacklisted tags are not downloaded.
     *
     * @param blacklist A QSet<QString> including unwanted tags.
     *
     **/
    void setBlacklist(const QStringList &blacklist);

    /**
    * @brief Set the tag blacklist.
    *
    * If a tag is in the blacklist, posts tagged with it will not be downloaded.
    *
    **/

    void setBlacklist(const QSet<QString> &blacklist);

    /**
     * @brief Set the maximum allowed rating for the board.
     *
     * Posts whose rating is higher than the maximuk allowed will not be
     * downloaded.
     *
     **/
    void setMaximumAllowedRating(DanbooruPost::Rating rating);

    /**
     * @brief Set the board URL to connect to.
     *
     * @param url The URL to connect to.
     * @return void
     */
    void setBoardUrl(const QUrl &url);

    /**
     * @brief Set an image cache to use.
     *
     * @param cache A pointer to an intsnaec of KImageCache.
     * @return void
     */
    void setImageCache(KImageCache *cache);

    /**
     * @brief Set username for login.
     *
     * @param username The username to use.
     *
     **/
    void setUserName(const QString &username);

    /**
     * @brief Set the password used for login.
     *
     * It should not be the password itself, but a SHA1 hash
     * with a specific salt (which is board-dependent; check their
     * API access rules).
     *
     * @param password The salted password to use.
     *
     **/
    void setPassword(const QString &password);

    void setMaxPosts(int number);

    void setCurrentPage(int page);

    void setPostTags(const QStringList &tags);

private Q_SLOTS:
    void processPostList(KJob *job);
    void processTagList(KJob *job);
    void downloadAllTags(KJob *job);

Q_SIGNALS:

    /**
     * Emitted when there are no more posts to download.
     *
     * Connect to this signal to know when downloading is complete.
     *
     **/
    void postDownloadFinished();

    /**
     * Emitted when there are no more pools to download.
     **/
    void poolDownloadFinished();

    /**
     * Emitted when a download error occurred.
     *
     * The parameter contains the error string.
     *
     **/
    void downloadError(QString error);

    /**
     * Emitted when a post has been downloaded.
     *
     * The parameter contains a pointer to the post that has been
     * downloaded.
     **/
    void postDownloaded(Danbooru::DanbooruPost *post);

    /**
     * Emitted when a pool has been downloaded.
     *
     * The parameter contains a pointer to the pool that has been
     * downloaded.
     **/
    void poolDownloaded(Danbooru::DanbooruPool *pool);

    /**
     * Emitted when a tag has been downloaded.
     *
     * The parameter contains a pointer to the tag that has been
     * downloaded.
     **/
    void tagDownloaded(Danbooru::DanbooruTag *tag);

};
}
#endif // DANBOORUSERVICE_H
