#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <errno.h>
#include <fam.h>
#include <glib.h>

static gboolean fam_event_handler (GIOChannel *src, GIOCondition condition, gpointer data);

FAMConnection *famconn = NULL;
FAMRequest *req = NULL;
GMainLoop *loop = NULL;

int main (int argc, char *argv[])
{
	gchar *fname;
	
	if (argc < 2) {
		g_print ("Usage: %s <full-path-to-file-to-watch>\n", argv[0]);
		return -1;
	}
	fname = argv[1];
	
	famconn = g_new0 (FAMConnection, 1);
	/* Uncomment the following two lines to make it work with SUID binaries */
	//if (getuid() != geteuid())
	//	setuid(geteuid());
	
	if (FAMOpen (famconn) != 0)
	{
		g_free (famconn);
		g_warning ("Unable to connect to FAM!");
		return -1;
	}
	
	req = g_new0 (FAMRequest, 1);
	
	if (FAMMonitorFile (famconn, fname, req, NULL) == -1 && errno != 0)
	{
		g_warning ("FAMMonitorFile(%s): %s (errno=%d)", fname, g_strerror (errno), errno);
		/* For some reason, FAMMonitorFile sometimes returns -1 and sets errno to 0 (SUCCESS) */
		if (errno != 0) {
			g_free (req);
			req = NULL;
			return FALSE;
		}
	}
	GIOChannel *iochannel = g_io_channel_unix_new (FAMCONNECTION_GETFD(famconn));
	g_io_add_watch (iochannel, G_IO_IN | G_IO_HUP,
				   (GIOFunc) fam_event_handler, NULL);
	g_io_channel_unref (iochannel); /* Remove our reference (add_watch() has one already) */
	loop = g_main_loop_new (NULL, FALSE);
	g_main_loop_run (loop);
	g_print ("Main loop has returned..\n");
	g_free (famconn);
	g_free (req);
	return 0;
}

static gboolean fam_event_handler (GIOChannel *src, GIOCondition condition, gpointer data)
{
	FAMEvent ev;
	gboolean rv = TRUE;
	g_print ("Fam socket has data. Condition: 0x%X\n", condition);
	while (FAMPending(famconn))
	{
		if (FAMNextEvent(famconn, &ev) != 1)
		{
			/*  Nuts!  An error!  Shut down & clean up.  */
			g_error ("Error while receiving FAM-event! This shouldn't happen\n");
			rv = FALSE;
			g_main_loop_quit(loop);
			break;
		}

		switch (ev.code)
		{
			case FAMChanged:
				g_print ("File %s changed\n", ev.filename);
				break;
				
			default:
				break;
		}
	}
	if (condition & G_IO_HUP) {
		g_warning ("Got Hangup on FAM IOChannel, aborting");
		g_main_loop_quit(loop);
		rv = FALSE;
	}
	
	if (condition & G_IO_ERR) {
		g_warning ("Got error on FAM IOChannel, aborting watch");
		g_main_loop_quit(loop);
		rv = FALSE;
	}
	if (condition & G_IO_NVAL) {
		g_warning ("Got invalid data on FAM IOChannel, aborting watch");
		g_main_loop_quit(loop);
		rv = FALSE;
	}

	return rv;
}
