#include <com_sun_glass_ui_gtk_GtkCommonDialogs.h>
#include "glass_general.h"
#include "glass_window.hpp"

extern "C" {
#include <gdk/gdk.h>
#include <gtk/gtk.h>
}

#include <cstring>
#include <cstdlib>

static void setup_GtkFileFilters(GtkFileChooser*, JNIEnv*, jobjectArray);
static void free_fname(char*, gpointer);

static gboolean jstring_to_utf_get(JNIEnv *env, jstring jstr,
                                   const char **cstr) {
    const char *newstr;

    if (jstr == NULL) {
        *cstr = NULL;
        return TRUE;
    }

    newstr = env->GetStringUTFChars(jstr, NULL);
    if (newstr != NULL) {
        *cstr = newstr;
        return TRUE;
    }

    return FALSE;
}

static void jstring_to_utf_release(JNIEnv *env, jstring jstr,
                                   const char *cstr) {
    if (cstr != NULL) {
        env->ReleaseStringUTFChars(jstr, cstr);
    }
}

static GtkWindow *gdk_window_handle_to_gtk(jlong handle) {
    return  (handle != 0)
                ? ((WindowContext*)JLONG_TO_PTR(handle))->get_gtk_window()
                : NULL;
}

JNIEXPORT jobjectArray JNICALL Java_com_sun_glass_ui_gtk_GtkCommonDialogs__1showFileChooser
  (JNIEnv *env, jclass clazz, jlong parent, jstring folder, jstring title,
   jint type, jboolean multiple, jobjectArray extFilters) {

    jobjectArray jfile_names = NULL;
    char* filename;
    jstring jfilename;

    const char* chooser_folder;
    const char* chooser_title;
    const int chooser_type = type == 0 ? GTK_FILE_CHOOSER_ACTION_OPEN : GTK_FILE_CHOOSER_ACTION_SAVE;

    if (!jstring_to_utf_get(env, folder, &chooser_folder)) {
        return NULL;
    }

    if (!jstring_to_utf_get(env, title, &chooser_title)) {
        jstring_to_utf_release(env, folder, chooser_folder);
        return NULL;
    }

    GtkWidget* chooser = gtk_file_chooser_dialog_new(chooser_title, gdk_window_handle_to_gtk(parent), 
            static_cast<GtkFileChooserAction>(chooser_type),
            GTK_STOCK_CANCEL,
            GTK_RESPONSE_CANCEL,
            (chooser_type == GTK_FILE_CHOOSER_ACTION_OPEN ? GTK_STOCK_OPEN : GTK_STOCK_SAVE),
            GTK_RESPONSE_ACCEPT,
            NULL);

    gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(chooser), (JNI_TRUE == multiple));
    gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(chooser), chooser_folder);
    setup_GtkFileFilters(GTK_FILE_CHOOSER(chooser), env, extFilters);

    if (gtk_dialog_run(GTK_DIALOG(chooser)) == GTK_RESPONSE_ACCEPT) {
        GSList* fnames_gslist = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(chooser));
        gint fnames_list_len = g_slist_length(fnames_gslist);
        LOG1("FileChooser selected files: %d\n", fnames_list_len)

        if (fnames_list_len > 0) {
            jfile_names = env->NewObjectArray((jsize)fnames_list_len, string, NULL);
            int i;
            for(i = 0; i < fnames_list_len; i++) {
                filename = (char*)g_slist_nth(fnames_gslist, i)->data;
                LOG1("Add [%s] into returned filenames\n", filename)
                jfilename = env->NewStringUTF(filename);
                env->SetObjectArrayElement(jfile_names, (jsize)i, jfilename);
            }
            g_slist_foreach(fnames_gslist, (GFunc) free_fname, NULL);
            g_slist_free(fnames_gslist);
        }
    } else {
        jfile_names = env->NewObjectArray(0, string, NULL);
    }
    gtk_widget_destroy(chooser);

    jstring_to_utf_release(env, folder, chooser_folder);
    jstring_to_utf_release(env, title, chooser_title);

    LOG_STRING_ARRAY(env, jfile_names);
    return jfile_names;
}

static void free_fname(char* fname, gpointer unused) {
    g_free(fname);
}

JNIEXPORT jstring JNICALL Java_com_sun_glass_ui_gtk_GtkCommonDialogs__1showFolderChooser
  (JNIEnv *env, jclass clazz, jlong parent, jstring folder, jstring title) {
    jstring jfilename = NULL;
    const char *chooser_folder;
    const char *chooser_title;

    if (!jstring_to_utf_get(env, folder, &chooser_folder)) {
        return NULL;
    }

    if (!jstring_to_utf_get(env, title, &chooser_title)) {
        jstring_to_utf_release(env, folder, chooser_folder);
        return NULL;
    }

    GtkWidget* chooser = gtk_file_chooser_dialog_new(
            chooser_title,
            gdk_window_handle_to_gtk(parent),
            GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
            GTK_STOCK_CANCEL,
            GTK_RESPONSE_CANCEL,
            GTK_STOCK_OPEN,
            GTK_RESPONSE_ACCEPT,
            NULL);

    if (chooser_folder != NULL) {
        gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(chooser),
                                            chooser_folder);
    }

    if (gtk_dialog_run(GTK_DIALOG(chooser)) == GTK_RESPONSE_ACCEPT) {
        gchar* filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(chooser));
        jfilename = env->NewStringUTF(filename);
        LOG1("Selected folder: %s\n", filename);
        g_free(filename);
    }

    jstring_to_utf_release(env, folder, chooser_folder);
    jstring_to_utf_release(env, title, chooser_title);

    gtk_widget_destroy(chooser);
    return jfilename;
}

/**
 *
 * @param env
 * @param extFilters ExtensionFilter[]
 * @return
 */
static void setup_GtkFileFilters(GtkFileChooser* chooser, JNIEnv* env, jobjectArray extFilters) {
    int i;
    LOG0("Setup filters\n")
    //setup methodIDs
    jclass jcls = env->FindClass("com/sun/glass/ui/CommonDialogs$ExtensionFilter");
    jmethodID jgetDescription = env->GetMethodID(jcls,
                                         "getDescription", "()Ljava/lang/String;");
    jmethodID jextensionsToArray = env->GetMethodID(jcls,
                                         "extensionsToArray", "()[Ljava/lang/String;");

    jsize jfilters_size = env->GetArrayLength(extFilters);
    LOG1("Filters: %d\n", jfilters_size)
    if (jfilters_size == 0) return;

    for(i = 0; i<jfilters_size; i++) {
        GtkFileFilter* ffilter = gtk_file_filter_new();
        jobject jfilter = env->GetObjectArrayElement(extFilters, i);

        //setup description
        jstring jdesc = (jstring)env->CallObjectMethod(jfilter, jgetDescription);
        int jdesc_size = env->GetStringLength(jdesc);
        char* description = (char*)g_malloc(jdesc_size + 1);
        env->GetStringUTFRegion(jdesc, 0, jdesc_size, description);
        LOG2("description[%d]: %s\n", i, description)
        gtk_file_filter_set_name(ffilter, description);
        g_free(description);

        //add patterns
        jobjectArray jextensions = (jobjectArray)env->CallObjectMethod(jfilter, jextensionsToArray);
        jsize jextarray_size = env->GetArrayLength(jextensions);
        LOG1("Patterns: %d\n", jextarray_size)
        int ext_idx;
        for(ext_idx = 0; ext_idx < jextarray_size; ext_idx++) {
            jstring jext = (jstring)env->GetObjectArrayElement(jextensions, ext_idx);
            jsize jext_size = env->GetStringLength(jext);
            char* ext = (char *) g_malloc(jext_size + 1);
            env->GetStringUTFRegion(jext, 0, jext_size, ext);
            LOG2("pattern[%d]: %s\n", ext_idx, ext)
            gtk_file_filter_add_pattern(ffilter, ext);
            g_free(ext);
        }
        LOG0("Filter ready\n")
        gtk_file_chooser_add_filter(chooser, ffilter);
    }
}

