#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <cspi/spi.h>
#include <glib.h>
#include <pthread.h>

static gchar *events[] = 
    {
	"focus:",
    	"object:text-caret-moved",
    	"object:link-selected",
    };


static void report_event (const AccessibleEvent *event, void *user_data);
static AccessibleEventListener *listener = NULL;

int
main(int argc, char **argv)
{
    gint i;

    SPI_init();

    listener = SPI_createAccessibleEventListener (report_event, NULL);
    for (i = 0; i < G_N_ELEMENTS (events); i++)
	SPI_registerGlobalEventListener (listener, events[i]);

    SPI_event_main();
    SPI_exit ();

    return 0;
}


static void
report_state (Accessible *acc)
{
    AccessibleStateSet *state; 
    struct
    {
        AccessibleState type;
        gchar *type_text;
    }states[] = 
        {
	    {SPI_STATE_INVALID,			"INVALID"},
	    {SPI_STATE_ACTIVE,			"ACTIVE"},
	    {SPI_STATE_ARMED,			"ARMED"},
	    {SPI_STATE_BUSY,			"BUSY"},
	    {SPI_STATE_CHECKED,			"CHECKED"},
	    {SPI_STATE_COLLAPSED,		"COLLAPSED"},
	    {SPI_STATE_DEFUNCT,			"DEFUNCT"},
	    {SPI_STATE_EDITABLE,		"EDITABLE"},
	    {SPI_STATE_ENABLED,			"ENABLED"},
	    {SPI_STATE_EXPANDABLE,		"EXPANDABLE"},
	    {SPI_STATE_EXPANDED,		"EXPANDED"},
	    {SPI_STATE_FOCUSABLE,		"FOCUSABLE"},
	    {SPI_STATE_FOCUSED,			"FOCUSED"},
	    {SPI_STATE_HORIZONTAL,		"HORIZONTAL"},
	    {SPI_STATE_ICONIFIED,		"ICONIFIED"},
	    {SPI_STATE_MODAL,			"MODAL"},
	    {SPI_STATE_MULTI_LINE,		"MULTI_LINE"},
	    {SPI_STATE_MULTISELECTABLE,		"MULTISELECTABLE"},
	    {SPI_STATE_OPAQUE,			"OPAQUE"},
	    {SPI_STATE_PRESSED,			"PRESSED"},
	    {SPI_STATE_RESIZABLE,		"REZISEABLE"},
	    {SPI_STATE_SELECTABLE,		"SELECTABLE"},
	    {SPI_STATE_SELECTED,		"SELECTED"},	    
	    {SPI_STATE_SENSITIVE,		"SENSITIVE"},
	    {SPI_STATE_SHOWING,			"SHOWING"},
	    {SPI_STATE_SINGLE_LINE,		"SINGLE_LINE"},
	    {SPI_STATE_STALE,			"STALE"},	    
	    {SPI_STATE_TRANSIENT,		"TRANSIENT"},
	    {SPI_STATE_VERTICAL,		"VERTICAL"},
	    {SPI_STATE_VISIBLE,			"VISIBLE"},
	    {SPI_STATE_MANAGES_DESCENDANTS,	"MANGE_DESC"},
	    {SPI_STATE_INDETERMINATE,		"INDETERMINATE"},
	};
    int i;
        
    if (!acc)
	return;
	
    state = Accessible_getStateSet (acc);
    if (!state)
	return;
 
    for (i = 0; i < G_N_ELEMENTS (states); i++)
    {
	if (AccessibleStateSet_contains (state, states[i].type))
	    fprintf (stderr, " %s", states[i].type_text);
    }

    AccessibleStateSet_unref (state);
}	

static Accessible*
get_html (Accessible *acc)
{
    Accessible *parent;
    
    if (!acc)
	return;
    
    parent = acc;
    Accessible_ref (acc);
    while (parent)
    {
        if (Accessible_getRole (acc) == SPI_ROLE_HTML_CONTAINER)
	    break;
	acc = Accessible_getParent (parent);
	parent = acc;
    }
    return acc; 
}

static void 
report_general (const AccessibleEvent *event,
	        void *user_data)
{
    static gint cnt = 0;
    fprintf (stderr, "\n\n%d: %xp %s for %s(%s) role %s with details %ld %ld",
		cnt++,
		(unsigned int)event->source, event->type, 
		Accessible_getName (event->source),
		Accessible_getDescription (event->source),
		Accessible_getRoleName (event->source),
		event->detail1, event->detail2);
}

static void 
report_event (const AccessibleEvent *event,
	      void *user_data)
{
    static gboolean busy = FALSE;

    Accessible_ref (event->source);

    if (busy)
    {
	fprintf (stderr, "\nRRRR:%s", event->type);
	return;
    }
    busy = TRUE;

    report_general (event, user_data);
    fprintf (stderr, "\nCRT  STATE:");
    report_state (event->source);
    fprintf (stderr, "\nHTML STATE:");
    report_state (get_html (event->source));

    busy = FALSE;
}
