#ifndef UI_H
#define	UI_H

/*
 * UI event types.
 * Stored in ui_event_t -> type.
 */
typedef enum
{
	ui_no_event,

	/*
	 * Key & mouse buttons press or release events.
	 * Message-related information stored in ui_event_t -> key.
	 */
	ui_key_event,
	/*
	 * Pointer motion event.
	 * Message-related information stored in ui_event_t itself,
	 * both ui_event_t -> key fields and most of ui_event_t -> configure
	 * fields are irrelevant.
	 */
	ui_pointer_motion_event,
	/*
	 * Key & mouse buttons press or release events.
	 * Message-related information stored in ui_event_t -> configure.
	 */
	ui_window_focus_in_event,	/* can look at configure.focused */
	ui_window_focus_out_event,	/* can look at configure.focused */
	ui_window_expose_event,		/* look at configure.exposed_XXX */
	ui_window_map_event,		/* can look at configure.visible */
	ui_window_unmap_event,		/* can look at configure.visible */
	ui_window_move_event,		/* look at configure.[x|y] */
	ui_window_size_event,		/* look at configure.[width|height] */
	/*
	 * Message from window manager. Look at configure.wm_event.
	 */
	ui_wm_event,

	ui_max_event
}	ui_event_type_t;

/*
 * Scancodes for "Windows" PC keyboard + 3-button & wheel mouse.
 *
 * Stored in ui_key_event_t -> key -> scan
 */
typedef enum
{
	sc_unknown,

	sc_escape,
	sc_f1,
	sc_f2,
	sc_f3,
	sc_f4,
	sc_f5,
	sc_f6,
	sc_f7,
	sc_f8,
	sc_f9,
	sc_f10,
	sc_f11,
	sc_f12,
	sc_print,
	sc_scroll_lock,
	sc_pause,

	sc_grave,
	sc_1,
	sc_2,
	sc_3,
	sc_4,
	sc_5,
	sc_6,
	sc_7,
	sc_8,
	sc_9,
	sc_0,
	sc_minus,
	sc_equal,
	sc_backslash,
	sc_backspace,

	sc_tab,
	sc_q,
	sc_w,
	sc_e,
	sc_r,
	sc_t,
	sc_y,
	sc_u,
	sc_i,
	sc_o,
	sc_p,
	sc_lbracket,
	sc_rbracket,
	sc_enter,

	sc_caps_lock,
	sc_a,
	sc_s,
	sc_d,
	sc_f,
	sc_g,
	sc_h,
	sc_j,
	sc_k,
	sc_l,
	sc_semicolon,
	sc_apostrophe,

	sc_lshift,
	sc_z,
	sc_x,
	sc_c,
	sc_v,
	sc_b,
	sc_n,
	sc_m,
	sc_comma,
	sc_period,
	sc_slash,
	sc_rshift,

	sc_lcontrol,
	sc_lsuper, /* Left WIN */
	sc_lalt,
	sc_space,
	sc_ralt,
	sc_rsuper, /* Right WIN */
	sc_menu,
	sc_rcontrol,

	sc_insert,
	sc_home,
	sc_prior,
	sc_delete,
	sc_end,
	sc_next,

	sc_up,
	sc_down,
	sc_left,
	sc_right,

	sc_num_lock,
	sc_kp_slash,
	sc_kp_multiply,
	sc_kp_subtract,
	sc_kp_home,
	sc_kp_up,
	sc_kp_prior,
	sc_kp_add,
	sc_kp_left,
	sc_kp_begin,
	sc_kp_right,
	sc_kp_end,
	sc_kp_down,
	sc_kp_next,
	sc_kp_enter,
	sc_kp_insert,
	sc_kp_delete,
	
	sc_lbutton,
	sc_mbutton,
	sc_rbutton,

	sc_wheelup,
	sc_wheeldown,

	sc_maxcode
} ui_scancode_t;

#define	sc_pageup	sc_prior
#define	sc_pagedown	sc_next

#define	sc_lwin		sc_lsuper
#define	sc_rwin		sc_rsuper

#define	sc_kp_7		sc_kp_home
#define	sc_kp_8		sc_kp_up
#define	sc_kp_9		sc_kp_prior
#define	sc_kp_4		sc_kp_left
#define	sc_kp_5		sc_kp_begin
#define	sc_kp_6		sc_kp_right
#define	sc_kp_1		sc_kp_end
#define	sc_kp_2		sc_kp_down
#define	sc_kp_3		sc_kp_next
#define	sc_kp_0		sc_kp_insert
#define	sc_kp_dot	sc_kp_delete

/*
 * Mouse buttons state masks.
 * Stored in ui_event_t -> button
 */
#define	UI_LBUTTON_MASK	(1<<0)
#define	UI_MBUTTON_MASK (1<<1)
#define	UI_RBUTTON_MASK (1<<2)

/*
 * Modifier key state masks.
 * Stored in ui_event_t-> state
 */
#define	UI_NUM_LOCK_MASK	(1<<0)	/* X11: Mod2 */
#define	UI_CAPS_LOCK_MASK	(1<<1)
#define	UI_SCROLL_LOCK_MASK	(1<<2)	/* X11: Mod5 */
#define	UI_SHIFT_MASK		(1<<3)
#define	UI_CONTROL_MASK		(1<<4)
#define	UI_ALT_MASK			(1<<5)	/* X11: Mod1 */
#define	UI_SUPER_MASK		(1<<6)	/* X11: Mod4 */

/*
 * WM requests: only one is known at this time
 */
typedef enum
{
	ui_wm_unknown,

	ui_wm_close,	/* closing request (under Win32 - Alt+F4 pressed) */

	ui_wm_max
}	ui_wm_event_t;

typedef struct ui_key_event_s
{
	vboolean press;	/* == true if key/button is pressed */
	unsigned scan;	/* scancode: cpecific for LibV, defined above */
	unsigned acode;	/* 8-bit character code for current locale */
	unsigned ucode;	/* machine-endian 16-bit unicode */
}	ui_key_event_t, *ui_key_event_p;

typedef struct ui_configure_event_s
{
	vboolean focused;	/* == true if window has input focus */
	vboolean visible;	/* == true if window is visible (mapped) */
	/* damaged rectangle for ui_window_expose event */
	unsigned exposed_left, exposed_top, exposed_right, exposed_bottom;
	int x, y;			/* position of window */
	unsigned width, height;	/* size of window */
	/* window manager request */
	unsigned wm_event;
}	ui_configure_event_t, *ui_configure_event_p;

typedef struct ui_event_s
{
	int		type;
	/*
	 * Win32: time in seconds since creation of window.
	 * X11: time since first key/button/motion event.
	 *
	 * FIXME: still platform-dependent.
	 * FIXME: doesn't correspond to timeTickCount().
	 * FIXME: Make it works under Win32 as it works under X11.
	 */
	vec_t	time;
	/*
	 * Mouse pointer position, client space.
	 */
	int		client_x, client_y;
	/*
	 * Mouse pointer position, screen space. Try _not_ to use it
	 * without necessity.
	 */
	int		screen_x, screen_y;
	/*
	 * Mouse pointer deltas since last move.
	 */
	int		client_dx, client_dy;
	unsigned button; /* state of mouse buttons */
	unsigned state; /* state of keyboard modifiers */

	ui_key_event_t key;	/* ui_key_event - specific data */

	ui_configure_event_t configure; /* window - configuration specific data */
}	ui_event_t, *ui_event_p;


#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
	/*
	 * Enables or disables keyboard autorepeat.
	 */
	void	V_GLOBAL	uiAutoRepeat(vboolean enable);
	/*
	 * If 'enable': saves pointer position, hides pointer, starts
	 * incremental tracking of pointer coords (screen position of pointer
	 * _no more_ corresponds to window position, which can be arbitrary
	 * number between [-MAXLONG;MAXLONG]). If !'enable': restores
	 * pointer position, shows pointer. It is recommended to use deltas
	 * (i.e. msg->client_dx and msg->client_dy) instead of coords.
	 */
	void	V_GLOBAL	uiAutoWarp(vboolean enable);
	/*
	 * Polls the system (moving the messages from all threads' queues),
	 * returns number of events waiting in queue of window of current
	 * thread; _never blocks_.
	 */
	vboolean	V_GLOBAL	uiPending(void);
	/*
	 * Removes the oldest event waiting in queue of active GL
	 * window. Polls the system queue and _can block_.
	 */
	vboolean	V_GLOBAL	uiNextEvent(ui_event_p ev_return);
	/*
	 * Returns pointer to n#th event from head of the queue.
	 * Neither polls system, nor blocks.
	 */
	ui_event_p	V_GLOBAL	uiPeekEvent(vsize_t offset_from_first_push);
	/* Same as above, but returns n#th event from tail of the queue. */
	ui_event_p	V_GLOBAL	uiPeekLastEvent(vsize_t offset_from_last_push);
	/*
	 * The two following routines behaves similar to previous ones,
	 * but also removes message from queue.
	 */
	vboolean	V_GLOBAL	uiRemoveEvent(vsize_t offset_from_first_push,
		ui_event_p ev_return);
	vboolean	V_GLOBAL	uiRemoveLastEvent(vsize_t offset_from_last_push,
		ui_event_p ev_return);
#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif	/* UI_H */
