/* This is ButtonBar
 * 09-05-1996
 * (C) 1996 Sander RM SToks
 */

#include <tos.h>
#include <aes.h>
#include <vdi.h>
#include <stdio.h>
#include <string.h>
#include "bar.h"
#include "defines.h"

extern int rc_intersect (GRECT *a, GRECT *b);

int work_in[12], work_out[57], handle, whandle, phys_handle, gl_apid,
	gr_cw, gr_ch, gr_bw, gr_bh, fullx, fully, fullw, fullh,
	b_hor, b_ver, orient;
char cmdlines[MAXBUTTONS][MAXLINE];
GRECT work;

int open_vwork (void)
{
	register int i;
	if ((gl_apid = appl_init()) != -1)
	{
		for (i=1; i<10; work_in[i++] = 1);
		work_in[10] = 2;
		phys_handle = graf_handle (&gr_cw, &gr_ch, &gr_bw, &gr_bh);
		work_in[0]  = handle = phys_handle;

		v_opnvwk (work_in, &handle, work_out);
		return (0);
	}
	else
		return (1);
}


void close_vwork (void)
{
	v_clsvwk (handle);
	appl_exit ();
}


int do_dialog (OBJECT *tree, int first)
{
	GRECT g;
	int ret;
	wind_update (BEG_UPDATE);
	wind_update (BEG_MCTRL);
	form_center (tree, &g.g_x, &g.g_y, &g.g_w, &g.g_h);
	form_dial (FMD_START, 0, 0, 0, 0, g.g_x, g.g_y, g.g_w, g.g_h);
	form_dial (FMD_GROW, g.g_x+g.g_w/2, g.g_y+g.g_y/2, 0, 0, g.g_x, g.g_y, g.g_w, g.g_h);
	objc_draw (tree, ROOT, MAX_DEPTH, g.g_x, g.g_y, g.g_w, g.g_h);
	ret = form_do (tree, first);
	tree[ret].ob_state &= ~SELECTED;
	form_dial (FMD_SHRINK, g.g_x+g.g_w/2, g.g_y+g.g_h/2, 0, 0, g.g_x, g.g_y, g.g_w, g.g_h);
	form_dial (FMD_FINISH, 0, 0, 0, 0, g.g_x, g.g_y, g.g_w, g.g_h);
	wind_update (END_MCTRL);
	wind_update (END_UPDATE);
	return (ret);
}


void draw_button (int i, int s)
{
	int x, y, p[6];
	GRECT r;

	x = i % b_hor;
	y = i / b_hor;
	wind_get (whandle, WF_WORKXYWH, &r.g_x, &r.g_y, &r.g_w, &r.g_h);
	p[0] = x*BUTTONWIDTH + r.g_x;
	p[1] = y*BUTTONHEIGHT + r.g_y;
	p[2] = p[0] + BUTTONWIDTH - 1;
	p[3] = p[1] + BUTTONHEIGHT - 1;
	vsf_color (handle, LWHITE);
	v_bar (handle, p);
	vswr_mode (handle, MD_TRANS);
	vst_color (handle, (cmdlines[i][0] == 255) ? LBLACK : BLACK);
	v_gtext (handle, p[0] + 8 + (s ? 2 : 0), p[1] + 26 + (s ? 2 : 0),
		&cmdlines[i][1]);
	vswr_mode (handle, MD_REPLACE);
	p[0] = (x+1)*BUTTONWIDTH + r.g_x - 2;
	p[1]++;
	p[2] = x*BUTTONWIDTH + r.g_x + 1;
	p[3] = y*BUTTONHEIGHT + r.g_y + 1;
	p[4] = p[2];
	p[5] = p[3] + BUTTONHEIGHT - 2;
	vsl_color (handle, s ? LBLACK : WHITE);
	v_pline (handle, 3, p);
	p[0]++;
	p[1]++;
	p[2] = p[0];
	p[3] = p[5];
	p[4]++;
	vsl_color (handle, s ? WHITE : LBLACK);
	v_pline (handle, 3, p);
}


void redraw (GRECT *dirty, int b)
{
	GRECT r;
	graf_mouse (M_OFF, NULL);
	wind_update (BEG_UPDATE);
	wind_get (whandle, WF_FIRSTXYWH, &r.g_x, &r.g_y, &r.g_w, &r.g_h);
	while (r.g_w && r.g_h)
	{
		if (rc_intersect (dirty, &r))
		{
			int p[4], i;
			p[0] = r.g_x;
			p[1] = r.g_y;
			p[2] = r.g_x + r.g_w - 1;
			p[3] = r.g_y + r.g_h - 1;
			vs_clip (handle, 1, p);
			for (i = 0; i <= b_hor*b_ver; i++)
				draw_button (i, (i == b));
			vs_clip (handle, 0, p);
		}
		wind_get (whandle, WF_NEXTXYWH, &r.g_x, &r.g_y, &r.g_w, &r.g_h);
	}
	wind_update (END_UPDATE);
	graf_mouse (M_ON, NULL);	
}


void do_button (int i)
{
	GRECT d;
	d.g_x = work.g_x + (i % b_hor)*BUTTONWIDTH;
	d.g_y = work.g_y + (i / b_hor)*BUTTONHEIGHT;
	d.g_w = BUTTONWIDTH;
	d.g_h = BUTTONHEIGHT;
	redraw (&d, i);
	if (cmdlines[i][0] != 255) shel_write (SWM_LAUNCH, cmdlines[i][0], 0, &cmdlines[i][8], &cmdlines[i][127]);
	else Bconout (2,7);
	redraw (&d, -1);
}


void sstrcpy (char *dest, const char *src)
{
	if (src != NULL)
		strcpy (dest, src);
	else
		strcpy (dest, "");
}


int parse_file (void)
{
	FILE *bar;
	char line[256];
	int kind, i;

	b_hor = 2;
	b_ver = 10;
	orient = 1;
	for (i = 0; i < MAXBUTTONS; i++)
	{
		cmdlines[i][0] = 255;
		strcpy (&cmdlines[i][1], "Empty");
	}
	if ((bar = fopen ("C:\\BAR.INF", "r")) == NULL)
	{
		fprintf (stderr, "ButtonBar: Couldn't open BAR.INF file\n");
		fclose (bar);
		return (-1);
	}
	fscanf (bar, "%i,%i,%s\n", &b_hor, &b_ver, line);
	if (!strncmp (line, "topleft", 7))
		orient = TOPLEFT;
	else if (!strncmp (line, "topright", 8))
		orient = TOPRIGHT;
	else if (!strncmp (line, "botleft", 7))
		orient = BOTLEFT;
	else if (!strncmp (line, "botright", 8))
		orient = BOTRIGHT;
	else
	{
		fprintf (stderr, "ButtonBar: Parse error in line 1\n");
		fclose (bar);
		return (-2);
	}
	i = 0;
	while (fscanf (bar, "%i,%s", &kind, line) != EOF)
	{
		cmdlines[i][0] = (char) kind;
		sstrcpy (&cmdlines[i][1], strtok (line, ","));
		sstrcpy (&cmdlines[i][8], strtok (NULL, ","));
		sstrcpy (&cmdlines[i][128], strtok (NULL, ","));
		i++;
	}
	fclose (bar);
	return (0);
}


int main (void)
{
	OBJECT *ad_menu, *ad_about;
	int mx, my, btn, kbd, c, clicks, ev_which, quit = 0;
	int msg[8];

	if (open_vwork ())
	{
		fprintf (stderr, "ButtonBar: Couldn't open Virtual Workstation\n");
		return (-1);
	}

	if (!rsrc_load ("BAR.RSC"))
	{
		fprintf (stderr, "ButtonBar: Couldn't load resource file\n");
		return (-2);
	}

	if (parse_file ())
		return (-3);

	wind_get (0, WF_WORKXYWH, &fullx, &fully, &fullw, &fullh);

	if ((whandle = wind_create (0, fullw - b_hor*BUTTONWIDTH,
		 fully, b_hor*BUTTONWIDTH, b_ver*BUTTONHEIGHT + 2)) < 0)
	{
		fprintf (stderr, "ButtonBar: Couldn't create window\n");
		return (-4);
	}

	rsrc_gaddr (R_TREE, MENU, &ad_menu);
	rsrc_gaddr (R_TREE, DABOUT, &ad_about);
	menu_bar (ad_menu, TRUE);
	switch (orient)
	{
	case TOPLEFT:
		wind_open (whandle, 0, fully,
				b_hor*BUTTONWIDTH, b_ver*BUTTONHEIGHT + 2);
		break;
	case TOPRIGHT:
		wind_open (whandle, fullw - b_hor*BUTTONWIDTH, fully,
				b_hor*BUTTONWIDTH, b_ver*BUTTONHEIGHT + 2);
		break;
	case BOTLEFT:
		wind_open (whandle, 0, fullh + fully - b_ver*BUTTONHEIGHT - 2,
				b_hor*BUTTONWIDTH, b_ver*BUTTONHEIGHT + 2);
		break;
	case BOTRIGHT:
		wind_open (whandle, fullw - b_hor*BUTTONWIDTH, fullh + fully - b_ver*BUTTONHEIGHT - 2,
				b_hor*BUTTONWIDTH, b_ver*BUTTONHEIGHT + 2);
	}
	wind_set (whandle, WF_BEVENT, 1, 0, 0, 0);
	wind_get (whandle, WF_WORKXYWH, &work.g_x, &work.g_y, &work.g_w, &work.g_h);
	redraw (&work, -1);
	graf_mouse (ARROW, 0L);
	while (!quit)
	{
		ev_which = evnt_multi (MU_KEYBD|MU_BUTTON|MU_MESAG, 1, 1, 1,
				   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, msg, 0, 0,
				   &mx, &my, &btn, &kbd, &c, &clicks);
		if (ev_which & MU_MESAG) switch (msg[0])
		{
		case MN_SELECTED:
			switch (msg[4])
			{
			case ABOUT:
				do_dialog (ad_about, 0);
				menu_tnormal (ad_menu, BAR, 1);
				break;
			case RELOAD:
				if (parse_file ()) return (-3);
				switch (orient)
				{
				case TOPLEFT:
					wind_set (whandle, WF_CURRXYWH, 0, fully,
						b_hor*BUTTONWIDTH, b_ver*BUTTONHEIGHT + 2);
					break;
				case TOPRIGHT:
					wind_set (whandle, WF_CURRXYWH, fullw - b_hor*BUTTONWIDTH, fully,
						b_hor*BUTTONWIDTH, b_ver*BUTTONHEIGHT + 2);
					break;
				case BOTLEFT:
					wind_set (whandle, WF_CURRXYWH, 0, fullh + fully - b_ver*BUTTONHEIGHT - 2,
						b_hor*BUTTONWIDTH, b_ver*BUTTONHEIGHT + 2);
					break;
				case BOTRIGHT:
					wind_set (whandle, WF_CURRXYWH, fullw - b_hor*BUTTONWIDTH, fullh + fully - b_ver*BUTTONHEIGHT - 2,
						b_hor*BUTTONWIDTH, b_ver*BUTTONHEIGHT + 2);
				}
				wind_get (whandle, WF_WORKXYWH, &work.g_x, &work.g_y, &work.g_w, &work.g_h);
				redraw (&work, -1);
				menu_tnormal (ad_menu, MFILE, 1);
				break;
			case QUIT:
				quit = TRUE;
				menu_tnormal (ad_menu, MFILE, 1);
				break;
			}
			break;
		case WM_REDRAW:
			redraw ((GRECT *)&msg[4], -1);
			break;
		case WM_TOPPED:
			wind_set (whandle, WF_TOP);
			break;
		}

		if (ev_which & MU_BUTTON)
		{
			if ((mx > work.g_x) && (mx < work.g_x + work.g_w)
			 && (my > work.g_y) && (my < work.g_y + work.g_h))
			{
				int i = b_hor * ((my - work.g_y) / BUTTONHEIGHT)
					  + (mx - work.g_x) / BUTTONWIDTH;
				do_button (i);
			}
			else
				Bconout (2,7);	/* Ping! */
		}

		if (ev_which & MU_KEYBD) switch (c & 0xFF)
		{
		case CNTRL_Q:
			quit = TRUE;
			break;
		}
	}
	wind_new ();
	menu_bar (ad_menu, FALSE);
	rsrc_free ();
	close_vwork ();
	return (0);
}