#include "intern.h"
#include "INLINE.H"

static int	last_ascii;

static void _redraw_obj(OBJECT *tree, int obj)
{
	GRECT	r;
	
	get_objframe(tree, obj, &r);
#ifdef __MTAES__
	objc_draw(tree, obj, 1, &r);
#else
	objc_draw(tree, obj, 1, r.g_x, r.g_y, r.g_w, r.g_h);
#endif
}

static void set_numbers(int code)
{
	char	str[6];

	sprintf(str, "%03d", code);
	set_string(cf_ascii_tab, AT_DEZ, str);
	_redraw_obj(cf_ascii_tab, AT_DEZ);

	sprintf(str, "0x%02X", code);
	set_string(cf_ascii_tab, AT_HEX, str);
	_redraw_obj(cf_ascii_tab, AT_HEX);
}

static void draw_ascii(int id, int pts)
{
	int	wc, hc, wb, hb, d, i, x, y;
	GRECT	r;
	char	c[2] = "x";
	
	vst_font(cf_vdi_handle, id);
	vst_point(cf_vdi_handle, pts, &wc, &hc, &wb, &hb);
	vst_alignment(cf_vdi_handle, TA_CENTER, TA_TOP, &d, &d);
	vswr_mode(cf_vdi_handle, MD_TRANS);
	vst_color(cf_vdi_handle, 1);

	get_objframe(cf_ascii_tab, AT_BOX, &r);
	set_clipping(cf_vdi_handle, r.g_x, r.g_y, r.g_w, r.g_h, TRUE);
	x = r.g_x + gl_wbox / 2;
	y = r.g_y + 1;
	for (i = 0; i < 256; i++)
	{
		c[0] = i;
		v_gtext(cf_vdi_handle, x, y, c); 
		x += gl_wbox;
		if (((i+1) % 16) == 0)
		{
			y += gl_hbox;
			x = r.g_x + gl_wbox / 2;
		}	
	}
	set_clipping(cf_vdi_handle, r.g_x, r.g_y, r.g_w, r.g_h, FALSE);
}

static int get_ascii(int x, int y)
{
	int	x1, y1;
	
	objc_offset(cf_ascii_tab, AT_BOX, &x1, &y1);
	x -= x1;
	y -= y1;
	if ((x < 0) || (y < 0))
		return -1;

	x /= gl_wbox;
	y /= gl_hbox;
	if ((x < 16) && (y < 16))
		return (x + y * 16);
	else
		return -1;
}

static void select_ascii(int obj)
{
	int	pxy[4], x, y;

	objc_offset(cf_ascii_tab, AT_BOX, &x, &y);
	pxy[0] = x + (obj % 16) * gl_wbox;
	pxy[1] = y + (obj / 16) * gl_hbox;
	pxy[2] = pxy[0] + gl_wbox - 1;
	pxy[3] = pxy[1] + gl_hbox - 1;

	graf_mouse(M_OFF, NULL);
	vsf_color(cf_vdi_handle, BLACK);
	vsf_interior(cf_vdi_handle, FIS_SOLID);
	vswr_mode(cf_vdi_handle, MD_XOR);
	v_bar(cf_vdi_handle, pxy);
	graf_mouse(M_ON, NULL);
}

static void jump_to(int new)
{
	if (last_ascii != -1)
		select_ascii(last_ascii);
	select_ascii(new);
	last_ascii = new;
	set_numbers(new);
}

int ascii_table(int id, int pts)
{
	int	event, mx, my, kstate, kreturn, breturn, bclicks, 
			d, obj, code = -1;
	MFDB	background;
	GRECT	r;
	int	quit;
#ifdef __MTAES__
	GRECT		null = {0,0,0,0};
	GRECT		r3;
	EVNTDATA	ev;
#endif

	set_string(cf_ascii_tab, AT_DEZ, "000");
	set_string(cf_ascii_tab, AT_HEX, "0x00");

	wind_update(BEG_UPDATE);
	wind_update(BEG_MCTRL);
#ifdef __MTAES__
	form_center(cf_ascii_tab, &r);
#else
	form_center(cf_ascii_tab, &r.g_x, &r.g_y, &r.g_w, &r.g_h);
#endif
	save_background(&r, &background);
#ifdef __MTAES__
	form_dial(FMD_START, &null, &r);
#else
	form_dial(FMD_START, 0, 0, 0, 0, r.g_x, r.g_y, r.g_w, r.g_h);
#endif
	graf_mouse(M_OFF, NULL);
#ifdef __MTAES__
	objc_draw(cf_ascii_tab, ROOT, MAX_DEPTH, &r); 
#else
	objc_draw(cf_ascii_tab, ROOT, MAX_DEPTH, r.g_x, r.g_y, r.g_w, r.g_h); 
#endif
	draw_ascii(id, pts); 
	graf_mouse(M_ON, NULL);

	last_ascii = -1;
	quit = FALSE;
#ifdef __MTAES__
	graf_mkstate(&ev);
#else
	graf_mkstate(&mx, &my, &d, &d);
#endif
	do
	{
#ifdef __MTAES__
		r3.g_x = ev.x;
		r3.g_y = ev.y;
		r3.g_w = 1;
		r3.g_h = 1;
		event = evnt_multi((MU_BUTTON|MU_KEYBD|MU_M1),
									1, 1, 1,
									1, &r3,
									0, &null,
									NULL, 0,
									&ev, &kreturn, &bclicks);
		mx = ev.x;
		my = ev.y;
		breturn = ev.bstate;
		kstate = ev.kstate;
#else
		event = evnt_multi(MU_BUTTON|MU_KEYBD|MU_M1,
									1, 1, 1,
									1, mx, my, 1, 1,
									0, 0, 0, 0, 0,
									NULL, 0,
									&mx, &my, &breturn, &kstate, &kreturn, &bclicks);
#endif
		if (event & MU_M1)
		{
			obj = get_ascii(mx, my);
			if ((obj != -1) && (obj != last_ascii))
				jump_to(obj);
		}
		if (event & MU_BUTTON)
		{
			obj = get_ascii(mx, my);
			if (obj != -1)
			{
				code = obj;
				quit = TRUE;
			}
			else
			{
				if (objc_find(cf_ascii_tab, ROOT, MAX_DEPTH, mx, my) == AT_ABBRUCH)
				{
					code = -1;
					quit = TRUE;
				}
				else
					Bconout(2, 7);
			}
		}
		if (event & MU_KEYBD)
		{
			int scan, d;

			scan = kreturn >> 8;
			switch (scan)
			{
				case 0x61:						/* UNDO */
					code = -1;
					quit = TRUE;
					break;
					
				case 0x1C:						/* Return */
				case 0x72:						/* Enter */
					if (last_ascii != -1)
						code = last_ascii;
					else
						code = -1;
					quit = TRUE;
					break;
				
				case 0x47:						/* HOME */
					if (kstate & K_SHIFT)
						jump_to(255);
					else
						jump_to(0);
					break;

				case 0x4F :						/* MagiCMac: anti-HOME */
					jump_to(255);
					break;

				case 0x4B:						/* Left */
					if (last_ascii == -1)
						jump_to(0);
					else
					{
						if (kstate & K_SHIFT)
						{
							d = last_ascii % 16;
							jump_to(last_ascii - d);
						}
						else if (last_ascii > 0)
							jump_to(last_ascii - 1);
					}
					break;

				case 0x4D:						/* Right */
					if (last_ascii == -1)
						jump_to(0);
					else
					{
						if (kstate & K_SHIFT)
						{
							d = last_ascii % 16;
							jump_to(last_ascii + (15 - d));
						}
						else if (last_ascii < 255)
							jump_to(last_ascii + 1);
					}
					break;

				case 0x48:						/* Up */
					if (last_ascii == -1)
						jump_to(0);
					else if (last_ascii > 15)
						jump_to(last_ascii - 16);
					break;
				case 0x50:						/* Down */
					if (last_ascii == -1)
						jump_to(0);
					else if (last_ascii < 240)
						jump_to(last_ascii + 16);
					break;
			}
		}
	}
	while (!quit);

#ifdef __MTAES__
	form_dial(FMD_FINISH, &r, &null);
#else
	form_dial(FMD_FINISH, 0, 0, 0, 0, r.g_x, r.g_y, r.g_w, r.g_h);
#endif
	restore_background(&r, &background);
	wind_update(END_MCTRL);
	wind_update(END_UPDATE);

	return code;
}

void set_asciitable_strings(char *title, char *button)
{
	if (title[0] != EOS)
		set_string(cf_ascii_tab, AT_TITLE, title);
	if (button[0] != EOS)
		set_string(cf_ascii_tab, AT_ABBRUCH, button);
}
