/* Copyright (C) 2005-2006 Fabio Marzocca <thesaltydog@gmail.com>
 * Copyright (C) 2012-2021 MATE Developers
 *
 * This file is part of MATE Utils.
 *
 * MATE Utils 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.
 *
 * MATE Utils 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 MATE Utils.  If not, see <https://www.gnu.org/licenses/>.
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <gtk/gtk.h>
#include <glib.h>
#include <glib/gprintf.h>
#include <glib/gi18n.h>
#include <string.h>

#include "baobab.h"
#include "baobab-treeview.h"
#include "baobab-cell-renderer-progress.h"
#include "baobab-utils.h"
#include "callbacks.h"

#define GET_WIDGET(x) (GTK_WIDGET (gtk_builder_get_object (baobab.main_ui, (x))))

static GtkTreeStore *
create_model (void)
{
	GtkTreeStore *mdl = gtk_tree_store_new (NUM_TREE_COLUMNS,
						G_TYPE_STRING,	/* COL_DIR_NAME */
						G_TYPE_STRING,	/* COL_H_PARSENAME */
						G_TYPE_DOUBLE,	/* COL_H_PERC */
						G_TYPE_STRING,	/* COL_DIR_SIZE */
						G_TYPE_UINT64,	/* COL_H_SIZE */
						G_TYPE_UINT64,	/* COL_H_ALLOCSIZE */
						G_TYPE_STRING,	/* COL_ELEMENTS */
						G_TYPE_INT,	/* COL_H_ELEMENTS */
						G_TYPE_STRING,	/* COL_HARDLINK */
						G_TYPE_UINT64	/* COL_H_HARDLINK */
						);

	return mdl;
}

static void
on_tv_row_expanded (GtkTreeView *treeview,
		    GtkTreeIter *arg1,
		    GtkTreePath *arg2,
		    gpointer data)
{
	gtk_tree_view_columns_autosize (treeview);
}

static void
on_tv_cur_changed (GtkTreeView *treeview, gpointer data)
{
	GtkTreeIter iter;
	gchar *parsename = NULL;

	gtk_tree_selection_get_selected (gtk_tree_view_get_selection (treeview), NULL, &iter);

	if (gtk_tree_store_iter_is_valid (baobab.model, &iter)) {
		gtk_tree_model_get (GTK_TREE_MODEL (baobab.model), &iter,
				    COL_H_PARSENAME, &parsename, -1);
	}
}

static void
contents_changed (void)
{
	if (messageyesno (_("Rescan your home folder?"),
			  _("The content of your home folder has changed. Select rescan to update the disk usage details."),
			  GTK_MESSAGE_QUESTION, _("_Rescan"), baobab.window) == GTK_RESPONSE_OK) {
		baobab_rescan_current_dir ();
	}
	else {
		/* Just update the total */
		baobab_update_filesystem ();
	}
}

static gboolean
on_tv_button_press (GtkWidget *widget,
		    GdkEventButton *event,
		    gpointer data)
{
	GtkTreePath *path;
	GtkTreeIter iter;
	GFile *file;

	gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget),
	                               (gint) event->x, (gint) event->y,
	                               &path, NULL, NULL, NULL);
	if (!path)
		return TRUE;

	/* get the selected path */
	g_free (baobab.selected_path);
	gtk_tree_model_get_iter (GTK_TREE_MODEL (baobab.model), &iter,
				 path);
	gtk_tree_model_get (GTK_TREE_MODEL (baobab.model), &iter,
			    COL_H_PARSENAME, &baobab.selected_path, -1);

	file = g_file_parse_name (baobab.selected_path);

	if (baobab.CONTENTS_CHANGED_DELAYED) {
		GFile *home_file;

		home_file = g_file_new_for_path (g_get_home_dir ());
		if (g_file_has_prefix (file, home_file)) {
			baobab.CONTENTS_CHANGED_DELAYED = FALSE;
			if (baobab.STOP_SCANNING) {
				contents_changed ();
			}
		}
		g_object_unref (home_file);
	}

	/* right-click */
	if (event->button == 3) {

		if (g_file_query_exists (file, NULL)) {
		     popupmenu_list (path, event, can_trash_file (file));
		}
	}

	gtk_tree_path_free (path);
	g_object_unref (file);

	return FALSE;
}

static gboolean
baobab_treeview_equal_func (GtkTreeModel *model,
                            gint column,
                            const gchar *key,
                            GtkTreeIter *iter,
                            gpointer data)
{
	gboolean results = TRUE;
	gchar *name;

	gtk_tree_model_get (model, iter, 1, &name, -1);

	if (name != NULL) {
		gchar * casefold_key;
		gchar * casefold_name;

		casefold_key = g_utf8_casefold (key, -1);
		casefold_name = g_utf8_casefold (name, -1);

		if ((casefold_key != NULL) &&
		    (casefold_name != NULL) &&
		    (strstr (casefold_name, casefold_key) != NULL)) {
			results = FALSE;
		}
		g_free (casefold_key);
		g_free (casefold_name);
		g_free (name);
	}
	return results;
}

static void
perc_cell_data_func (GtkTreeViewColumn *col,
		     GtkCellRenderer *renderer,
		     GtkTreeModel *model,
		     GtkTreeIter *iter,
		     gpointer user_data)
{
	gdouble perc;
	gchar textperc[10];

	gtk_tree_model_get (model, iter, COL_H_PERC, &perc, -1);

 	if (perc < 0)
		strcpy (textperc, "-.- %");
	else if (perc == 100.0)
		strcpy (textperc, "100 %");
	else
 		g_sprintf (textperc, " %.1f %%", perc);

	g_object_set (renderer, "text", textperc, NULL);
}

GtkWidget *
create_directory_treeview (void)
{
	GtkCellRenderer *cell;
	GtkTreeViewColumn *col;

	GtkWidget *tvw = GET_WIDGET ("treeview1");

	g_signal_connect (tvw, "row-expanded",
			  G_CALLBACK (on_tv_row_expanded), NULL);
	g_signal_connect (tvw, "cursor-changed",
			  G_CALLBACK (on_tv_cur_changed), NULL);
	g_signal_connect (tvw, "button-press-event",
			  G_CALLBACK (on_tv_button_press), NULL);

	/* dir name column */
	g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (tvw)), "changed",
			  G_CALLBACK (on_tv_selection_changed), NULL);
	cell = gtk_cell_renderer_text_new ();
	col = gtk_tree_view_column_new_with_attributes (NULL, cell, "markup",
							COL_DIR_NAME, "text",
							COL_DIR_NAME, NULL);
	gtk_tree_view_column_set_sort_column_id (col, COL_DIR_NAME);
	gtk_tree_view_column_set_reorderable (col, TRUE);
	gtk_tree_view_column_set_title (col, _("Folder"));
	gtk_tree_view_column_set_sizing (col, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
	gtk_tree_view_column_set_resizable (col, TRUE);
	gtk_tree_view_append_column (GTK_TREE_VIEW (tvw), col);

	/* percentage bar & text column */
	col = gtk_tree_view_column_new ();

	cell = baobab_cell_renderer_progress_new ();
	gtk_tree_view_column_pack_start (col, cell, FALSE);
	gtk_tree_view_column_set_attributes (col, cell, "perc",
	                                     COL_H_PERC, NULL);

	cell = gtk_cell_renderer_text_new ();
	gtk_tree_view_column_pack_start (col, cell, TRUE);
	gtk_tree_view_column_set_cell_data_func (col, cell,
						 perc_cell_data_func,
						 NULL, NULL);

	g_object_set (G_OBJECT (cell), "xalign", (gfloat) 1.0, NULL);
	gtk_tree_view_column_set_sort_column_id (col, COL_H_PERC);
	gtk_tree_view_column_set_reorderable (col, TRUE);
	gtk_tree_view_column_set_title (col, _("Usage"));
	gtk_tree_view_column_set_sizing (col, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
	gtk_tree_view_column_set_resizable (col, FALSE);
	gtk_tree_view_append_column (GTK_TREE_VIEW (tvw), col);

	/* directory size column */
	cell = gtk_cell_renderer_text_new ();
	col = gtk_tree_view_column_new_with_attributes (NULL, cell, "markup",
							COL_DIR_SIZE, "text",
							COL_DIR_SIZE, NULL);
	g_object_set (G_OBJECT (cell), "xalign", (gfloat) 1.0, NULL);
	gtk_tree_view_column_set_sort_column_id (col,
						 baobab.show_allocated ? COL_H_ALLOCSIZE : COL_H_SIZE);
	gtk_tree_view_column_set_reorderable (col, TRUE);
	gtk_tree_view_column_set_title (col, _("Size"));
	gtk_tree_view_column_set_sizing (col, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
	gtk_tree_view_column_set_resizable (col, TRUE);
	gtk_tree_view_append_column (GTK_TREE_VIEW (tvw), col);

	/* store this column, we need it when toggling 'allocated' */
	g_object_set_data (G_OBJECT (tvw), "baobab_size_col", col);

	/* objects column */
	cell = gtk_cell_renderer_text_new ();
	col = gtk_tree_view_column_new_with_attributes (NULL, cell, "markup",
							COL_ELEMENTS, "text",
							COL_ELEMENTS, NULL);
	g_object_set (G_OBJECT (cell), "xalign", (gfloat) 1.0, NULL);
	gtk_tree_view_column_set_sort_column_id (col, COL_H_ELEMENTS);
	gtk_tree_view_column_set_reorderable (col, TRUE);
	gtk_tree_view_column_set_title (col, _("Contents"));
	gtk_tree_view_column_set_sizing (col, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
	gtk_tree_view_column_set_resizable (col, TRUE);
	gtk_tree_view_append_column (GTK_TREE_VIEW (tvw), col);

	/* hardlink column */
	cell = gtk_cell_renderer_text_new ();
	col = gtk_tree_view_column_new_with_attributes (NULL, cell, "markup",
							COL_HARDLINK, "text",
						 	COL_HARDLINK, NULL);
	gtk_tree_view_append_column (GTK_TREE_VIEW (tvw), col);

	gtk_tree_view_collapse_all (GTK_TREE_VIEW (tvw));
	gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (tvw), FALSE);
	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (GET_WIDGET ("scrolledwindow1")),
					GTK_POLICY_AUTOMATIC,
					GTK_POLICY_AUTOMATIC);

	gtk_tree_view_set_search_equal_func (GTK_TREE_VIEW (tvw),
	                                     baobab_treeview_equal_func,
	                                     NULL, NULL);

	baobab.model = create_model ();

	/* By default, sort by size */
	gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (baobab.model),
					      baobab.show_allocated ? COL_H_ALLOCSIZE : COL_H_SIZE,
					      GTK_SORT_DESCENDING);

	gtk_tree_view_set_model (GTK_TREE_VIEW (tvw),
				 GTK_TREE_MODEL (baobab.model));
	g_object_unref (baobab.model);

	return tvw;
}

void
baobab_treeview_show_allocated_size (GtkWidget *tv,
				     gboolean show_allocated)
{
	gint sort_id;
	gint new_sort_id;
	GtkSortType order;
	GtkTreeViewColumn *size_col;

	g_return_if_fail (GTK_IS_TREE_VIEW (tv));

	gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (baobab.model),
					      &sort_id, &order);

	/* set the sort id for the size column */
	size_col = g_object_get_data (G_OBJECT (tv), "baobab_size_col");
	new_sort_id = show_allocated ? COL_H_ALLOCSIZE : COL_H_SIZE;
	gtk_tree_view_column_set_sort_column_id (size_col, new_sort_id);

	/* if we are currently sorted on size or allocated size,
	 * then trigger a resort (with the same order) */
	if (sort_id == COL_H_SIZE || sort_id == COL_H_ALLOCSIZE) {
		gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (baobab.model),
						      new_sort_id, order);
	}
}
