#include <allegro.h>
#include "gui.h"
#include "gui-mouse.h"


static int last_mb, last_mz, last_mpos;


void gui_update_mouse(Widget<Container> *root, Widget **focus_object)
{
#define MOUSE_PRESSED(x)	( (mb & (1 << (x))) && !(last_mb & (1 << (x))))
#define MOUSE_HELD(x)		( (mb & (1 << (x))) &&  (last_mb & (1 << (x))))
#define MOUSE_RELEASED(x)	(!(mb & (1 << (x))) &&  (last_mb & (1 << (x))))
#define MOUSE_ALWAYS_OFF(x)	(!(mb & (1 << (x))) && !(last_mb & (1 << (x))))

    int button;
    int mb = mouse_b;
    int mz = mouse_z;
    int mpos = mouse_pos;

    /* If any buttons are held, then the focus object does not change. */
    for (button = 0; button < 3; button++)
	if (MOUSE_HELD(button) || MOUSE_RELEASED(button))
	    goto skip_mouse_enter_exit_messages;

    /* Mouse movement. */
    if (mpos != last_mpos) {
	Widget *new_focus_object = [root getWidgetBounding:mouse_x :mouse_y];
	if (new_focus_object != *focus_object) {
	    if (*focus_object)
		[*focus_object receiveMessage:MSG_MOUSE_EXIT];
	    [new_focus_object  receiveMessage:MSG_MOUSE_ENTER];
	    *focus_object = new_focus_object;
	}
	last_mpos = mpos;
    }

 skip_mouse_enter_exit_messages:

    /* Mouse button states. */
    if (*focus_object) {
	for (button = 0; button < 3; button++) {
	    if (MOUSE_PRESSED(button))
		[*focus_object receiveMessage:MSG_MOUSE_PRESSED :button];
	    else if (MOUSE_HELD(button))
		[*focus_object receiveMessage:MSG_MOUSE_HELD :button];
	    else if (MOUSE_RELEASED(button))
		[*focus_object receiveMessage:MSG_MOUSE_RELEASED :button];
	}
    }

    /* Mouse wheel. */
    if (mz != last_mz) {
	[*focus_object receiveMessage:MSG_MOUSE_WHEEL :last_mz - mz];
	last_mz = mz;
    }

    last_mb = mb;

#undef MOUSE_PRESSED
#undef MOUSE_HELD
#undef MOUSE_RELEASED
#undef MOUSE_ALWAYS_OFF
}


int gui_mouse_init(void)
{
    if (install_mouse() < 0) {
	allegro_message("Error installing mouse.\n");
	return -1;
    }

#if ((ALLEGRO_VERSION >= 4) &&		\
     (ALLEGRO_SUB_VERSION >= 1) &&	\
     (ALLEGRO_WIP_VERSION >= 16))
    /* I still have Allegro 4.0.3 in Windows. */
    enable_hardware_cursor();
#endif

    show_mouse(screen);
    return 0;
}


void gui_mouse_shutdown (void)
{
}
