#ifndef	ARCH_WINLIB_COMMON_H
#define	ARCH_WINLIB_COMMON_H

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

	/* key & mouse buttons press or release events */
	ui_key_event,

	/* there is no special event for this type */
	ui_pointer_motion_event,

	/* generic type: configure_window_event_t */
	ui_window_focus_in_event,
	ui_window_focus_out_event,
	ui_window_expose_event,
	ui_window_map_event,
	ui_window_unmap_event,
	ui_window_move_event,
	ui_window_size_event,

	/* got message from window manager */
	ui_wm_event,

	ui_max_event
}	ui_event_type_t;

/*
 * Scancodes for "Windows" PC keyboard + 3-button mouse
 *
 * Stored in ui_key_event_t -> 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;

/*
 * 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,

	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 ch;	/* 8-bit character code for current locale */
	unsigned unicode;	/* 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 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.
	 */
	vec_t	time;
	int		client_x, client_y; /* mouse pointer position */
	int		client_dx, client_dy; /* mouse pointer deltas */
	int		screen_x, screen_y; /* pointer position in screen coords */
	unsigned button; /* mouse buttons */
	unsigned state; /* keyboard modifiers */
	ui_key_event_t key;
	ui_configure_event_t configure;
}	ui_event_t, *ui_event_p;

DEQUE_STRUCT(event,ui_event_t)

DECLARE_DEQUE_API(event,V_CALL,ui_event_t)

typedef struct vidmode_s
{
	u32_t	width;
	u32_t	height;
	u32_t	bpp;		/* set correctly but not used under X11 */
	u32_t	refresh;	/* set correctly but not used under X11 */
	int		modeline;	/* not used under Win32 (FIXME - also needless under X11) */
}	vidmode_t, *vidmode_p;

#define	MAX_WINDOW_TITLE	128

#define	ARCH_COMMON_WINDOW_FIELDS \
	char	title[MAX_WINDOW_TITLE]; /* caption */ \
	u32_t	x, y; /* [left,top] */ \
	u32_t	width, height; \
	/* X11 - time of 1st input msg; Win32 - time of wnd creation */ \
	unsigned start_time; \
	vboolean focused; /* affected by winsystem | archWinFocus() */ \
	vboolean visible; /* affected by winsystem | archWinShow() */ \
	int pointer_hide_count; /* affected by archWinShowPointer() */ \
	int ms_grab_count; /* affected by archWinGrabMouse() */ \
	int kb_grab_count; /* affected by archWinGrabKeyboard() */ \
	int	current_vidmode; /* affected by archWinSetVidMode() */ \
	int saved_pointer_hide_count; /* affected by ui_win_loose_control() */ \
	int saved_ms_grab_count; /* affected by ui_win_loose_control() */ \
	int saved_kb_grab_count; /* affected by ui_win_loose_control() */ \
	int	saved_vidmode; /* affected by ui_win_loose_control() */ \
	/* last ms coords, client space, as returned by windowing system */ \
	int	last_mx, last_my; \
	/* last ms coords, client space, as tracked by library */ \
	int last_vmx, last_vmy; \
	unsigned last_key_state; /* keyboard modifiers of last input msg */ \
	unsigned last_button_state; /* mouse btns of last mouse msg */ \
	vboolean auto_repeat_disabled; /* !filter autorepeated keys */ \
	/* mouse pointer hidden, 'infinite' mouse mode */ \
	vboolean auto_warp_enabled; \
	int	auto_warp_saved_x, auto_warp_saved_y; \
	vboolean zap_next_mousemove; /* eat next MouseMove msg */ \
	u8_t keyboard_state[sc_maxcode]; /* 0 if sc_XXX key is released */ \
	event_deque_p msg_que; /* message deque */

#define	INIT_COMMON_WINDOW_FIELDS(winobj) \
	(winobj)->title[0] = 0; \
	(winobj)->x = (winobj)->y = 0; \
	(winobj)->width = (winobj)->height = 256; \
	(winobj)->start_time = 0; \
	(winobj)->visible = false; \
	(winobj)->focused = false; \
	(winobj)->pointer_hide_count = 0; \
	(winobj)->ms_grab_count = 0; \
	(winobj)->kb_grab_count = 0; \
	(winobj)->current_vidmode = -1; \
	(winobj)->saved_pointer_hide_count = 0; \
	(winobj)->saved_ms_grab_count = 0; \
	(winobj)->saved_kb_grab_count = 0; \
	(winobj)->saved_vidmode = -1; \
	(winobj)->auto_warp_enabled = false; \
	(winobj)->last_mx = (winobj)->last_my = 0; \
	(winobj)->last_key_state = (winobj)->last_button_state = 0; \
	(winobj)->auto_repeat_disabled = false; \
	(winobj)->zap_next_mousemove = false; \
	memZero((winobj)->keyboard_state,sc_maxcode); \
	(winobj)->msg_que = NULL;

#define	CLEAR_COMMON_WINDOW_FIELDS(winobj) \
	eventDeqFree((winobj)->msg_que); \
	(winobj)->msg_que = NULL;

/*
 * We need complete definition of arch_window_t even for
 * portable part of windowing library.
 */
#ifdef	__WIN32__
#include "../win32/winlib.h"
#else	/* !__WIN32__ */
#include "../generic/winlib.h"
#endif	/* !__WIN32__ */

#ifdef	__cplusplus
extern "C" {
#endif
	/*
	 * Window management
	 */
	arch_window_p	V_CALL	archWinOpenNP(void_p osd_parent,void_p visinfo,
		char *title,u32_t left,u32_t top,u32_t width,u32_t height,
		vboolean caption, /* if false - set WS_POPUP | OverrideRedirect */
		vboolean allow_resize);
	void		V_CALL	archWinClose(arch_window_p aw);
	/* set mode_num to -1 for default mode */
	vboolean	V_CALL	archWinSetVidMode(arch_window_p aw,int mode_num);
	/* window configuration */
	vboolean	V_CALL	archWinShow(arch_window_p aw,vboolean show);
	void		V_CALL	archWinFocus(arch_window_p aw);
	vboolean	V_CALL	archWinMove(arch_window_p aw,s32_t x,s32_t y);
	vboolean	V_CALL	archWinSize(arch_window_p aw,s32_t width,s32_t height);
	/*
	 * Mouse pointer helper functions
	 */
	vboolean	V_CALL	archWinWarpPointer(arch_window_p aw,s32_t x,s32_t y);
	/* Returns 'true' if cursor is visible at exit. */
	vboolean	V_CALL	archWinShowPointer(arch_window_p aw,vboolean show);
	void		V_CALL	archWinGrabMouse(arch_window_p aw,vboolean grab);
	void		V_CALL	archWinGrabKeyboard(arch_window_p aw,vboolean grab);
	/* enables or disables keyboard autorepeat */
	void		V_CALL	archWinAutoRepeat(arch_window_p aw,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_CALL	archWinAutoWarp(arch_window_p aw,vboolean enable);
	/*
	 * Message queue management
	 */
	void		V_CALL	archWinPoll(arch_window_p wnd,vboolean block);
	/*
	 * archWinWaitMessages()
	 * Waits for events, but not longer than 'timeout' milliseconds.
	 * Retuns immediately with 'true' if there is at least one event pending.
	 * Returns 'false' if no event received within 'timeout'.
	 * Pass -1 as timeout for infinite wait.
	 */
	vboolean V_CALL	archWinWaitMessages(int timeout);
	/* Common stuff */
	vboolean V_CALL	ui_default_wnd_proc(arch_window_p aw,ui_event_p ev);
	void	V_CALL	ui_win_loose_control(arch_window_p aw,vboolean hiding);
	void	V_CALL	ui_make_default_key_event(ui_key_event_p ev);
	void	V_CALL	ui_set_configure_from_aw(arch_window_p aw,ui_configure_event_p ev);
	vec_t	V_CALL	ui_make_message_time(unsigned *start,unsigned current);
	/*
	 * Conversion between scancodes and their names.
	 * The name formed by striping "sc_" prefix.
	 */
	char_p		V_GLOBAL	uiKeyscan2Name(unsigned scan);
	unsigned	V_GLOBAL	uiName2Keyscan(char *name);
	/* BEGIN gl_common.h */
	/*
	FIXME - STUBS
	 * Event management functions (all functions assume that
	 * current GL context for calling thread is valid.
	 */
	/*
	 * Returns number of events waiting in queue of active GL
	 * window. Polls the system queue, but _never_ blocks.
	 */
	vboolean V_GLOBAL	uiPending(void);
	/*
	 * Removes all messages from queues (both from system and
	 * window's), never blocks.
	 */
	void V_GLOBAL	uiFlushQueue(void);
	/*
	 * 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);
	/*
	 * Removes the oldest event waiting in queue of active GL
	 * window. Polls the system queue and _may_ block.
	 */
	vboolean	V_GLOBAL	uiNextEvent(ui_event_p ev_return);
#ifdef	__cplusplus
}
#endif

#endif	/* !ARCH_WINLIB_COMMON_H */
