/*
**	jump.c
**
*/

#include <stdio.h>
#include <X11/Intrinsic.h>
#include <X11/Dialog.h>
#include <X11/List.h>
#include <X11/StringDefs.h>
#include <X11/Text.h>
#include <X11/Xaw/Cardinals.h>
#include <ctype.h>

#define  XtNinput	"input"
#define  F_LOGIC         2
#define  NO_FAIR         1
#define  OK              0
#define  ILLEGAL         3
#define  ACCEPTD         4

/*
**	The globals underneath are known to this file only, that's why
**	"static".
*/

static Widget	global_bad_guy_dialog, global_bad_guy_button,
		global_number_dialog, global_number_button, 
		global_size_dialog, global_size_button,
		global_time_dialog, global_time_button;

/*
**	The following globals must be passed outside, in order to
**	call XtListHighlight on them from main.
*/

Widget		global_bad_guy_list,
		global_number_list,
		global_size_list,
		global_time_list;

String		global_bad_guy_string, global_time_string,
		global_number_string, global_size_string;

void make_jump (parent_widget, right_widget, bottom_widget, 
		left_neighbour, left_distance, top_neighbour, top_distance)

Widget	*right_widget, *bottom_widget,
	left_neighbour, top_neighbour;
int	left_distance, top_distance;

{
	Widget	bad_guy_dialog, bad_guy_list, bad_guy_button,
		number_dialog, number_list, number_button,
		size_dialog, size_list, size_button,
		time_dialog, time_list, time_button;
	extern 	void make_switch_dialog ();

/*
**	Allocate space for global strings
*/
	global_bad_guy_string = (char *) malloc (BUFSIZ * sizeof(char));
	global_time_string = (char *) malloc (BUFSIZ * sizeof(char));
	global_size_string = (char *) malloc (BUFSIZ * sizeof(char));
	global_number_string = (char *) malloc (BUFSIZ * sizeof(char));

	make_switch_dialog (parent_widget, 
	   &bad_guy_dialog, &bad_guy_list, &bad_guy_button, 
	   "fail on formula:                 ", "", "bad_guy",
	   left_neighbour, left_distance, top_neighbour, top_distance);
	global_bad_guy_dialog = bad_guy_dialog;
	global_bad_guy_button = bad_guy_button;
	global_bad_guy_list   = bad_guy_list;
	*right_widget = bad_guy_dialog;
	*bottom_widget = bad_guy_list;

	make_switch_dialog (parent_widget,
	   &number_dialog, &number_list, &number_button,
	   "maximum number of matrices:", "0", "number",
	   left_neighbour, left_distance, *bottom_widget, 0);
	global_number_dialog = number_dialog;
	global_number_button = number_button;
	global_number_list   = number_list;
	*bottom_widget = number_list;

	make_switch_dialog (parent_widget,
	   &size_dialog, &size_list, &size_button,
	   "maximum size of matrices:  ", "14", "size",
	   left_neighbour, left_distance, *bottom_widget, 0);
	global_size_dialog = size_dialog;
	global_size_button = size_button;
	global_size_list   = size_list;
	*bottom_widget = size_list;

	make_switch_dialog (parent_widget,
	   &time_dialog, &time_list, &time_button,
	   "stop when time exceeds:    ", "0 sec", "time",
	   left_neighbour, left_distance, *bottom_widget, 0);
	global_time_dialog = time_dialog;
	global_time_button = time_button;
	global_time_list   = time_list;
	*bottom_widget = time_list;

}


void make_switch_dialog (parent_widget, dialog_widget, the_list, the_button,
	prompt_string, default_string, flag_string,
	left_neighbour, left_distance, top_neighbour, top_distance)

Widget	parent_widget, *dialog_widget, *the_list, *the_button, 
	left_neighbour, top_neighbour;
String	prompt_string, default_string, flag_string;
int	left_distance, top_distance;

{
	int		i;
	Arg		dialog_args [30], list_args [30];
	static String	list_strings [] = {"on", "off", NULL,};
	extern void	list_action (), change_action ();
	XtCallbackRec 	list_calls [2], change_calls [2];
	XtTranslations	translation_table;
  
	i = 0;
	XtSetArg (dialog_args [i], XtNlabel, (XtArgVal) prompt_string);
	i++;
	XtSetArg (dialog_args [i], XtNvalue, (XtArgVal) default_string);
	i++;
	XtSetArg (dialog_args [i], XtNborderWidth, (XtArgVal) 0);
	i++;
	XtSetArg (dialog_args [i], XtNfromHoriz, (XtArgVal) left_neighbour);
	i++;
	XtSetArg (dialog_args [i], XtNhorizDistance, (XtArgVal) left_distance);
	i++;
	XtSetArg (dialog_args [i], XtNfromVert, (XtArgVal) top_neighbour);
	i++;
	XtSetArg (dialog_args [i], XtNvertDistance, (XtArgVal) top_distance);
	i++;
	XtSetArg (dialog_args [i], XtNinput, (XtArgVal) True);
	i++;
/*
  	XtSetArg (dialog_args [i], XtNtranslations, (XtArgVal) 
  	   translation_table);
  	i++;
*/
	*dialog_widget = XtCreateManagedWidget ("switch_dialog",
				dialogWidgetClass, parent_widget,
				dialog_args, i);
	XtSetSensitive (*dialog_widget, False);

	i = 0;
	XtSetArg (list_args [i], XtNcallback, (XtArgVal) list_calls);
	i++;
	XtSetArg (list_args [i], XtNverticalList, (XtArgVal) False);
	i++;
	XtSetArg (list_args [i], XtNlist, (XtArgVal) list_strings);
	i++;
	XtSetArg (list_args [i], XtNfromHoriz, (XtArgVal) left_neighbour);
	i++;
	XtSetArg (list_args [i], XtNhorizDistance, (XtArgVal) 
				(left_distance + 4));
	i++;
	XtSetArg (list_args [i], XtNfromVert, (XtArgVal) *dialog_widget);
	i++;
	XtSetArg (list_args [i], XtNvertDistance, (XtArgVal) 0);
	i++;

	list_calls[0].callback = (XtCallbackProc) list_action;
	list_calls[0].closure = (caddr_t) flag_string;
	list_calls[1].callback = (XtCallbackProc) NULL;
	list_calls[1].closure = (caddr_t) NULL;

	*the_list = XtCreateManagedWidget ("switch_list", listWidgetClass,
			parent_widget, list_args, i);

	change_calls[0].callback = (XtCallbackProc) change_action;
	change_calls[0].closure = (caddr_t) flag_string;
	change_calls[1].callback = (XtCallbackProc) NULL;
	change_calls[1].closure = (caddr_t) NULL;
	
	make_button (parent_widget, the_button, "the_button", "change",
			change_calls, *the_list, 4, *dialog_widget, 0);
	XtSetSensitive (*the_button, False);
}

static int m_size = 0, m_number = 0, m_time = 0;

static void list_action (the_list, the_flag, the_selection)

Widget			the_list;
String			the_flag;
XtListReturnStruct	*the_selection;

{
	char	the_line [256], unit [10];
	Widget	dialog_widget, button_widget;
	int	number, factor;
	char	c;
	Boolean	bad_input;
	extern	void	ring (), putout ();

	bad_input = False;
	if (strncmp (the_flag, "bad_guy", 7) == 0) {
		dialog_widget = global_bad_guy_dialog;
		button_widget = global_bad_guy_button;
		if (the_selection->list_index == 1)
			sprintf (the_line, "D\nb\n");
		else
			sprintf (the_line, "B\n%s\n", 
				XtDialogGetValueString (dialog_widget));
	}
	else if (strncmp (the_flag, "number", 6) == 0) {
		dialog_widget = global_number_dialog;
		button_widget = global_number_button;
		sprintf (the_line, "%s\n", 
			XtDialogGetValueString (dialog_widget));
		if (sscanf (the_line, "%1s", &c) > 0) {
			if (isdigit (c) || the_selection->list_index == 1) {
				if (the_selection->list_index == 1)
					m_number = 0;
				else {
					sscanf (the_line, "%d", &number);
					m_number = number;
				}
				sprintf (the_line, "J\ne\n%d\n%d\n%d\n", 
					m_number, m_size, m_time);
			}
			else {
				bad_input = True;
				putout (" Illegal input: must be a number\n", 
				   (XawTextPosition) 29);
			}
		}
		else
			bad_input = True;
	}
	else if (strncmp (the_flag, "size", 4) == 0) {
		dialog_widget = global_size_dialog;
		button_widget = global_size_button;
		sprintf (the_line, "%s\n", 
			XtDialogGetValueString (dialog_widget));
		if (sscanf (the_line, "%1s", &c) > 0) {
			if (isdigit (c) || the_selection->list_index == 1) {
				if (the_selection->list_index == 1)
					m_size = 0;
				else {
					sscanf (the_line, "%d", &number);
					m_size = number;
				}
				sprintf (the_line, "J\ne\n%d\n%d\n%d\n", 
					m_number, m_size, m_time);
			}
			else {
				bad_input = True;
				putout (" Illegal input: must be a number\n", 
				  (XawTextPosition) 29);
			}
		}
		else
			bad_input = True;
	}
	else if (strncmp (the_flag, "time", 4) == 0) {
		dialog_widget = global_time_dialog;
		button_widget = global_time_button;
		sprintf (the_line, "%s\n", 
			XtDialogGetValueString (dialog_widget));
		if (sscanf (the_line, "%1s", &c) > 0) {
			if (isdigit (c) || the_selection->list_index == 1) {
				if (the_selection->list_index == 1)
					m_time = 0;
				else {
					sscanf (the_line, "%d %s", &number, 
						unit);
					if (strncmp (unit, "s", 1) == 0)
						factor = 1;
					else if (strncmp (unit, "mi", 2) == 0)
						factor = 60;
					else if (strncmp (unit, "h", 1) == 0)
						factor = 3600;
					else if (strncmp (unit, "d", 1) == 0)
						factor = 3600 * 24;
					else if (strncmp (unit, "w", 1) == 0)
						factor = 3600 * 24 * 7;
					else if (strncmp (unit, "f", 1) == 0)
						factor = 3600 * 24 * 14;
					else if (strncmp (unit, "mo", 2) == 0)
						factor = 3600 * 24 * 30;
					else if (strncmp (unit, "y", 1) == 0)
						factor = 3600 * 24 * 365;
					else
						factor = 1;
					m_time = number * factor;
				}
				sprintf (the_line, "J\ne\n%d\n%d\n%d\n", 
					m_number, m_size, m_time);
			}
			else {
				bad_input = True;
				putout (" Illegal input: must be a number\n", 
				  (XawTextPosition) 29);
			}
		}
		else
			bad_input = True;
	}
/*
**	Now talk to magic, but only if input not botched
*/

	if (!bad_input) {
		send_to_magic (the_line);
		if (receive_all () == ILLEGAL) {
			ring ();
			send_to_magic ("N\n");
			receive_all ();
		}
	}
	else
		ring ();
/*
**	Do sensitize-desensitize regardless
*/
	switch (the_selection->list_index) {
	case 0: XtSetSensitive (dialog_widget, True);
		XtSetSensitive (button_widget, True);
		break;
	case 1: XtSetSensitive (dialog_widget, False);
		XtSetSensitive (button_widget, False);
		break;
	}
}

void getit (widget, event, params, num_params)
Widget		widget;
XEvent		*event;
String		*params;
Cardinal	*num_params;
{
	Widget	dialog;
	extern void ring ();
	extern void change_action ();

	dialog = XtParent(widget);
	if (dialog == global_bad_guy_dialog) 
	   change_action(dialog, "bad_guy", (XtPointer) NULL);
	else if (dialog == global_number_dialog)
	   change_action(dialog, "number", (XtPointer) NULL);
	else if (dialog == global_size_dialog)
	   change_action(dialog, "size", (XtPointer) NULL);
	else if (dialog == global_time_dialog)
	   change_action(dialog, "time", (XtPointer) NULL);
}

static void change_action (the_button, the_flag, call_data)

Widget			the_button;
String			the_flag;
caddr_t			call_data;

{
	char	the_line [256], unit [10];
	Widget	dialog_widget;
	int	number, factor;
	char	c;
	Boolean	bad_input;
	extern	void
		ring (), putout ();

	bad_input = False;
	if (strncmp (the_flag, "bad_guy", 7) == 0) {
		dialog_widget = global_bad_guy_dialog;
		sprintf (the_line, "B\n%s\n",
			XtDialogGetValueString (dialog_widget));
	}
	else if (strncmp (the_flag, "number", 6) == 0) {
		dialog_widget = global_number_dialog;
		sprintf (the_line, "%s\n", 
			XtDialogGetValueString (dialog_widget));
		if (sscanf (the_line, "%1s", &c) > 0) {
			if (isdigit (c)) {
				sscanf (the_line, "%d", &number);
				m_number = number;
				sprintf (the_line, "J\ne\n%d\n%d\n%d\n", 
					m_number, m_size, m_time);
			}
			else {
				bad_input = True;
				putout (" Illegal input: must be a number\n", 
				  (XawTextPosition) 29);
			}
		}
		else
			bad_input = True;
	}
	else if (strncmp (the_flag, "size", 4) == 0) {
		dialog_widget = global_size_dialog;
		sprintf (the_line, "%s\n", 
			XtDialogGetValueString (dialog_widget));
		if (sscanf (the_line, "%1s", &c) > 0) {
			if (isdigit (c)) {
				sscanf (the_line, "%d", &number);
				m_size = number;
				sprintf (the_line, "J\ne\n%d\n%d\n%d\n", 
				m_number, m_size, m_time);
			}
			else {
				bad_input = True;
				putout (" Illegal input: must be a number\n", 
				  (XawTextPosition) 29);
			}
		}
		else
			bad_input = True;
	}
	else if (strncmp (the_flag, "time", 4) == 0) {
		dialog_widget = global_time_dialog;
		sprintf (the_line, "%s\n", 
			XtDialogGetValueString (dialog_widget));
		if (sscanf (the_line, "%1s", &c) > 0) {
			if (isdigit (c)) {
				sscanf (the_line, "%d %s", &number, unit);
				if (strncmp (unit, "s", 1) == 0)
					factor = 1;
				else if (strncmp (unit, "mi", 2) == 0)
					factor = 60;
				else if (strncmp (unit, "h", 1) == 0)
					factor = 3600;
				else if (strncmp (unit, "d", 1) == 0)
					factor = 3600 * 24;
				else if (strncmp (unit, "w", 1) == 0)
					factor = 3600 * 24 * 7;
				else if (strncmp (unit, "f", 1) == 0)
					factor = 3600 * 24 * 14;
				else if (strncmp (unit, "mo", 2) == 0)
					factor = 3600 * 24 * 30;
				else if (strncmp (unit, "y", 1) == 0)
					factor = 3600 * 24 * 365;
				else
					factor = 1;
				number = number * factor;
				m_time = number;
				sprintf (the_line, "J\ne\n%d\n%d\n%d\n", 
				m_number, m_size, m_time);
			}
			else {
				bad_input = True;
				putout (" Illegal input: must be a number\n", 
				  (XawTextPosition) 29);
			}
		}
		else
			bad_input = True;
	}

	if (!bad_input) {
		send_to_magic (the_line);
		if (receive_all () == ILLEGAL) {
			ring ();
			send_to_magic ("N\n");
			receive_all ();
		}
	}
	else
		ring ();
}

void	reset_jump ()

{
/*
**	Merely switch off the widgets involved, since "kill" will
**	reset everything in magic anyway.
*/

	XtListHighlight (global_bad_guy_list, 1);
	XtSetSensitive (global_bad_guy_dialog, False);
	XtSetSensitive (global_bad_guy_button, False);

	XtListHighlight (global_number_list, 1);
	XtSetSensitive (global_number_dialog, False);
	XtSetSensitive (global_number_button, False);

	XtListHighlight (global_size_list, 1);
	XtSetSensitive (global_size_dialog, False);
	XtSetSensitive (global_size_button, False);

	XtListHighlight (global_time_list, 1);
	XtSetSensitive (global_time_dialog, False);
	XtSetSensitive (global_time_button, False);
}

void	update_bad_guy_dialog()
{
        extern String	global_bad_guy_string;
	Arg		args[3];

	XtSetArg (args [0], XtNvalue, global_bad_guy_string);
	XtSetValues (global_bad_guy_dialog, args, ONE);
}

void	update_time_dialog()
{
	extern String	global_time_string;
	Arg		args[3];

	XtSetArg (args [0], XtNvalue, global_time_string);
	XtSetValues (global_time_dialog, args, ONE);
}

void	update_size_dialog()
{
	extern String	global_size_string;
	Arg		args[3];

	XtSetArg (args [0], XtNvalue, global_size_string);
	XtSetValues (global_size_dialog, args, ONE);
}

void	update_number_dialog()
{
	extern String	global_number_string;
	Arg		args[3];

	XtSetArg (args [0], XtNvalue, global_number_string);
	XtSetValues (global_number_dialog, args, ONE);
}
