/* vim: colorcolumn=80 ts=4 sw=4
 */
/*
 * fileselection.c
 *
 * Copyright © 2002 Sun Microsystems, Inc.
 * Copyright © 2021-2023 Logan Rathbone
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 *
 * Original Author: Glynn Foster <glynn.foster@sun.com>
 */

#include "util.h"
#include "zenity.h"

#include <string.h>

#include <config.h>

/* TODO: port to GtkFileDialog.
 */
G_GNUC_BEGIN_IGNORE_DEPRECATIONS

static ZenityData *zen_data;

static void zenity_fileselection_dialog_response (GtkWidget *widget, int response, gpointer data);

void
zenity_fileselection (ZenityData *data, ZenityFileData *file_data)
{
	GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_OPEN;
	GtkFileChooserNative *dialog;

	zen_data = data;

	if (file_data->directory) {
		action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
	}
	else if (file_data->save) {
		action = GTK_FILE_CHOOSER_ACTION_SAVE;
	}

	dialog = gtk_file_chooser_native_new (data->dialog_title,
		NULL,	/* parent */
		action,
		_("_OK"),
		_("_Cancel"));

	if (data->modal)
		gtk_native_dialog_set_modal (GTK_NATIVE_DIALOG(dialog), TRUE);

	if (data->extra_label)
		g_warning ("Cannot add extra labels to GtkFileChooserNative");

	g_signal_connect (dialog, "response", G_CALLBACK(zenity_fileselection_dialog_response), file_data);

	if (file_data->uri)
	{
		if (g_path_is_absolute (file_data->uri) == TRUE)
		{
			g_autofree char *dir = g_path_get_dirname (file_data->uri);
			g_autoptr(GFile) dir_gfile = g_file_new_for_path (dir);

			gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER(dialog),
					dir_gfile,
					NULL);	/* GError */
		}

		if (file_data->uri[strlen (file_data->uri) - 1] != '/')
		{
			if (file_data->save)
			{
				g_autofree char *basename = g_path_get_basename (file_data->uri);

				gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog),
						basename);
			}
			else
			{
				g_autoptr(GFile) file = g_file_new_for_uri (file_data->uri);

				gtk_file_chooser_set_file (GTK_FILE_CHOOSER(dialog),
						file,
						NULL);	/* GError */
			}
		}
	}

	if (file_data->multi)
		gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER(dialog), TRUE);

	if (file_data->filter)
	{
		/* Filter format: Executables | *.exe *.bat *.com */
		for (int filter_i = 0; file_data->filter[filter_i]; filter_i++)
		{
			GtkFileFilter *filter = gtk_file_filter_new ();
			char *filter_str = file_data->filter[filter_i];
			GStrv pattern;
			g_auto(GStrv) patterns = NULL;
			g_autofree char *name = NULL;
			int i;

			/* Set name */
			for (i = 0; filter_str[i] != '\0'; i++)
				if (filter_str[i] == '|')
					break;

			if (filter_str[i] == '|') {
				name = g_strndup (filter_str, i);
				g_strstrip (name);
			}

			if (name) {
				gtk_file_filter_set_name (filter, name);

				/* Point i to the right position for split */
				for (++i; filter_str[i] == ' '; i++)
					;
			} else {
				gtk_file_filter_set_name (filter, filter_str);
				i = 0;
			}

			/* Get patterns */
			patterns = g_strsplit_set (filter_str + i, " ", -1);

			for (pattern = patterns; *pattern; pattern++)
				gtk_file_filter_add_pattern (filter, *pattern);

			gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(dialog), filter);
		}
	}
	gtk_native_dialog_show (GTK_NATIVE_DIALOG (dialog));

	if (data->timeout_delay > 0) {
		g_timeout_add_seconds (data->timeout_delay,
			(GSourceFunc) zenity_util_timeout_handle,
			dialog);
	}

	/* Since a native dialog is not a GtkWindow, we can't use our handy
	 * util function.
	 */
	gtk_native_dialog_show (GTK_NATIVE_DIALOG(dialog));

	zenity_util_gapp_main (NULL);
}

static void
zenity_fileselection_dialog_output (GtkFileChooser *chooser,
		ZenityFileData *file_data)
{
	g_autoptr(GListModel) model = gtk_file_chooser_get_files (chooser);
	guint items = g_list_model_get_n_items (model);

	for (guint i = 0; i < items; ++i)
	{
		g_autoptr(GFile) file = g_list_model_get_item (model, i);

		g_print ("%s", g_file_get_path (file));

		if (i != items - 1)
			g_print ("%s", file_data->separator);
	}
	g_print ("\n");
}

static void
zenity_fileselection_dialog_response (GtkWidget *widget, int response, gpointer data)
{
	ZenityFileData *file_data = data;
	GtkFileChooser *chooser = GTK_FILE_CHOOSER (widget);

	switch (response)
	{
		case GTK_RESPONSE_ACCEPT:
			zenity_fileselection_dialog_output (chooser, file_data);
			zenity_util_exit_code_with_data (ZENITY_OK, zen_data);
			break;

		case GTK_RESPONSE_REJECT:
			zen_data->exit_code = zenity_util_return_exit_code (ZENITY_CANCEL);
			break;

		case ZENITY_TIMEOUT:
			zenity_fileselection_dialog_output (chooser, file_data);
			zen_data->exit_code = zenity_util_return_exit_code (ZENITY_TIMEOUT);
			break;

		default:
			if (zen_data->extra_label &&
					response < (int)g_strv_length (zen_data->extra_label)) {
				printf ("%s\n", zen_data->extra_label[response]);
			}
			zen_data->exit_code = zenity_util_return_exit_code (ZENITY_ESC);
			break;
	}
	zenity_util_gapp_quit (NULL, zen_data);
}

G_GNUC_END_IGNORE_DEPRECATIONS
