#ifndef	ARCH_WINLIB_H
#define	ARCH_WINLIB_H

#define CONFIG_ENABLE_AUTOREPEAT	1

typedef struct
{
	u8_t r,g,b,a;
}	colorquad_t, *colorquad_p;

typedef struct vidmode_s
{
	u32_t	width;
	u32_t	height;
	u32_t	bpp;
	u32_t	refresh;
	int		modeline; /* not used under Win32 */
}	vidmode_t, *vidmode_p;

typedef enum
{
	ui_event_redraw,
	ui_event_activate,
	ui_event_close,
	ui_event_move,
	ui_event_size,
	ui_event_key_down,
	ui_event_key_up,
	ui_event_mouse_move,
	
	ui_event_unknown, /* never posted to message queue */

	ui_max_event
}	ui_event_t;

#define	UI_MESSAGE_MAX_CODES	4

typedef struct ui_message_s
{
	ui_event_t	event;
	vec_t		time; /* time of posting in seconds since window creation */
	vboolean	removed; /* == true after archPeekEvent(...,remove = true) */
	s32_t		code[UI_MESSAGE_MAX_CODES];
}	ui_message_t, *ui_message_p;

#define	MSG_SET_EMPTY(msg) \
	memZero(msg,sizeof(*(msg))); \
	(msg)->event = ui_event_unknown; \
	(msg)->removed = false;

#define	MSG_EVENT(msg)		((msg)->event)
#define	MSG_TIME(msg)		((msg)->time)

/* ui_event_redraw */
#define	MSG_DRAW_LEFT(msg)	((msg)->code[0])
#define	MSG_DRAW_TOP(msg)	((msg)->code[1])
#define	MSG_DRAW_RIGHT(msg)	((msg)->code[2])
#define	MSG_DRAW_BOTTOM(msg)	((msg)->code[3])

/* ui_event_activate */
#define	MSG_WIN_ACTIVE(msg)	((msg)->code[0])

/* ui_event_move */
#define	MSG_WIN_LEFT(msg)	((msg)->code[0])
#define	MSG_WIN_TOP(msg)	((msg)->code[1])

/* ui_event_size */
#define	MSG_WIN_WIDTH(msg)	((msg)->code[0])
#define	MSG_WIN_HEIGHT(msg)	((msg)->code[1])

/* ui_event_key_down, ui_event_key_up */
#define	MSG_KEY_CODE(msg)	((msg)->code[0])
#define	MSG_KEY_CHAR(msg)	((msg)->code[1])
#define	MSG_KEY_FLAGS(msg)	((msg)->code[2])
#define	MSG_KEY_LOCALE(msg)	((msg)->code[3])
/*
 * FIXME: the flags below must not conflict with other key definitions;
 * prefix them with ARCH_ ?
 */
#define	MSG_KEY_RMETA		(1 << 0)
#define	MSG_KEY_LMETA		(1 << 1)
#define	MSG_KEY_RCONTROL	(1 << 2)
#define	MSG_KEY_LCONTROL	(1 << 3)
#define	MSG_KEY_RSHIFT		(1 << 4)
#define	MSG_KEY_LSHIFT		(1 << 5)
#define	MSG_KEY_CAPS		(1 << 6)
#define	MSG_KEY_SCROLL		(1 << 7)
#define	MSG_KEY_NUM			(1 << 8)
#define	MSG_KEY_LMOUSE		(1 << 9)
#define	MSG_KEY_MMOUSE		(1 << 10)
#define	MSG_KEY_RMOUSE		(1 << 11)
#define	MSG_KEY_WAS_DOWN	(1 << 16)	/* ui_event_key_down only */

#define	MSG_LOCALE_EN		0
#define	MSG_LOCALE_RU		1

/* ui_event_mouse_move */
#define	MSG_MOUSE_X(msg)	((msg)->code[0])
#define	MSG_MOUSE_Y(msg)	((msg)->code[1])

/*
 * The default handler should pass untranslated message
 * to 'before_process' (if non-NULL). If later returns
 * true, no further processing required. Otherwise,
 * message should be translated to the arch - independent
 * form and default processing have to be carried out.
 * Than default handles should call 'after_process'; if
 * later returns 'false', translated message have to be
 * stored in queue.
 */

#define	MAX_WINDOW_TITLE	128

#define	ARCH_WINDOW_MAGIC	0x41574E44 /* AWND */

#define	ARCH_COMMON_WINDOW_FIELDS \
	u32_t	magic; \
	vboolean (*before_process)(struct arch_window_s *self,void_p arch_raw_message); \
	vboolean (*after_process)(struct arch_window_s *self,ui_message_p new_msg); \
	DEFINE_TREE_LINK(struct arch_window_s) \
	char	title[MAX_WINDOW_TITLE]; \
	u32_t	left, top; \
	u32_t	width, height; \
	vboolean visible; \
	vboolean clears; \
	vboolean active; \
	vboolean pointer_captured; \
	int pointer_hide_count; \
	vboolean auto_warp_pointer; \
	vboolean keyboard_captured; \
	vidmode_p vidmodes; \
	u32_t	num_vidmodes; \
	int		current_vidmode; /* affected by archWinSetVideoMode() */ \
	int		vidmode_on_activate; /* _not_ affected by archWinSetVideoMode() */ \
	fifo_t	messages; /* fixme: replace with deque */

#define	INIT_COMMON_WINDOW_FIELDS(winobj,parent) \
	(winobj)->magic = ARCH_WINDOW_MAGIC; \
	(winobj)->before_process = NULL; \
	(winobj)->after_process = NULL; \
	LINK_TREE_NODE(winobj,parent); \
	(winobj)->title[0] = 0; \
	(winobj)->left = (winobj)->top = 0; \
	(winobj)->width = (winobj)->height = 256; \
	(winobj)->visible = false; \
	(winobj)->clears = true; \
	(winobj)->active = false; \
	(winobj)->pointer_captured = false; \
	(winobj)->pointer_hide_count = 0; \
	(winobj)->auto_warp_pointer = false; \
	(winobj)->keyboard_captured = false; \
	(winobj)->vidmodes = NULL; \
	(winobj)->num_vidmodes = 0; \
	(winobj)->current_vidmode = -1; \
	(winobj)->vidmode_on_activate = -1; \
	/* fixme: replace this with deque */ \
	fifoInit(&(winobj)->messages,sizeof(ui_message_t));

#define	CLEAR_COMMON_WINDOW_FIELDS_EXCEPT_LINK(winobj) \
	fifoClear(&(winobj)->messages); \
	if((winobj)->vidmodes) \
		memFree((winobj)->vidmodes);

#define	VALID_ARCH_WINDOW(aw) \
	((aw) && memIsPointer(aw) && (aw)->magic == ARCH_WINDOW_MAGIC)

/*
 * Include arch-specific config macros and data types.
 * FIXME: is the place for this correct ?
 */
#if		defined(__UNIX__)
#include <../arch/generic/winlib.h>
#elif	defined(__WIN32__)
#include <../arch/win32/winlib.h>
#else
#error	"Unknown platform !"
#endif

#ifdef	__cplusplus
extern "C" {
#endif
	/*
	 * Window management
	 */
	arch_window_p	V_CALL	archWinOpen(arch_window_p parent,
		char *title,char *icon_id,s32_t left,s32_t top,s32_t width,s32_t height,
		vboolean caption,vboolean allow_resize);
	/*
	 * Video mode management
	 */
	vidmode_p	V_CALL	archWinGetVideoMode(arch_window_p aw,int mode_num);
	/* set mode_num to -1 for default mode */
	vboolean	V_CALL	archWinSetVideoMode(arch_window_p aw,int mode_num,
		colorquad_p palette_opt);
	vboolean	V_CALL	archWinShow(arch_window_p aw,vboolean show);
	void		V_CALL	archWinFocus(arch_window_p aw);
	vboolean	V_CALL	archWinPending(arch_window_p aw);
	vboolean	V_CALL	archWinNextMessage(arch_window_p aw,ui_message_p msg_ret);
	vboolean	V_CALL	archWinResize(arch_window_p aw,s32_t width,s32_t height);
	vboolean	V_CALL	archWinMove(arch_window_p aw,s32_t left,s32_t top);
	/*
	 * Mouse pointer helper functions
	 */
	vboolean	V_CALL	archWinWarpPointer(arch_window_p aw,s32_t x,s32_t y);
	vboolean	V_CALL	archWinShowPointer(arch_window_p aw,vboolean show);
	void		V_CALL	archWinCapturePointer(arch_window_p aw,vboolean capture);

	void		V_CALL	archWinClose(arch_window_p aw);
#ifdef	__cplusplus
}
#endif

/*
 * FIXME: rename and move to another header
 */
char_t	V_GLOBAL	inputKeycodeToChar2(ui_message_p msg);

#endif	/* !ARCH_WINLIB_H */
