/*
 * 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 <gtk/gtk.h>
#include <cassert>
#include <map>
#include <string>

class TreeView
{
public:
    typedef enum
    {
        STRING,
        STRINGR,
        INT,
        BOOL,
        PIXBUF,
        PIXBUF_STRING,
        ICON_STRING,
        ICON_STRING_TEXT_COLOR,
        EDIT_STRING,
        PROGRESS,
        SPEED,
        SIZE,
        TIME_LEFT
    } columnType;

    TreeView();
    ~TreeView();
    void setView(GtkTreeView *view);
    void setView(GtkTreeView *view, bool padding, const std::string &name = "");
    GtkTreeView *get();
    void insertColumn(const std::string &title, const GType &gtype, const columnType type, const int width, const std::string &linkedCol = "");
    void insertColumn(const std::string &title, const GType &gtype, const columnType type, const int width,
                      const std::string &linkedCol, const std::string &linkedTextColor);
    void insertHiddenColumn(const std::string &title, const GType &gtype);
    void finalize();
    int getColCount() const;
    int getRowCount();
    GType* getGTypes();
    void setSortColumn_gui(const std::string &column, const std::string &sortColumn);
    int col(const std::string &title);
    void saveSettings();
    std::string getString(GtkTreeIter *i, const std::string &column, GtkTreeModel *m = NULL);
    template<class T>
    T getValue(GtkTreeIter *i, const std::string &column, GtkTreeModel *m = NULL)
    {
        if(!m)
            m = gtk_tree_view_get_model(view);
        T value;
        gtk_tree_model_get(m, i, col(column), &value, -1);
        return value;
    }
    template<class T, class C>
    C getValue(GtkTreeIter *i, const std::string &column, GtkTreeModel *m = NULL)
    {
        return static_cast<C>(getValue<T>(i, column, m));
    }

private:
    class Column
    {
    public:
        Column() {};
        Column(const std::string &title, int id, GType gtype, TreeView::columnType type, int width, const std::string &linkedCol = "") :
            title(title), id(id), gtype(gtype), type(type), width(width), pos(id), linkedCol(linkedCol), visible(true) {};
        Column(const std::string &title, int id, GType gtype, TreeView::columnType type, int width,
               const std::string &linkedCol, const std::string &linkedTextColor) :
            title(title),
            id(id),
            gtype(gtype),
            type(type),
            width(width),
            pos(id),
            linkedCol(linkedCol),
            linkedTextColor(linkedTextColor),
            visible(true) {};
        Column(const std::string &title, int id, GType gtype) :
            title(title), id(id), gtype(gtype), pos(id) {};

        bool operator<(const Column &right) const
        {
            return pos < right.pos;
        }

        std::string title;
        int id = 0;
        GType gtype;
        TreeView::columnType type = STRING;
        int width = 50;
        int pos = 0;
        std::string linkedCol;
        std::string linkedTextColor;
        bool visible = true;
    };

    void addColumn_gui(Column& column);
    void restoreSettings();
    static gboolean popupMenu_gui(GtkWidget *widget, GdkEventButton *event, gpointer data);
    static void toggleColumnVisibility(GtkMenuItem *item, gpointer data);
    static void speedDataFunc(GtkTreeViewColumn*, GtkCellRenderer*, GtkTreeModel*, GtkTreeIter*, gpointer);
    static void sizeDataFunc(GtkTreeViewColumn*, GtkCellRenderer*, GtkTreeModel*, GtkTreeIter*, gpointer);
    static void timeLeftDataFunc(GtkTreeViewColumn*, GtkCellRenderer*, GtkTreeModel*, GtkTreeIter*, gpointer);

    GtkTreeView *view;
    std::string name; // Used to save settings
    bool padding;
    int count;
    int visibleColumns;
    GtkMenu *menu;
    GType *gtypes;
    std::map<std::string, GtkWidget*> colMenuItems;

    typedef std::map<std::string, Column> ColMap;
    typedef std::map<int, std::string> SortedColMap;
    typedef ColMap::iterator ColIter;
    typedef SortedColMap::iterator SortedColIter;
    ColMap columns;
    SortedColMap sortedColumns;
    ColMap hiddenColumns;
    SortedColMap sortedHiddenColumns;
};
