#include <glib.h>
#include <glib-object.h>
#include <gio/gio.h>
#include <glib.h>
#include <glib-object.h>
#include <stdlib.h>

static void on_changed (GFileMonitor* _sender, GFile* file, GFile* other_file, GFileMonitorEvent event_type, gpointer self);
static gpointer thread_func (gpointer self);
static gboolean source_func_01 (gpointer self);
static void media_monitor_setup_monitors ();
static gboolean source_func_02 (gpointer self);

static GList* monitors;

static GMainContext* main_context;
static GMainContext* local_context;
static GMainLoop* local_loop;
static GThread* thread;



static gboolean source_func_01 (gpointer self) {
    GSource* source;
    source = g_idle_source_new ();
    g_source_set_callback (source, source_func_02, NULL, NULL);
    g_source_attach (source, local_context);
    g_source_unref (source);
    return FALSE;
}

static gboolean source_func_02 (gpointer self) {
    media_monitor_setup_monitors ();
    return FALSE;
}


static void setup_monitors_recoursive (GFile* dir) {
    GFileType file_type = 0;
    GFileEnumerator* enumerator = NULL;
    GFileInfo* info = NULL;
    g_return_if_fail (dir != NULL);

    file_type = g_file_query_file_type (dir, G_FILE_QUERY_INFO_NONE, NULL);
    if (file_type != G_FILE_TYPE_DIRECTORY) {
        return;
    }
    GFileMonitor* monitor = NULL;
    monitor = g_file_monitor_directory (dir, G_FILE_MONITOR_NONE, NULL, NULL);
    monitor = g_object_ref (monitor);
    g_signal_connect_object (monitor, "changed", (GCallback) on_changed, NULL, 0);

    monitors = g_list_prepend (monitors, monitor);
    g_object_unref (monitor);

    enumerator = g_file_enumerate_children (
                            dir,
                            g_strdup (G_FILE_ATTRIBUTE_STANDARD_NAME "," 
                                      G_FILE_ATTRIBUTE_STANDARD_TYPE), 
                            G_FILE_QUERY_INFO_NONE,
                            NULL,
                            NULL);
    while (TRUE) {
        gchar* filename;
        gchar* filepath;
        GFile* file;
        GFileType filetype;
        if(info != NULL)
            g_object_unref (info);
        info = g_file_enumerator_next_file (enumerator, NULL, NULL);
        if (info == NULL) {
            break;
        }
        filename = g_strdup (g_file_info_get_name (info));
        filepath = g_build_filename (g_file_get_path (dir), filename, NULL);
        file = g_file_new_for_path (filepath);
        filetype = g_file_info_get_file_type (info);
        if (filetype == G_FILE_TYPE_DIRECTORY) {
            setup_monitors_recoursive (file);
        }
        g_object_unref (file);
        g_free (filepath);
        g_free (filename);
    }
    g_object_unref (enumerator);
}

static void media_monitor_setup_monitors () {
    const gchar* path = NULL;
    GFile* dir;
    path = g_get_user_special_dir (G_USER_DIRECTORY_MUSIC);
    dir = g_file_new_for_path (path);
    monitors = NULL;
    setup_monitors_recoursive (dir);
    g_object_unref (dir);
    g_print("DONE SETTING UP %u MONITORS\n", g_list_length (monitors));
}


static void on_changed (GFileMonitor* sender,
                        GFile* file,
                        GFile* other_file,
                        GFileMonitorEvent event_type,
                        gpointer self) {
    // CRASH happens if no prints are added here
    //g_print("BLA %u MONITORS\n", g_list_length (monitors));
    return;
}

static gpointer thread_func (gpointer self) {
    gpointer res;
    gint result = 0;
    local_context = g_main_context_new ();
    g_main_context_push_thread_default (local_context);
    local_loop = g_main_loop_new (local_context, FALSE);
    g_main_loop_run (local_loop);
    result = 0;
    res = result;
    return res;
}


int main (int argc, char ** argv) {
    g_thread_init (NULL);
    g_type_init ();
    GMainLoop* loop;
    if (!g_thread_supported ()) {
        g_error ("Cannot work without multithreading support.");
    }
    main_context = g_main_context_default();
    thread = g_thread_create (thread_func, NULL, FALSE, NULL);
    loop = g_main_loop_new (NULL, FALSE);
    g_timeout_add_seconds_full (G_PRIORITY_DEFAULT, (guint) 2, source_func_01, NULL, NULL);
    g_main_loop_run (loop);
    g_main_loop_unref (loop);
    return 0;
}

