/*
    zfiledlg.c - file dialog
    Copyright (C) 2011-2020 Ladislav Vaiz <ok1zia@nagano.cz>

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    version 2 as published by the Free Software Foundation.

*/

#include <zfiledlg.h>

#include <eprintf.h>
#include <zdebug.h>
#include <zgptrarray.h>
#include <zpath.h>
#include <zselect.h>
#include <zstr.h>
#include <zthread.h>
#include <glib.h>

//#ifdef Z_HAVE_DLFCN_H
//#include <dlfcn.h>
//#endif

#ifdef Z_HAVE_STDLIB_H
#include <stdlib.h>
#endif

#include <string.h>

struct zselect;

static gpointer zfiledlg_thread_func(gpointer data);


struct zfiledlg *zfiledlg_init(void){
    struct zfiledlg *dlg;

    dlg = g_new0(struct zfiledlg, 1);
    dlg->thread = NULL;
    dlg->last_dir = NULL;
    return dlg;   
}

void zfiledlg_free(struct zfiledlg *dlg){
	if (dlg->thread != NULL) {
		g_thread_join(dlg->thread);
		dlg->thread = NULL;
	}
    //dbg("zfiledlg_free\n");
    g_free(dlg->last_dir);
#ifdef Z_MSC_MINGW
	g_free(dlg->ofn.lpstrFile);
#endif
    dlg->last_dir = NULL;
}


int zfiledlg_open(struct zfiledlg *dlg, struct zselect *zsel, void (*fce)(void *, char *), void *arg, const char *filename, const char *ext){
#ifdef Z_MSC_MINGW_CYGWIN
	int i, l, t;
	GString *gs;
	char *c, *ext2;

	if (dlg->thread != NULL) {
		g_thread_join(dlg->thread);
		dlg->thread = NULL;
	}
	dlg->zsel = zsel;
	dlg->fce = fce;
	dlg->arg = arg;
	
    ZeroMemory(&dlg->ofn, sizeof(OPENFILENAME));
    dlg->ofn.lStructSize = sizeof(OPENFILENAME);
    dlg->ofn.lpstrFile = (char *)g_malloc(_MAX_PATH);
	g_strlcpy(dlg->ofn.lpstrFile, filename, _MAX_PATH);
	dlg->ofn.nMaxFile = _MAX_PATH;

	gs = g_string_new("");
	ext2 = g_strdup(ext);
	t = 0;
	while ((c = z_tokenize(ext2, &t)) != NULL) {
		char *u = g_strdup(c);
		z_str_uc(u);
		g_string_append_printf(gs, "%s files (*.%s)|*.%s|", u, c, c);
		g_free(u);
	}
	g_free(ext2);
	g_string_append_printf(gs, "All files (*.*)|*.*|", ext, ext);
	c = g_strdup(gs->str);
	g_string_free(gs, TRUE);
	l = strlen(c);
	for (i = 0; i < l; i++) if (c[i] == '|') c[i] = '\0';
	dlg->ofn.lpstrFilter = c;

    dlg->ofn.nFilterIndex = 1;
    dlg->ofn.nMaxFileTitle = 0;
    dlg->ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;

	//dlg->thread = g_thread_create(zfiledlg_thread_func, dlg, TRUE, NULL);
	dlg->thread = g_thread_try_new("zfiledlg", zfiledlg_thread_func, dlg, NULL);
    return 0;

#elif defined(Z_HAVE_GTK)

	if (dlg->thread != NULL) {
		g_thread_join(dlg->thread);
		dlg->thread = NULL;
	}
	dlg->zsel = zsel;
	dlg->fce = fce;
	dlg->arg = arg;
	dlg->ext2 = g_strdup(ext);
/*    void *gtkso = dlopen("/usr/lib/libgtk-x11-2.0.so.0", RTLD_LAZY);
    if (!gtkso) {
        error("dlopen failed: %s\n", dlerror());
        return -1;
    }
    dlg->gtk_init = dlsym(gtkso, "gtk_init");
    dlg->gtk_file_chooser_dialog_new = dlsym(gtkso, "gtk_file_chooser_dialog_new");
    dlg->gtk_dialog_run = dlsym(gtkso, "gtk_dialog_run");
    dlg->gtk_file_chooser_get_filename = dlsym(gtkso, "gtk_file_chooser_get_filename");
    dlg->gtk_widget_destroy = dlsym(gtkso, "gtk_widget_destroy");
    dlg->gtk_events_pending = dlsym(gtkso, "gtk_events_pending");
    dlg->gtk_main_iteration = dlsym(gtkso, "gtk_main_iteration");
    dlg->gtk_file_chooser_set_current_folder = dlsym(gtkso, "gtk_file_chooser_set_current_folder");
    dlg->gtk_file_filter_new = dlsym(gtkso, "gtk_file_filter_new");
    dlg->gtk_file_filter_set_name = dlsym(gtkso, "gtk_file_set_name");
    dlg->gtk_file_filter_add_pattern = dlsym(gtkso, "gtk_file_add_pattern");
    dlg->g_object_set_data = dlsym(gtkso, "g_object_set_data");
    dlg->gtk_file_chooser_add_filter = dlsym(gtkso, "gtk_file_chooser_add_filter");*/

    gtk_init(0, NULL);

    dlg->memlist = g_ptr_array_new();

#ifdef Z_MACOS
	zfiledlg_thread_func(dlg);
#else
	dlg->thread = g_thread_try_new("zfiledlg", zfiledlg_thread_func, dlg, NULL);
#endif

    return 0;
#else
    return -1;
#endif
}

static gpointer zfiledlg_thread_func(gpointer data){
#ifdef Z_MSC_MINGW_CYGWIN
	struct zfiledlg *dlg = (struct zfiledlg *)data;
#endif

	zg_thread_set_name("Libzia zfiledlg");

#ifdef Z_MSC_MINGW_CYGWIN

    if (!GetOpenFileName(&dlg->ofn)){
		zselect_msg_send(dlg->zsel, "ZFILEDLG;0x%lx;X;%d", (unsigned long)GPOINTER_TO_SIZE(dlg), CommDlgExtendedError());
	}else{
		zselect_msg_send(dlg->zsel, "ZFILEDLG;0x%lx;F;%s", (unsigned long)GPOINTER_TO_SIZE(dlg), dlg->ofn.lpstrFile);
    }
	g_free((void *)dlg->ofn.lpstrFilter);
	return NULL;
	
#elif defined (Z_HAVE_GTK)
    int ret;
    int t;
	char *c, *d;
	struct zfiledlg *dlg = (struct zfiledlg *)data;

    GtkWidget *dialog = gtk_file_chooser_dialog_new("Open file", NULL, GTK_FILE_CHOOSER_ACTION_OPEN, 
            "_Cancel", GTK_RESPONSE_CANCEL,
            "_Open", GTK_RESPONSE_ACCEPT,
            NULL);
    if (dlg->last_dir != NULL) {
        ret = gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), dlg->last_dir);
    }
	
    t = 0;
	while ((c = z_tokenize(dlg->ext2, &t)) != NULL) {
        GtkFileFilter *filter = gtk_file_filter_new();

        d = g_strdup_printf("%s files (*.%s)", c, c);
        g_ptr_array_add(dlg->memlist, d);
        gtk_file_filter_set_name(filter, d);

        d = g_strdup_printf("*.%s", c);
        g_ptr_array_add(dlg->memlist, d);
        gtk_file_filter_add_pattern(filter, d);

        gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
	}
	g_free(dlg->ext2);

    ret = gtk_dialog_run(GTK_DIALOG(dialog));
    if (ret != GTK_RESPONSE_ACCEPT){
		zselect_msg_send(dlg->zsel, "ZFILEDLG;0x%lx;X;%d", (unsigned long)GPOINTER_TO_SIZE(dlg), ret);
    }else{
        char *file = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
        zselect_msg_send(dlg->zsel, "ZFILEDLG;0x%lx;F;%s", (unsigned long)GPOINTER_TO_SIZE(dlg), file);
    }
    gtk_widget_destroy(dialog);
    while (gtk_events_pending()) gtk_main_iteration();
    zg_ptr_array_free_all(dlg->memlist);
    return NULL;
#else
    return NULL;
#endif
}

void zfiledlg_read_handler(int n, char *items[]){
    dbg("zfiledlg_read_handler '%s'\n", items[1]);
    struct zfiledlg *dlg = (struct zfiledlg *)strtol(items[1], NULL, 16);
    dbg("zfiledlg_read_handler %p\n", dlg);

	if (strcmp(items[2], "F") == 0){
        g_free(dlg->last_dir);
        dlg->last_dir = g_strdup(items[3]);
        z_dirname(dlg->last_dir);
        dbg("zfiledlg_read_handler: last_dir='%s'\n", dlg->last_dir);
		dlg->fce(dlg->arg, items[3]);
	}
}
