#include <stdio.h>
#include <ctype.h>

#include "Xm/Form.h"
#include "Xm/Label.h"
#include "Xm/ScrolledW.h"
#include "Xm/PushB.h"
#include "Xm/Text.h"

#include "ArgPack.h"
#include "alfonts.h"
#include "menupack.h"
#include "xstuff.h"
#include "alpop.h"
#include "registry.h"
#include "data.h"
#include "dataP.h"
#include "argusi.h"

static Widget	main_shell;
static Bool	MODIFIED = Bool_FALSE;
static Registry plug_widgets;
static Bool	save_abort = Bool_FALSE;
static char	err_string[AE_MAX_STRING];
static XmFontList	fonts;

NORET
AE_get_label_string_from_option_menu(opt_menu, text)
Widget	opt_menu;
char	**text;
{
	Widget		w;
	XmString	label_s;

	w = (Widget)Alxt_get_widget_feature(opt_menu, XmNmenuHistory);
	label_s = (XmString)Alxt_get_widget_feature(w, XmNlabelString);
	if(XmStringGetLtoR(label_s, XmSTRING_DEFAULT_CHARSET, text) == FALSE)
		Al_fatal_error("Could not get label name from compound string.");
}

/* The purpose of the following function is to work around a bug in the current
   (8/89) dateparser.  The symptom thus far: 88140 seconds are subtracted from
   the correct time if the year in full form (eg. 1989) appears at the end
   of the date string; 19740 seconds are subtracted if the year in decade form
   (eq. 89) appears.  The function sees if either of these conditions exists
   and makes the apropriate addition if so.
*  The function returns success if it was able to correct or no corrections
*  were made.  It returns failure if the correction it tried failed.
*/
Bool
AE_work_around_year_bug(date, t)
char	*date;
time_t	*t;
{
	char	*c,
		*d,
		tc;
	time_t	tt;

	c = (char *)(strlen(date) + (int)date);
	while(isspace(*--c) && c > date)
		;
	d = c;
	while(isdigit(*c) && c-- > date)
		;
	c++;
	if(d - c != 1 && d - c != 3)	/* form 89 or form 1989 */
		return Bool_TRUE;
	tt = *t;
	if(d - c == 1 && atoi(c) > 59)	/* just the way it is */
	{	tt += 19740L;
		tc = *c;
		*c = '\0';
		if(tt != getdate(date, 0))
		{	*c = tc;
			return Bool_FALSE;
		}
		*c = tc;
		*t = tt;
	}
	else if(atoi(c) > 1959 && atoi(c) < 2000)/* those could be legal hours */
	{	tt += 88140L;
		tc = *c;
		*c = '\0';
		if(tt != getdate(date, 0))
		{	*c = tc;
			return Bool_FALSE;
		}
		*c = tc;
		*t = tt;
	}
	return Bool_TRUE;
}
	

NORET
AE_plug_in(a0, a1, a2)
VOIDP	a0,
	a1,
	a2;
{
	Widget	w = (Widget)a0;
	Socket	sock = (Socket)a1;
	Update	*update_which = (Update *)a2;
	char	*label,
		*text;
	time_t	t;
	EntCode	plug;
	short	i;
	
	if(save_abort == Bool_TRUE)
		return;
	if(XtIsManaged(w) == FALSE ||		/* For text/optmenu that is */
	   XtIsManaged(XtParent(w)) == FALSE)	/* currently in use */
		return;
	plug = sock->patch;
	switch(sock->type) 
	{
	case AE_ON_OFF:
		AE_get_label_string_from_option_menu(w, &label);
		AE_chord_changes[plug].enabled = (strcmp(label, "Off") ? 
						   Bool_TRUE : Bool_FALSE);
		break;
	case AE_START_TEXT:
		text = XmTextGetString(w);
		if((t = getdate(text, NULL)) == -1)
		{	sprintf(err_string,
				"Cannot parse date: %s\nPlease enter a new date\n(No changes will be saved)", 
				text);
			AlPop_Query(ALPOP_ERROR, err_string, (char *)NULL, w,
				    ALPOP_HANG_BELOW,
				    XtDisplay(w), ALPOP_OK);
			save_abort = Bool_TRUE;	/* need a better way */
			return;
		}
		if(AE_work_around_year_bug(text, &t) == Bool_FALSE)
		{	sprintf(err_string,
				"The date parser might be incorrectly parsing the date %sIt thinks the date is %sIf this is incorrect please press cancel and adjust the date\nby the incorrect amount.\nOtherwise press O.K. to continue saving",
				text, ctime(&t));
			if((int)AlPop_Query(ALPOP_WARNING, err_string, (char *)NULL,
					    w, ALPOP_HANG_BELOW,
					    XtDisplay(w),
					    ALPOP_OK | ALPOP_CANCEL) == 2)
			{	save_abort = Bool_TRUE;
				return;
			}
		}
		XtFree(text);
		AE_chord_changes[plug].start = t;
		if(update_which[plug] == AE_UPINTVL)
			AE_chord_changes[plug].data = 
			  AE_chord_changes[plug].stop - t;
		else if(update_which[plug] == AE_UPSTOP)
			AE_chord_changes[plug].stop = 
			  AE_chord_changes[plug].data + t;
		else
			update_which[plug] = AE_UPEITHER;
		break;
	case AE_STOP_TEXT:
		text = XmTextGetString(w);
		if((t = getdate(text, NULL)) == -1)
		{	sprintf(err_string,
				"Cannot parse date: %s\nPlease enter a new datee\n(No changes will be saved)", 
				text);
			AlPop_Query(ALPOP_ERROR, err_string, (char *)NULL, w,
				    ALPOP_HANG_BELOW,
				    XtDisplay(w),
				    ALPOP_OK);
			save_abort = Bool_TRUE;	/* need a better way */
			return;
		}
		if(AE_work_around_year_bug(text, &t) == Bool_FALSE)
		{	sprintf(err_string,
				"The date parser might be incorrectly parsing the date %sIt thinks the date is %sIf this is incorrect please press cancel and adjust the date\nby the incorrect amount.\nOtherwise press O.K. to continue saving",
				text, ctime(&t));
			if((int)AlPop_Query(ALPOP_WARNING, err_string, (char *)NULL,
					    w, ALPOP_HANG_BELOW,
					    XtDisplay(w),
					    ALPOP_OK | ALPOP_CANCEL) == 2)
			{	save_abort = Bool_TRUE;
				return;
			}
		}
		XtFree(text);
		AE_chord_changes[plug].stop = t;
		if(update_which[plug] == AE_UPEITHER)
			AE_chord_changes[plug].data = 
			  t - AE_chord_changes[plug].start;
		else
			update_which[plug] = AE_UPINTVL;
		break;
	case AE_STOP_INTVL:
		AE_get_label_string_from_option_menu(w, &label);
		for(i = 0; i < AE_NUM_OPTS -1; i++)
			if(!strcmp(label, AlAE_int_opts_vals[i].opt))
			{	AE_chord_changes[plug].data = 
				  AlAE_int_opts_vals[i].val;
				break;
			}
		if(update_which[plug] == AE_UPEITHER)
			AE_chord_changes[plug].stop = 
			  AE_chord_changes[plug].start + 
			  AE_chord_changes[plug].data;
		else
			update_which[plug] = AE_UPSTOP;
	}
	
}

/* Bellow we check the new chords against the ones read in to see what needs
 * to be plugged in.  Interface to AlData routines used by old lensdc.
 */
NORET
AE_change_changed()
{
	EntCode	i;

	for(i = 0; i < PLUGS; i++)
	{	if(AE_chord_changes[i].enabled != AlDC_plugs[i].enabled)
		{	if(AlDC_plugs[i].enabled == Bool_TRUE)
				AlData_general_disable(i);
			else
				AlData_general_enable(i);
		
		}
		if(AE_chord_changes[i].start == AlDC_plugs[i].start &&
		   AE_chord_changes[i].data == AlDC_plugs[i].data)
			continue;
		AlData_periodic_col_change(AlDC_plugs[i].start = 
					   AE_chord_changes[i].start, i);
		AlDC_plugs[i].stop = AE_chord_changes[i].stop;
		AlDC_plugs[i].data = AE_chord_changes[i].data;
	}
}

void
AEC_quit(w)
Widget	w;
{
	if(MODIFIED == Bool_TRUE)
	{	short	b;

		b = (short)AlPop_Query(ALPOP_WARNING, "No Save since last modification.\nQuit anyway?",
				       (char *)NULL, w, ALPOP_HANG_BELOW,
				       XtDisplay(w),
				       ALPOP_OK | ALPOP_CANCEL);
		if(b != 1)
			return;
		/*** Should do something for save-then-quit functionality */
	}
	XtDestroyWidget(main_shell);
	exit(0);
}

void
AEC_save(w)
Widget	w;
{
	int	update_which[PLUGS];	/* used by traverse proc */

	if(MODIFIED == Bool_FALSE)
		 if((int)AlPop_Query(ALPOP_QUESTION, "No changes need to be saved.\nPress O.K. if you want to save anyway\nPress Cancel otherwise",
				(char *)NULL, w, ALPOP_HANG_BELOW,
				     XtDisplay(w),
				     ALPOP_OK | ALPOP_CANCEL) != 1)
			return;
	bzero((char *)update_which, sizeof(int)*PLUGS);
	Registry_traverse(plug_widgets, (Registry_ActionProc)AE_plug_in, 
			  (VOIDP)update_which);
	if(save_abort == Bool_TRUE)
	{	save_abort = Bool_FALSE;
		return;
	}
	AE_change_changed();
	if(AlData_save_state() == Bool_FALSE)
		AlPop_Query(ALPOP_ERROR, "Save failed, reason unknown",
			    (char *)NULL, w, ALPOP_HANG_BELOW,
			    XtDisplay(w), ALPOP_OK);
	else
		MODIFIED = Bool_FALSE;
}

void
AEC_int_other(w, cl)
Widget	w;
caddr_t	cl;
{
	Widget	to_manage = (Widget)cl;

	/* unmanage the outer label; button->row_col->containing_form */
	XtUnmanageChild(XtParent(XtParent(XtParent(w))));
	XtManageChild(to_manage);
}

void
AEC_parse_text(w)
Widget w;
{
	time_t	t;
	char	*to_free;

	t = getdate(to_free = XmTextGetString(w), 0);	
	if(t == -1)
	{	sprintf(err_string, 
			"Cannot parse date: %s\nPlease Change", to_free);
		AlPop_Query(ALPOP_ERROR, err_string, (char *)NULL, w,
			    ALPOP_HANG_BELOW,
			    XtDisplay(w), ALPOP_OK);
	}
	XtFree(to_free);
}

void
AEC_text_editable(w, cl)
Widget	w;
caddr_t	cl;
{
	Boolean	editable = (Boolean)cl;

	Alxt_SetArg(w, XmNeditable, (XtArgVal)editable);
}

void
AEC_set_modify()
{
	MODIFIED = Bool_TRUE;
}

Widget
AE_create_main_form(parent)
Widget	parent;
{
	Widget	form;

	form = XmCreateForm(parent, "Main Form", main_form_res, 
			     XtNumber(main_form_res));
	return form;
}

Widget
AE_create_title_bar(form)
Widget	form;
{
	Widget	title_bar,
		title,
		sub_title;
	ArgPack	argp = ArgPack_create();

	title_bar = XmCreateForm(form, "Title Bar Form", title_bar_res,
				 XtNumber(title_bar_res));

	ArgPack_add_arg(argp, XmNalignment, (XtArgVal)XmALIGNMENT_BEGINNING);
	ArgPack_add_arg(argp, XmNfontList, (XtArgVal)fonts);
	ArgPack_add_arg(argp, XmNlabelString, 
			(XtArgVal)XmStringCreate("ArgusEye",
						 ALFONTS_MAJOR_HEADING));
	title = XmCreateLabel(title_bar, "Main-heading-label",
			      ArgPack_the_args(argp),
			      ArgPack_num_args(argp));
	ArgPack_delete(argp);

	argp = ArgPack_create();
	ArgPack_add_arg(argp, XmNleftAttachment, (XtArgVal)XmATTACH_WIDGET);
	ArgPack_add_arg(argp, XmNleftWidget, (XtArgVal)title);
	ArgPack_add_arg(argp, XmNleftOffset, (XtArgVal)15);
	ArgPack_add_arg(argp, XmNtopAttachment, (XtArgVal)XmATTACH_FORM);
	ArgPack_add_arg(argp, XmNtopOffset, (XtArgVal)10);
	ArgPack_add_arg(argp, XmNalignment, (XtArgVal)XmALIGNMENT_END);
	ArgPack_add_arg(argp, XmNfontList, (XtArgVal)fonts);
	ArgPack_add_arg(argp, XmNlabelString, 
			(XtArgVal)XmStringCreate("Application for controlling Data Collection",
						 ALFONTS_MINOR_HEADING));
	sub_title = XmCreateLabel(title_bar, "Minor-heading-label",
				  ArgPack_the_args(argp),
				  ArgPack_num_args(argp));
	ArgPack_delete(argp);
				  
	XtManageChild(title);
	XtManageChild(sub_title);
	XtManageChild(title_bar);
	return(title_bar);
}

Widget
AE_create_on_off_opt(form, code)
Widget	form;
EntCode	code;
{
	Widget		wrap;
	MenuPack	mp;
	Socket		sock;

	wrap = XmCreateForm(form, "On/Off Form", (ArgPack)NULL, 0);
	
	mp = MenuPack_create_option(wrap, "on_off_opt", "on_off_choice");
	MenuPack_add_option("On", mp, AEC_set_modify, (caddr_t)NULL, 
			    (ArgPack)NULL);
	MenuPack_add_option("Off", mp, AEC_set_modify, (caddr_t)NULL, 
			    (ArgPack)NULL);
	MenuPack_make_menu(mp);
	Alxt_SetArg(MenuPack_option_get_label(mp), XmNlabelString,
		    (XtArgVal)XmStringCreate("", XmSTRING_DEFAULT_CHARSET));
	MenuPack_set_as_default(mp, AlDC_plugs[code].enabled == Bool_TRUE ?
				"On" : "Off");
	
	sock = (Socket)Memory_allocate(sizeof(SocketSt));
	sock->type = AE_ON_OFF;
	sock->patch = code;
	Registry_add(plug_widgets, (VOIDP)MenuPack_get_top_level_manager(mp),
		     (VOIDP)sock);
	MenuPack_destroy(mp);
	XtManageChild(wrap);
	return wrap;
}

Widget
AE_create_cat_label(form, attach_w, code)
Widget	form,
	attach_w;
EntCode	code;
{
	Widget	cat_l;
	ArgPack	argp = ArgPack_create();
	char	str[64];
		
	assert(form);
	assert(attach_w);

	ArgPack_add_arg(argp, XmNleftAttachment, (XtArgVal)XmATTACH_WIDGET);
	ArgPack_add_arg(argp, XmNleftWidget, (XtArgVal)attach_w);

	ArgPack_add_arg(argp, XmNalignment, (XtArgVal)XmALIGNMENT_END);
	ArgPack_add_arg(argp, XmNwidth, (XtArgVal)140);
	sprintf(str, "%55s  Start:", AlData_CTGRS[code]);
	cat_l = XmCreateLabel(form, str, ArgPack_the_args(argp),
			      ArgPack_num_args(argp));

	ArgPack_delete(argp);
	XtManageChild(cat_l);
	return(cat_l);
}

Widget
AE_create_int_label(form, attach_w)
Widget	form,
	attach_w;
{
	Widget	int_l;
	ArgPack	argp = ArgPack_create();
		
	ArgPack_add_arg(argp, XmNleftAttachment, (XtArgVal)XmATTACH_WIDGET);
	ArgPack_add_arg(argp, XmNleftWidget, (XtArgVal)attach_w);
	int_l = XmCreateLabel(form, "Interval: ", ArgPack_the_args(argp),
			      ArgPack_num_args(argp));
	ArgPack_delete(argp);
	XtManageChild(int_l);
	return(int_l);
}

Widget
AE_create_time_text(form, attach_w, code, kind)
Widget	form,
	attach_w;
EntCode	code;
TimeKind	kind;
{
	Widget	text;
	ArgPack	argp = ArgPack_create();
	Socket	sock;

	ArgPack_add_arg(argp, XmNborderWidth, (XtArgVal)0);
	ArgPack_add_arg(argp, XmNshadowThickness, (XtArgVal)0);

	argp = ArgPack_duplicate_args(time_text_res);
	ArgPack_add_arg(argp, XmNleftWidget, (XtArgVal)attach_w);
	ArgPack_add_arg(argp, XmNleftWidget, (XtArgVal)attach_w);

	text = XmCreateText(form, "One-line-text", ArgPack_the_args(argp),
			    ArgPack_num_args(argp));

	XtAddCallback(text, XmNlosingFocusCallback, AEC_parse_text,
		      (caddr_t)NULL);
	XtAddCallback(text, XmNlosingFocusCallback, AEC_text_editable,
		      (caddr_t)FALSE);
	XtAddCallback(text, XmNfocusCallback, AEC_text_editable,
		      (caddr_t)TRUE);
	XmTextSetString(text, ctime(kind == AE_START ? &AlDC_plugs[code].start
				    : &AlDC_plugs[code].stop));
	XtAddCallback(text, XmNmodifyVerifyCallback, AEC_set_modify,
		      (caddr_t)NULL);
	XmAddTabGroup(text);

	sock = (Socket)Memory_allocate(sizeof(SocketSt));
	sock->type = (kind == AE_START ? AE_START_TEXT : AE_STOP_TEXT);
	sock->patch = code;
	Registry_add(plug_widgets, (VOIDP)text, (VOIDP)sock);
	ArgPack_delete(argp);
	return text;
}

NORET
AE_create_int_menu(form, attach_w, alternate_text, code)
Widget	form,
	attach_w,
	alternate_text;
EntCode	code;
{
	Widget		wrap;
	MenuPack	mp;
	ArgPack		argp = ArgPack_create();
	Socket		sock;
	short		i = 0;

		
	ArgPack_add_arg(argp, XmNleftAttachment, (XtArgVal)XmATTACH_WIDGET);
	ArgPack_add_arg(argp, XmNleftWidget, (XtArgVal)attach_w);
	wrap = XmCreateForm(form, "Interval Form", ArgPack_the_args(argp),
			      ArgPack_num_args(argp));
	
	ArgPack_delete(argp);

	mp = MenuPack_create_option(wrap, "Interval Selection", "Interval");

	while(i < AE_NUM_OPTS - 1)
		MenuPack_add_option(AlAE_int_opts_vals[i++].opt, mp, 
				    AEC_set_modify,
				    (caddr_t)NULL,
				    (ArgPack)NULL);
	MenuPack_add_option(AlAE_int_opts_vals[i].opt, mp, AEC_int_other,
			    (caddr_t)alternate_text,
			    (ArgPack)NULL);		/* for "other" opt */
	MenuPack_make_menu(mp);
	Alxt_SetArg(MenuPack_option_get_label(mp), XmNlabelString,
		    (XtArgVal)XmStringCreate("", XmSTRING_DEFAULT_CHARSET));

	/* the following loop sets the option menu label to show the
	 * correct interval as saved from the last session
	 */

	for(i = 0; i < AE_NUM_OPT_VALS; ++i)
		if(AlDC_plugs[code].data == AlAE_int_opts_vals[i].val)
		{	MenuPack_set_as_default(mp, AlAE_int_opts_vals[i].opt);
			break;
		}


	sock = (Socket)Memory_allocate(sizeof(SocketSt));
	sock->type = AE_STOP_INTVL;
	sock->patch = code;
	Registry_add(plug_widgets, (VOIDP)MenuPack_get_top_level_manager(mp),
		     (VOIDP)sock);
	if(i == AE_NUM_OPT_VALS)	/* could not find known interval */
		XtManageChild(alternate_text);
	else
		XtManageChild(wrap);

	MenuPack_destroy(mp);
}

Widget
AE_create_text_line(area, code, prev_line)
Widget	area,
	prev_line;
EntCode	code;
{
	char	name[64];
	Widget	line_form,
		on_off_opt,
		cat,
		txt,
		intl,
		int_text;
	ArgPack	argp  = ArgPack_create();


	ArgPack_add_arg(argp, XmNborderWidth, (XtArgVal)1);

	ArgPack_add_arg(argp, XmNleftAttachment, (XtArgVal)XmATTACH_FORM);
	ArgPack_add_arg(argp, XmNleftOffset, (XtArgVal)5);
	ArgPack_add_arg(argp, XmNtopOffset, (XtArgVal)15);
	if(prev_line != (Widget)NULL)
	{	ArgPack_add_arg(argp, XmNtopAttachment, (XtArgVal)XmATTACH_WIDGET);
		ArgPack_add_arg(argp, XmNtopWidget, (XtArgVal)prev_line);
	} else
		ArgPack_add_arg(argp, XmNtopAttachment, (XtArgVal)XmATTACH_FORM);
	
	sprintf(name, "Category: %s", AlData_CTGRS[code]);
	line_form = XmCreateForm(area, name, ArgPack_the_args(argp),
				 ArgPack_num_args(argp));

	on_off_opt = AE_create_on_off_opt(line_form, code);
	cat = AE_create_cat_label(line_form, on_off_opt, code);
	txt = AE_create_time_text(line_form, cat, code, AE_START);
	XtManageChild(txt);
	intl = AE_create_int_label(line_form, txt);
	int_text = AE_create_time_text(line_form, intl, code, AE_STOP);
	AE_create_int_menu(line_form, intl, int_text, code);
	ArgPack_delete(argp);
	XtManageChild(line_form);
	return line_form;
}

Widget
AE_create_io(scrollW)
Widget	scrollW;
{
	Widget	io,
		tmp_line = (Widget)NULL;
	ArgPack	argp = ArgPack_create();
	EntCode	i;

	ArgPack_add_arg(argp, XmNborderWidth, (XtArgVal)0);

	ArgPack_add_arg(argp, XmNrubberPositioning, (XtArgVal)TRUE);
	ArgPack_add_arg(argp, XmNhorizontalSpacing, (XtArgVal)5);
	ArgPack_add_arg(argp, XmNverticalSpacing, (XtArgVal)5);

	ArgPack_add_arg(argp, XmNresizePolicy, (XtArgVal)XmRESIZE_ANY);
	
	io = XmCreateForm(scrollW, "I/O Display", ArgPack_the_args(argp), 
				 ArgPack_num_args(argp));

	ArgPack_delete(argp);

	for(i = 0; i < PLUGS; i++)
		tmp_line = AE_create_text_line(io, i, tmp_line);

	/** Not sure if the Manage is necessary **/
	XtManageChild(io);

	return io;
}

NORET
AE_create_scroll_sec(form, attach_wa, attach_wb)
Widget	form,
	attach_wa,
	attach_wb;
{
	Widget	scroll_sec;
	ArgPack	argp;

	argp = ArgPack_duplicate_args(scroll_sec_res);
	ArgPack_add_arg(argp, XmNtopWidget, (XtArgVal)attach_wa);
	ArgPack_add_arg(argp, XmNbottomWidget, (XtArgVal)attach_wb);

	scroll_sec = XmCreateScrolledWindow(form, "Scroll Window", 
					    ArgPack_the_args(argp),
					    ArgPack_num_args(argp));

	ArgPack_delete(argp);

	argp = ArgPack_create();
	ArgPack_add_arg(argp, XmNworkWindow, 
			(XtArgVal)AE_create_io(scroll_sec));
	XtSetValues(scroll_sec, ArgPack_the_args(argp), ArgPack_num_args(argp));
	XtManageChild(scroll_sec);
}

Widget
AE_create_bottom(form)
Widget	form;
{
	Widget	quitB,
		helpB,
		saveB,
		buttons;
	ArgPack	gen_argp = ArgPack_create(),
		q_argp = ArgPack_create(),
		h_argp = ArgPack_create(),
		s_argp = ArgPack_create();

	ArgPack_add_arg(gen_argp, XmNheight, (XtArgVal)60);

	ArgPack_add_arg(gen_argp, XmNresizePolicy, (XtArgVal)XmRESIZE_NONE);

	ArgPack_add_arg(gen_argp, XmNbottomAttachment, (XtArgVal)XmATTACH_FORM);
	ArgPack_add_arg(gen_argp, XmNleftAttachment, (XtArgVal)XmATTACH_FORM);
	ArgPack_add_arg(gen_argp, XmNrightAttachment, (XtArgVal)XmATTACH_FORM);
	ArgPack_add_arg(gen_argp, XmNresizable, (XtArgVal)FALSE);

	buttons = XmCreateForm(form, "Button Form",
			       ArgPack_the_args(gen_argp),
			       ArgPack_num_args(gen_argp));
	ArgPack_delete(gen_argp);

	gen_argp = ArgPack_duplicate_args(gen_button_res);
	ArgPack_add_arg(gen_argp, XmNfontList, (XtArgVal)fonts);

	q_argp = ArgPack_copy_and_append(q_argp, gen_argp);
	ArgPack_add_arg(q_argp, XmNleftAttachment, (XtArgVal)XmATTACH_FORM);
	ArgPack_add_arg(q_argp, XmNlabelString, 
			(XtArgVal)XmStringCreate("Quit", ALFONTS_BUTTONS));
	quitB = XmCreatePushButton(buttons, "quit-button",
				   ArgPack_the_args(q_argp),
				   ArgPack_num_args(q_argp));
	ArgPack_delete(q_argp);
	XtAddCallback(quitB, XmNactivateCallback, AEC_quit, (caddr_t)NULL);

	h_argp = ArgPack_copy_and_append(h_argp, gen_argp);
	ArgPack_add_arg(h_argp, XmNleftAttachment, (XtArgVal)XmATTACH_WIDGET);
	ArgPack_add_arg(h_argp, XmNleftWidget, (XtArgVal)quitB);
	ArgPack_add_arg(h_argp, XmNlabelString, 
			(XtArgVal)XmStringCreate("Help", ALFONTS_BUTTONS));
	helpB = XmCreatePushButton(buttons, "help-button",
				   ArgPack_the_args(h_argp),
				   ArgPack_num_args(h_argp));
	ArgPack_delete(h_argp);

	s_argp = ArgPack_copy_and_append(s_argp, gen_argp);
	ArgPack_add_arg(s_argp, XmNrightAttachment, (XtArgVal)XmATTACH_FORM);
	ArgPack_add_arg(s_argp, XmNlabelString, 
			(XtArgVal)XmStringCreate("Save", ALFONTS_BUTTONS));
	saveB = XmCreatePushButton(buttons, "save-button",
				   ArgPack_the_args(s_argp),
				   ArgPack_num_args(s_argp));
	ArgPack_delete(s_argp);
	XtAddCallback(saveB, XmNactivateCallback, AEC_save, (caddr_t)NULL);

	ArgPack_delete(gen_argp);
/**! Should probably do a ManageChildren ***/
	XtManageChild(quitB);
	XtManageChild(helpB);
	XtManageChild(saveB);
	XtManageChild(buttons);
	return buttons;
}

	

main(argc, argv)
int	argc;
char	*argv[];
{
	Widget	main_form,
		title_bar,
		bottom;
	XtAppContext	app;
	Display		*display;
	ArgPack	argp = ArgPack_create();

	AlFonts_init();
	Al_init();
	XtToolkitInitialize();
	app = XtCreateApplicationContext();
	display = XtOpenDisplay(app, NULL, "argusi", "Argus", NULL, 0, &argc,
				argv);

	ArgPack_add_arg(argp, XmNkeyboardFocusPolicy, XmEXPLICIT);
	main_shell = XtAppCreateShell("argusi", "Argus",
				      vendorShellWidgetClass, display,
				      ArgPack_the_args(argp),
				      ArgPack_num_args(argp));

	main_form = AE_create_main_form(main_shell);
	/* for some !@#$% reason the above line has to come before the next */
	fonts = AlFonts_get(main_shell);
	plug_widgets = Registry_create(Registry_ptrcmp, Registry_ptrhash);
	Registry_size_hint(plug_widgets, AE_NUM_PLUG_WIDGETS);
	main_form = AE_create_main_form(main_shell);
	title_bar = AE_create_title_bar(main_form);
	bottom = AE_create_bottom(main_form);
	AE_create_scroll_sec(main_form, title_bar, bottom);
	XtManageChild(main_form);
	XtRealizeWidget(main_shell);
	XtAppMainLoop(app);
}
