/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.

For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "platform/linux/linux_open_with_dialog.h"

#include "platform/linux/linux_gtk_integration_p.h"
#include "platform/linux/linux_gdk_helper.h"
#include "window/window_controller.h"
#include "core/application.h"

#include <private/qguiapplication_p.h>

namespace Platform {
namespace File {
namespace internal {
namespace {

using namespace Platform::Gtk;

bool OpenWithDialogSupported() {
	return Platform::internal::GdkHelperLoaded()
		&& (gtk_app_chooser_dialog_new != nullptr)
		&& (gtk_app_chooser_get_app_info != nullptr)
		&& (gtk_app_chooser_get_type != nullptr)
		&& (gtk_widget_get_window != nullptr)
		&& (gtk_widget_realize != nullptr)
		&& (gtk_widget_show != nullptr)
		&& (gtk_widget_destroy != nullptr);
}

class OpenWithDialog : public QWindow {
public:
	OpenWithDialog(const QString &filepath);
	~OpenWithDialog();

	bool exec();

private:
	static void handleResponse(OpenWithDialog *dialog, int responseId);

	GFile *_gfileInstance = nullptr;
	GtkWidget *_gtkWidget = nullptr;
	QEventLoop _loop;
	std::optional<bool> _result;
};

OpenWithDialog::OpenWithDialog(const QString &filepath)
: _gfileInstance(g_file_new_for_path(filepath.toUtf8().constData()))
, _gtkWidget(gtk_app_chooser_dialog_new(
		nullptr,
		GTK_DIALOG_MODAL,
		_gfileInstance)) {
	g_signal_connect_swapped(
		_gtkWidget,
		"response",
		G_CALLBACK(handleResponse),
		this);
}

OpenWithDialog::~OpenWithDialog() {
	gtk_widget_destroy(_gtkWidget);
	g_object_unref(_gfileInstance);
}

bool OpenWithDialog::exec() {
	gtk_widget_realize(_gtkWidget);

	if (const auto activeWindow = Core::App().activeWindow()) {
		Platform::internal::XSetTransientForHint(
			gtk_widget_get_window(_gtkWidget),
			activeWindow->widget().get()->windowHandle()->winId());
	}

	QGuiApplicationPrivate::showModalWindow(this);
	gtk_widget_show(_gtkWidget);

	if (!_result.has_value()) {
		_loop.exec();
	}

	QGuiApplicationPrivate::hideModalWindow(this);
	return *_result;
}

void OpenWithDialog::handleResponse(OpenWithDialog *dialog, int responseId) {
	GAppInfo *chosenAppInfo = nullptr;
	dialog->_result = true;

	switch (responseId) {
	case GTK_RESPONSE_OK:
		chosenAppInfo = gtk_app_chooser_get_app_info(
			gtk_app_chooser_cast(dialog->_gtkWidget));

		if (chosenAppInfo) {
			GList *uris = nullptr;
			uris = g_list_prepend(uris, g_file_get_uri(dialog->_gfileInstance));
			g_app_info_launch_uris(chosenAppInfo, uris, nullptr, nullptr);
			g_list_free(uris);
			g_object_unref(chosenAppInfo);
		}

		break;

	case GTK_RESPONSE_CANCEL:
	case GTK_RESPONSE_DELETE_EVENT:
		break;

	default:
		dialog->_result = false;
		break;
	}

	dialog->_loop.quit();
}

} // namespace

bool ShowOpenWithDialog(const QString &filepath) {
	if (!OpenWithDialogSupported()) {
		return false;
	}

	return OpenWithDialog(filepath).exec();
}

} // namespace internal
} // namespace File
} // namespace Platform
