/**
 * gui_callbacks.c - GUI callback code for SciteProj
 *
 *  Copyright 2006 Roy Wood, 2009-2020 Andreas Rönnquist
 *
 * This file is part of SciteProj.
 *
 * SciteProj 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.
 *
 * SciteProj 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 SciteProj.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#include <string.h>
#include <sys/stat.h>
#include <glib.h>
#include <gtk/gtk.h>

#include <gdk/gdkkeysyms.h>

#include <stdlib.h>
#include <glib/gi18n.h>

#include <locale.h>

#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>

#include "gui_callbacks.h"
#include "clicked_node.h"

#include "gui.h"
#include "tree_manipulation.h"
#include "scite_utils.h"
#include "string_utils.h"
#include "prefs.h"
#include "statusbar.h"
#include "graphics.h"
#include "about.h"
#include "properties_dialog.h"
#include "file_utils.h"

#include "recent_files.h"
#include "remove.h"
#include "sort.h"

#include "load_folder.h"

#include "script.h"


/**
 * Open the selected file.
 *	This is called when a file is rightclicked and open is selected in the menu
 */
void popup_open_file_cb()
{
	gchar *command = NULL;
	GError *err = NULL;
	GtkWidget *dialog = NULL;
	gchar *absFilePath = NULL;

	// several files in selection?

	// We can only open files

	if (!clicked_node.valid || clicked_node.type != ITEMTYPE_FILE) {
		goto EXITPOINT;
	}

	if (!open_filename(clicked_node.name, (gchar*)(get_project_directory()), &err)) {
		goto EXITPOINT;
	}

	add_file_to_recent(clicked_node.name, NULL);


EXITPOINT:

	if (err != NULL) {
		dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR,
		                                GTK_BUTTONS_OK,
		                                _("Could not open selected file: \n\n%s"),
		                                err->message);

		gtk_dialog_run(GTK_DIALOG (dialog));
	}

	if (command) g_free(command);
	if (absFilePath) g_free(absFilePath);
	if (err) g_error_free(err);
	if (dialog) gtk_widget_destroy(dialog);
}



/**
 *	Open the LUA rc file for the project folder
 */
void edit_properties_cb()
{
	GError *err = NULL;
	gchar *command = NULL;

	if ((command = g_strdup_printf("open:%s\n", prefs_filename)) == NULL) {
		g_set_error(&err, APP_SCITEPROJ_ERROR, -1,
		            "%s: %s, g_strdup_printf() = NULL",
		            "Error formatting SciTE command",
		            __func__);
	}
	else {
		if (send_scite_command(command, &err)) {
			// Try to activate SciTE; ignore errors

			activate_scite(NULL);

			if (prefs.give_scite_focus == TRUE) {
				send_scite_command((gchar*)"focus:0", NULL);
			}
		}
	}
}


/**
 * step-through function for expand/collapse folder
 *
 * @param tree_view
 * @param newiter
 * @param tree_path
 */
static void fix_folders_step_through(GtkTreeView *tree_view, GtkTreeIter newiter, GtkTreePath *tree_path)
{
	GtkTreeModel *tree_model = gtk_tree_view_get_model(tree_view);

	gchar *relFilePath;

	GError *error;
	gint nodeItemType;

	GtkTreeIter iter = newiter;

	do {

		gtk_tree_model_get(tree_model, &iter, COLUMN_ITEMTYPE, &nodeItemType, -1);


		if (nodeItemType == ITEMTYPE_GROUP) {

			GtkTreePath *srcPath = gtk_tree_model_get_path(tree_model, &iter);
			gboolean groupIsExpanded = tree_row_is_expanded(srcPath);

			if (groupIsExpanded) {
				set_tree_node_icon(&iter, directory_open_pixbuf, &error);
			} else {
				set_tree_node_icon(&iter, directory_closed_pixbuf, &error);
			}

			set_tree_node_expanded(&iter, groupIsExpanded, NULL);

			gtk_tree_model_get(tree_model, &iter, COLUMN_FILEPATH, &relFilePath, -1);

			if (gtk_tree_model_iter_has_child(tree_model, &iter)) {

				GtkTreeIter newIter;
				gtk_tree_model_iter_children(tree_model, &newIter, &iter);
				fix_folders_step_through(tree_view, newIter, tree_path);
			}

			g_free(relFilePath);
			gtk_tree_path_free(srcPath);

		} else {

		}


	} while(gtk_tree_model_iter_next(tree_model,&iter));
}


gchar *remove_trailing_dot_folder(gchar *infolder)
{
	gchar *result = NULL;

	if (g_str_has_suffix(infolder, "/.") == TRUE) {

		int len = strlen(infolder);


		result = g_strdup(infolder);

		result[len - 2] = '\0';

	} else {
		result = g_strdup(infolder);
	}

	return result;
}

/**
 *
 */
void load_tree_at_iter(GtkTreeView *tree_view, GtkTreeIter *iter)
{
	// We've got the folder - get the child
	GtkTreeIter child;

	GtkTreeModel *tree_model = gtk_tree_view_get_model(tree_view);
	gchar *temp = NULL;

	if (iter) {

		if (gtk_tree_model_iter_children(tree_model, &child, iter)) {
			remove_tree_node(&child, NULL);

			gchar *temp_folder_path;

			gtk_tree_model_get(tree_model, iter, COLUMN_FILEPATH, &temp_folder_path, -1);

			gchar *folder_path = g_path_get_dirname(temp_folder_path);

			temp = folder_path;
			folder_path = remove_trailing_dot_folder(temp);
			g_free(temp);

			// Load the wanted filter from the LUA config
			GSList *filter_list = load_filter_from_lua(folder_path);

			GSList *global_filter_list = prefs.hide_filter_global;

			GSList *iterator;

			for (iterator = global_filter_list; iterator; iterator = iterator->next) {

				temp = (gchar*)(iterator->data);

				gchar *temp_base = g_path_get_basename(temp);

				filter_list = g_slist_append(filter_list , (gpointer)(temp_base));
			}

			GSList *final_filter_list = filter_list;

			GSList *file_list; //=load_folder_to_list(folder_path, FALSE,
			GSList *folder_list;

			// default sorting here compare_strings_bigger - since we turn the
			// list backwards after

			GCompareFunc comparer = get_sort_order_of_folder(temp_folder_path);

			file_list = load_folder_to_list(temp_folder_path,
													  FALSE,
													  comparer /*file_sort_by_extension_bigger_func*/,
													  final_filter_list);

			folder_list = load_folder_to_list(temp_folder_path, TRUE, compare_strings_bigger, final_filter_list);

			// Here we should filter out the unwanted items

			add_tree_folderlist(iter, folder_list, temp_folder_path);

			if (file_list) {
				//file_list = g_slist_reverse(file_list);

				add_tree_filelist(iter, file_list, NULL);
			}

			set_tree_node_expanded(iter, TRUE, NULL);

			GtkTreePath *tree_path = gtk_tree_model_get_path(tree_model, iter);

			gtk_tree_view_expand_row(tree_view, tree_path, FALSE);

			gtk_tree_path_free(tree_path);

			g_slist_foreach(filter_list, (GFunc)g_free, NULL);
			g_slist_free(filter_list);

		}
	}
}


/**
 * Callback for expand/collapse event of GtkTreeView
 *
 * @param treeView is not used
 * @param arg1 is not used
 * @param arg2 is not used
 * @param user_data is not used
 */
void row_expand_or_collapse_cb(GtkTreeView *tree_view, GtkTreeIter *iter,
                               GtkTreePath *tree_path, gpointer user_data)
{
	/* Switch the folder icon open/closed*/

	GtkTreeModel *tree_model = gtk_tree_view_get_model(tree_view);

	// make sure all icons the folder (and folders inside it) are set to a correct icon.
	fix_folders_step_through(tree_view, *iter,tree_path);

	gchar *temp;
	gboolean expanded;
	gboolean loaded;

	gtk_tree_model_get(tree_model, iter, COLUMN_FILEPATH, &temp, -1);
	gtk_tree_model_get(tree_model, iter, COLUMN_EXPANDED, &expanded, -1);
	gtk_tree_model_get(tree_model, iter, COLUMN_FOLDER_CONTENT_LOADED, &loaded, -1);

	//printf("%s : %d\n", temp, (int)expanded);

	if (!loaded) {
		set_tree_node_loaded(iter, TRUE, NULL);

		load_tree_at_iter(tree_view, iter);


	}
}



/**
 * Callback for "Quit" menu item
 */
void quit_menu_cb()
{
	gtk_main_quit();
}


/**
 * Callback for "About" menu item
 */
void about_menu_cb()
{
	show_about_dialog();
}



/**
 *
 */
gboolean key_press_cb(GtkWidget *widget, GdkEventKey *event, gpointer userData)
{
	switch (event->keyval)
	{
	case GDK_KEY_BackSpace:
	{
		debug_printf((gchar*)"key_press_cb: keyval = %d = GDK_BackSpace, hardware_keycode = %d\n",
		             event->keyval, event->hardware_keycode);
		break;
	}

	case GDK_KEY_Delete:
	{
		do_remove_node(TRUE);
		break;
	}
	case GDK_KEY_Insert:
	{
		break;
	}
	/*
	case GDK_KEY_F2:
	{
		do_rename_node(TRUE);
		return TRUE;
	}
	*/
	default:
	{
		debug_printf("key_press_cb: keyval = %d = '%c', hardware_keycode = %d\n",
		             event->keyval, (char) event->keyval, event->hardware_keycode);
		return FALSE;
	}
	}

	if (event->state & GDK_SHIFT_MASK) debug_printf(", GDK_SHIFT_MASK");
	if (event->state & GDK_CONTROL_MASK) debug_printf(", GDK_CONTROL_MASK");
	if (event->state & GDK_MOD1_MASK) debug_printf(", GDK_MOD1_MASK");
	if (event->state & GDK_MOD2_MASK) debug_printf(", GDK_MOD2_MASK");
	if (event->state & GDK_MOD3_MASK) debug_printf(", GDK_MOD3_MASK");
	if (event->state & GDK_MOD4_MASK) debug_printf(", GDK_MOD4_MASK");
	if (event->state & GDK_MOD5_MASK) debug_printf(", GDK_MOD5_MASK");

	debug_printf("\n");

	return FALSE;
}


/**
 *		search function for the gtk_tree_view_set_search_equal_func
 *		@return TRUE when rows DONT match, FALSE when rows match
 */
gboolean tree_view_search_equal_func(GtkTreeModel *model, gint column,
												 const gchar *key, GtkTreeIter *iter,
												 gpointer search_data)
{
	gchar *filename;
	// For some reason this should return TRUE if the row DONT match
	gboolean res = TRUE;

	gtk_tree_model_get(model, iter, COLUMN_FILENAME, &filename, -1);

	// zero when matches, which means we should return FALSE
	if (g_ascii_strncasecmp(key, filename, strlen(key)) == 0) res = FALSE;

	g_free(filename);

	return res;
}


/**
 *
 */
void refresh_folder_cb()
{
	if (!clicked_node.valid || clicked_node.type != ITEMTYPE_GROUP) {
		return;
	}

	gchar *folder_name;
	GtkTreeModel *tree_model = gtk_tree_view_get_model(GTK_TREE_VIEW(projectTreeView));
	GtkTreeIter iter = clicked_node.iter;

	GtkTreeIter *stored_iter = gtk_tree_iter_copy(&iter);

	gboolean expanded;

	gtk_tree_model_get(tree_model, &iter, COLUMN_FILENAME, &folder_name,
							 COLUMN_EXPANDED, &expanded,
							 -1);

	// If the folder is expanded
	if (expanded) {

		// add all rows below to a list of GtkTreePath


		GtkTreeIter child;

		GList *list_of_items = NULL;

		// First, store all GtkTreePath in a linked list

		if (gtk_tree_model_iter_children(tree_model, &child, &iter)) {
			GtkTreePath *tree_path;

			GtkTreeIter *temp_iter = &child;
			do {

				gchar *temp;
				gtk_tree_model_get(tree_model, temp_iter, COLUMN_FILENAME, &temp, -1);

				tree_path = gtk_tree_model_get_path(tree_model, temp_iter);
				GtkTreeRowReference *row_reference = gtk_tree_row_reference_new(tree_model, tree_path);

				list_of_items = g_list_append(list_of_items, row_reference);

				gtk_tree_path_free(tree_path);

			} while(gtk_tree_model_iter_next(tree_model, temp_iter));

			// go through the list of row-references

			GList *node;
			for (node = list_of_items; node != NULL; node = node -> next) {
				tree_path = gtk_tree_row_reference_get_path((GtkTreeRowReference*)node->data);

				if (tree_path) {
					if (gtk_tree_model_get_iter(tree_model, &iter, tree_path))
						remove_tree_node(&iter, NULL);
				}
			}

			g_list_foreach(list_of_items, (GFunc)gtk_tree_row_reference_free, NULL);
		}

		GtkTreeIter *temp_iter = gtk_tree_iter_copy(stored_iter);

		gchar *folder;
		gtk_tree_model_get(tree_model, temp_iter,
		                   COLUMN_FILEPATH, &folder,
		                   -1);

		GtkTreeIter new_iter;
		if (get_number_of_files_in_folder(folder) > 0) {
			add_tree_file(temp_iter, ADD_CHILD, "<loading...>", &new_iter, FALSE, NULL);
		}

		load_tree_at_iter(GTK_TREE_VIEW(projectTreeView), temp_iter);
		//set_tree_node_loaded(temp_iter, TRUE, NULL);

		// get the default sort order

		//sort_children(stored_iter, NULL, compare_strings_smaller);

	} else {
	}

}

