/*
 * Copyright © 2004-2010 Jens Oknelid, paskharen@gmail.com
 *
 * 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 2 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 <https://www.gnu.org/licenses/>.
 *
 * In addition, as a special exception, compiling, linking, and/or
 * using OpenSSL with this program is allowed.
 */

#pragma once

#include <dcpp/stdinc.h>
#include <dcpp/DirectoryListing.h>
#include <dcpp/QueueManager.h>
#include "bookentry.hh"
#include "treeview.hh"

class UserCommandMenu;

class ShareBrowser:
        public BookEntry
{
public:
    ShareBrowser(dcpp::UserPtr _user, const std::string &_file, const std::string &_initialDirectory, const bool _full);
    virtual ~ShareBrowser();
    virtual void show();
    void loadXML(std::string txt);

    ShareBrowser(const ShareBrowser&) = delete;
    ShareBrowser& operator=(const ShareBrowser&) = delete;

private:
    // GUI functions
    bool buildList_gui();
    void openDir_gui(const std::string &dir);
    bool findDir_gui(const std::string &dir, GtkTreeIter *parent);
    void buildDirs_gui(dcpp::DirectoryListing::Directory *dir, GtkTreeIter *iter);
    void updateFiles_gui(dcpp::DirectoryListing::Directory *dir);
    void updateStatus_gui();
    void setStatus_gui(std::string statusBar, std::string msg);
    void fileViewSelected_gui();
    void downloadSelectedFiles_gui(const std::string &target);
    void downloadSelectedDirs_gui(const std::string &target);
    void popupFileMenu_gui();
    void popupDirMenu_gui();
    void find_gui();
    void load(std::string xml);
    void viewPartial_gui();
    bool isFull();

    // GUI callbacks
    static gboolean onButtonPressed_gui(GtkWidget *widget, GdkEventButton *event, gpointer data);
    static gboolean onFileButtonReleased_gui(GtkWidget *widget, GdkEventButton *event, gpointer data);
    static gboolean onFileKeyReleased_gui(GtkWidget *widget, GdkEventKey *event, gpointer data);
    static gboolean onDirButtonReleased_gui(GtkWidget *widget, GdkEventButton *event, gpointer data);
    static gboolean onDirKeyReleased_gui(GtkWidget *widget, GdkEventKey *event, gpointer data);
    static void onMatchButtonClicked_gui(GtkWidget *widget, gpointer data);
    static void onFindButtonClicked_gui(GtkWidget *widget, gpointer);
    static void onNextButtonClicked_gui(GtkWidget *widget, gpointer);
    static void onDownloadClicked_gui(GtkMenuItem *item, gpointer data);
    static void onDownloadToClicked_gui(GtkMenuItem *item, gpointer data);
    static void onDownloadFavoriteClicked_gui(GtkMenuItem *item, gpointer data);
    static void onDownloadDirClicked_gui(GtkMenuItem *item, gpointer data);
    static void onDownloadDirToClicked_gui(GtkMenuItem *item, gpointer data);
    static void onDownloadFavoriteDirClicked_gui(GtkMenuItem *item, gpointer data);
    static void onSearchAlternatesClicked_gui(GtkMenuItem *item, gpointer data);
    static void onCopyMagnetClicked_gui(GtkMenuItem* item, gpointer data);
    static void onCopyPictureClicked_gui(GtkMenuItem* item, gpointer data);
    static void onDirGet(GtkMenuItem* item, gpointer data);
    // Client functions
    void downloadFile_client(dcpp::DirectoryListing::File *file, std::string target);
    void downloadDir_client(dcpp::DirectoryListing::Directory *dir, std::string target);
    void matchQueue_client();
    void downloadChangedDir(dcpp::DirectoryListing::Directory* d);

    // Thread-related functions
    static gpointer threadLoad_list(gpointer data);

    GdkEventType oldType;
    dcpp::UserPtr user;
    std::string file;
    std::string initialDirectory;
    std::string nick;
    dcpp::DirectoryListing listing;
    int64_t shareSize;
    int64_t currentSize;
    int shareItems;
    int currentItems;
    std::string search;
    bool updateFileView;
    int skipHits;
    bool full;
    TreeView dirView, fileView;
    GtkListStore *fileStore;
    GtkTreeStore *dirStore;
    GtkTreeSelection *fileSelection, *dirSelection;
    UserCommandMenu *fileUserCommandMenu;
    UserCommandMenu *dirUserCommandMenu;

    enum {
        COLUMN_FILENAME,
        COLUMN_TYPE,
        COLUMN_SIZE,
        COLUMN_EXACTSIZE,
        COLUMN_TTH,
        COLUMN_LAST
    };

    class ItemInfo : public dcpp::FastAlloc<ItemInfo> {
    public:
        enum ItemType {
            FILE,
            DIRECTORY,
            USER
        } type;

        union {
            dcpp::DirectoryListing::File* file;
            dcpp::DirectoryListing::Directory* dir;
        };

        ItemInfo(const std::string& nick, dcpp::DirectoryListing::Directory* d) : type(USER), dir(d) {
            columns.insert(ParamMap::value_type("FILENAME",nick));
        }

        ItemInfo(dcpp::DirectoryListing::File* f) : type(FILE), file(f) {
            columns.insert(ParamMap::value_type("FILENAME",f->getName()));
            //columns["COLUMN_FILENAME"] = dcpp::Text::toT(f->getName());
            columns.insert(ParamMap::value_type("TYPE",dcpp::Util::getFileExt(columns["FILENAME"])));
            //columns["COLUMN_TYPE"] = dcpp::Util::getFileExt(columns["COLUMN_FILENAME"]);
            //if(!columns["COLUMN_TYPE"].empty() && columns["COLUMN_TYPE"][0] == '.')
            //      columns["COLUMN_TYPE"].erase(0, 1);

            columns["EXACTSIZE"] = dcpp::Text::toT(dcpp::Util::formatExactSize(f->getSize()));
            columns["SIZE"] = dcpp::Text::toT(dcpp::Util::formatBytes(f->getSize()));
            columns["TTH"] = dcpp::Text::toT(f->getTTH().toBase32());
        }
        ItemInfo(dcpp::DirectoryListing::Directory* d) : type(DIRECTORY), dir(d) {
            columns.insert(ParamMap::value_type("FILENAME",d->getName()));
            columns.insert(ParamMap::value_type("EXACTSIZE",d->getComplete() ? dcpp::Util::formatExactSize(d->getTotalSize()) : _("?")));
            //columns["COLUMN_FILENAME"] = dcpp::Text::toT(d->getName());
            //columns["COLUMN_EXACTSIZE"] = d->getComplete() ? dcpp::Text::toT(dcpp::Util::formatExactSize(d->getTotalSize())) : _("?");
            columns.insert(ParamMap::value_type("SIZE",d->getComplete() ? dcpp::Util::formatBytes(d->getTotalSize()) : _("?")));
            //columns["COLUMN_SIZE"] = d->getComplete() ? dcpp::Text::toT(dcpp::Util::formatBytes(d->getTotalSize())) : _("?");
        }

        //const char *getText() const {
        //      return columns["COLUMN_FILENAME"].c_str();
        //}

        int getImage()  const {return 0;};

        int getSelectedImage() const {
            return getImage();
        }

        /*const std::string& getText(int col) const {
                        return columns[col];
                }*/

        struct TotalSize {
            TotalSize() : total(0) { }
            void operator()(ItemInfo* a) { total += a->type == DIRECTORY ? a->dir->getTotalSize() : a->file->getSize(); }
            int64_t total;
        };

        static int compareItems(ItemInfo* a, ItemInfo* b, int col);
    private:
        //std::string columns[COLUMN_LAST];
        typedef std::map<std::string, std::string> ParamMap;
        ParamMap columns;
    };
};
