#define WINVER 0xFFFFF /* use newest and greatest */

#include <gio/gio.h>
#include <glib.h>

#include <sys/stat.h>
#include <winsock2.h>
#include <iphlpapi.h>
#include <stdio.h>
#include <windows.h>

struct priv {
	OVERLAPPED overlap;
	GIOChannel *channel;
	GPollFD pollfd;
	GSource *source;
};

static int win_network_monitor_request_update(struct priv *priv)
{
	DWORD ret;
	HANDLE hand = NULL;

	g_printf("Request notify: start\n");
	ret = NotifyRouteChange(&hand, &priv->overlap);
	if (ret != NO_ERROR) {
		if (WSAGetLastError() != WSA_IO_PENDING) {
			g_warning("NotifyRouteChange error...%d\n", WSAGetLastError());
			return 1;
		}
	}
	g_printf("Request notify: done\n");

	return 0;
}

static gboolean routes_changed_cb(GIOChannel *source, GIOCondition condition, gpointer data)
{
	struct priv *priv = data;
	gboolean ret = TRUE;

	g_printf("New Status...\n");

	if (win_network_monitor_request_update(priv)) {
		ret = FALSE;
	}

	return ret;
}

gboolean still_here(gpointer user_data)
{
	g_printf("* still_here\n");

	return TRUE;
}

int main(int argc, char **argv)
{
	GMainLoop *loop;
	struct priv *priv;
	gboolean is_socket;
	gboolean is_file;
	struct _stati64 st;
	int optval;
	int optlen = sizeof(int);

	g_printf("Initial status...\n");

	priv = g_malloc0(sizeof(struct priv));
	priv->overlap.hEvent = WSACreateEvent();
	g_printf("hEvent: %d\n", (gintptr) priv->overlap.hEvent);

	is_socket = getsockopt((gintptr)priv->overlap.hEvent, SOL_SOCKET, SO_TYPE, (char *) &optval, &optlen) != SOCKET_ERROR;
	is_file = (_fstati64((gintptr) priv->overlap.hEvent, &st) == 0);

	if (!is_socket && !is_file) {
		g_printf("Neither a file nor a socket. Abort\n");
		//return -1;
	}

#ifdef IO_SOCKET
	priv->channel = g_io_channel_win32_new_socket((gintptr) priv->overlap.hEvent);

	g_io_add_watch(priv->channel, G_IO_IN | G_IO_PRI, routes_changed_cb, priv);
#else
	priv->source = g_timeout_source_new(0);
	g_source_set_ready_time(priv->source, -1);
	g_source_set_callback(priv->source, (GSourceFunc) routes_changed_cb, priv, NULL);

	priv->pollfd.fd = (gintptr)priv->overlap.hEvent;
	priv->pollfd.events = G_IO_IN;
	g_source_add_poll(priv->source, &priv->pollfd);

	g_source_attach(priv->source, g_main_context_get_thread_default());
#endif

	if (win_network_monitor_request_update(priv)) {
		return -1;
	}

	g_timeout_add_seconds(10, still_here, NULL);

	g_printf("start main loop\n");
	loop = g_main_loop_new(NULL, FALSE);
	g_main_loop_run(loop);

	return 0;
}
