/*
**	pipe.c
**
*/

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include "defs.h"
#include <X11/Intrinsic.h>
#include <X11/AsciiText.h>
#include "xmagic.h"

static FILE *sndfp,  *rcvfp;	/* used by send_to_magic and get_from_magic */

#ifndef	MAGIC
#define MAGIC	"/usr/local/magic"
#endif

invoke_magic ()	/* invoke magic */
{
	int pfdout[2], pfdin[2];
	extern int no_of_procs;
	char opt_string [10];

	if (pipe(pfdout) == -1 || pipe(pfdin) == -1)
		syserr("pipe");
	switch (fork()) {
	case -1: /* couldn't fork */
		syserr("fork");
	case 0:	/* child */
		if (close(0) == -1)
			syserr("close");
		if (dup(pfdout[0]) != 0)
			fatal("dup");
		if (close(1) == -1)
			syserr("close");
		if (dup(pfdin[1]) != 1)
			fatal("dup");
		if (close(pfdout[0]) == -1 || close(pfdout[1]) == -1 ||
		    close(pfdin[0]) == -1 || close(pfdin[1]) == -1)
			syserr("close");
#ifndef REMOTE
		if (no_of_procs) {
			sprintf (opt_string, "-#%d", no_of_procs);
			execl(MAGIC, "magic", "-x", opt_string, 0); 
		}
		else
			execl(MAGIC, "magic", "-x", 0);
#else
		if (no_of_procs) {
			sprintf (opt_string, "\'-#%d\'", no_of_procs);
			execlp ("rsh", "rsh", REMOTE, MAGIC, "-x",
				opt_string, 0);
		}
		else
			execlp ("rsh", "rsh", REMOTE, MAGIC, "-x", 0);
#endif
		syserr("execl");
	}
	/* parent - continued */
	if (close(pfdout[0]) == -1 || close(pfdin[1]) == -1)
		syserr("close");
	sndfp = fdopen(pfdout[1], "w");
	rcvfp = fdopen(pfdin[0], "r");
}

void send_to_magic (s)	/* send line to magic */
char *s;
{
	if (fputs(s, sndfp) == EOF)
		fatal("send_to_magic");
	fflush (sndfp);
}

BOOLEAN get_from_magic (s, max)	/* receive line from magic */

char *s; 
int max; 

{
	BOOLEAN	ret_value;

	if (fgets(s, max, rcvfp) == NULL)
		fatal("get_from_magic");
#ifdef DEBUG
	fprintf (stderr, "%s", s); fflush (stderr);
#endif
	
	ret_value = ( (strncmp(s, "    E)xit", 9) != 0) &&
		(strncmp(s, " Matrices come in all sizes", 26) != 0) &&
		(strncmp(s, " No fair:", 9) != 0) &&
		(strncmp(s, " Accepted", 9) != 0) &&
		(strncmp(s, " ERROR:", 7) != 0) &&
		(strncmp(s, " Time (wall clock)", 18) != 0) &&
		(strncmp(s, " It appears you can", 19) != 0) &&
		(strncmp(s, " Number of processes must be", 28) != 0) &&
		(strncmp(s, 
		   " Type the new connective:   Accepted !!", 39) != 0) &&
		(strncmp(s, " Illegal input:", 15) != 0) );
#ifdef DEBUG	
	if (!ret_value) {
		fprintf (stderr, "Prompt line detected\n"); fflush (stderr);
	}
#endif

	return (ret_value);
}

#define F_LOGIC		2
#define NO_FAIR		1
#define OK		0
#define ILLEGAL		3
#define ACCEPTD		4
#define DONE		5

Boolean	verbose =	False;

int receive_all ()	
/* receive and print all that comes from magic */

{
	char 		s[256];
	char		*cp;
	extern char	fragment_string [256];
	Boolean		not_prompt, get_next, no_plus, get_def, get_extra;
	static Boolean	err_flag = False;
	extern void	update_fragment (), update_axioms (), putout ();
	int		the_flag, i, j, def_count;
	extern int	last_state [NO_OF_AXIOMS], pre_axiom_count;
	extern Boolean	axioms_up, parallel_magic;
	extern String	global_bad_guy_string, global_time_string,
			global_size_string, global_number_string,
			global_file_string;
	extern void	update_bad_guy_dialog(), update_time_dialog(),
			update_size_dialog(), update_number_dialog(),
			update_file_dialog(), update_def_list();
	extern String	con_string[], extra_string;
	extern int	max_procs, no_of_procs;

	get_next = False;
	get_def = False;
	get_extra = False;
	no_plus = True;
	do {
	        not_prompt = get_from_magic (s, sizeof(s));
/*
**	Observe strings returned by get_from_magic and set up the
**	alert flags if you'll find the nasty ones (get_from_magic
**	also does that - there is some duplicity here which should
**	be removed once everything is working.
*/
		if (strncmp(s, "    E)xit", 9) == 0) {
			the_flag = OK;
#ifdef DEBUG
			fprintf (stderr, "OK set up\n"); fflush (stderr);
#endif
		}
		else if (strncmp(s, " No fair:", 9) == 0) {
			the_flag = NO_FAIR;
			err_flag = True;
#ifdef DEBUG
			fprintf (stderr, "NO_FAIR set up\n"); fflush (stderr);
#endif
		}
		else if (strncmp(s, " Matrices come in all sizes", 26) == 0) {
			the_flag = F_LOGIC;
#ifdef DEBUG
			fprintf (stderr, "F_LOGIC set up\n"); fflush (stderr);
#endif
		}
		else if (strncmp(s, " Illegal input:", 15) == 0) {
			the_flag = ILLEGAL;
			err_flag = True;
#ifdef DEBUG
			fprintf (stderr, "ILLEGAL set up\n"); fflush (stderr);
#endif
		}
		else if (strncmp(s, " ERROR:", 7) == 0) {
			the_flag = ILLEGAL;
			err_flag = True;
#ifdef DEBUG
			fprintf (stderr, "ILLEGAL set up\n"); fflush (stderr);
#endif
		}
		else if (strncmp(s, " It appears you can\'t have ", 27) == 0){
			the_flag = ILLEGAL;
			err_flag = True;
		}
		else if (strncmp(s, " Number of processes must be", 27) == 0){
			the_flag = ILLEGAL;
			err_flag = True;
		}
		else if (strncmp(s, " Accepted", 9) == 0) {
			the_flag = ACCEPTD;
#ifdef DEBUG
			fprintf (stderr, "ACCEPTD set up\n"); fflush (stderr);
#endif
		}
		else if (strncmp(s, 
			 " Type the new connective:   Accepted !!", 39) == 0) {
			the_flag = ACCEPTD;
#ifdef DEBUG
			fprintf (stderr, "ACCEPTD set up\n"); fflush (stderr);
#endif
		}
		else if (strncmp(s, " Time (wall clock)", 18) == 0) {
			the_flag = DONE;
#ifdef DEBUG
			fprintf (stderr, "DONE set up\n"); fflush (stderr);
#endif
		}

/*
**	Look for strings which contain the information used by various
**	form-update functions, and store them up for future use.
*/

		if (strncmp (s, " Fragment:", 9) == 0)
			strcpy (fragment_string, s);
		if (get_next) {
			if (sscanf (s, " %d", &i) < 1) 
				get_next = False;
			else {
				last_state [i - 1] = 1; 
				pre_axiom_count++;
#ifdef DEBUG	
				fprintf (stderr, "axiom %d registered\n", i);
				fflush (stderr);
#endif
			}
		}
		if (strncmp (s, " Plus:", 6) == 0) {
			no_plus = False;
			pre_axiom_count = 1;
			for (i = 0; i < BUILT_IN_AXIOMS; i++)
				last_state [i] = 0;
			sscanf (s, " Plus: %d ", &i);
			last_state [i - 1] = 1; 
#ifdef DEBUG
			fprintf (stderr, "axiom %d registered\n", i);
			fflush (stderr);
#endif
			get_next = True;
		}
		if (strncmp (s, " Fail:         ", 15) == 0) {
			strcpy (global_bad_guy_string, &s[15]);
			cp = strchr (global_bad_guy_string, '\n');
			*cp = '\0';

			update_bad_guy_dialog();
		}
		if (strncmp (s, " Search concludes after ", 24) == 0) {
			strcpy (global_time_string, &s[24]);
			cp = strchr (global_time_string, '\n');
			*cp = '\0';
			update_time_dialog();
		}
		if (strncmp (s, " Search concludes when ", 23) == 0) {
			if (strncmp (s, " Search concludes when size ", 28)
			== 0) {
				sscanf (s, " Search concludes when size %s",
					global_size_string);
				update_size_dialog();
			}
			else {
				sscanf (s, " Search concludes when %s",
					global_number_string);
				update_number_dialog();
			}
		}
		if (strncmp (s, " or when ", 9) == 0) {
			if (strncmp (s, " or when size ", 14) == 0) {
				sscanf (s, " or when size %s", 
					global_size_string);
				update_size_dialog();
			}
			else {
				sscanf (s, " or when %s",
					global_number_string);
				update_number_dialog();
			}
		}
		if (strncmp (s, " Output file:  \"", 16) == 0) {
			strcpy (global_file_string, &s[16]);
			cp = strchr (global_file_string, '"');
			*cp = '\0';
			update_file_dialog();
		}
		if (strncmp (s, " Definitions:  ", 15) == 0) {
			def_count = 0;
			strcpy (con_string [def_count], &s[15]);
			cp = strchr (con_string[def_count], '\n');
			*cp = '\0';
			def_count++;
			get_def = True;
		}
		else if (get_def) {
			if (strncmp (s, "               ", 15) == 0) {
				strcpy (con_string [def_count], &s[15]);
				cp = strchr (con_string[def_count],
					'\n');
				*cp = '\0';
				def_count++;
			}
			else {
				for (j = def_count; j < 6; j++)
					*con_string[j] = '\0';
				get_def = False;
			}
			update_def_list();
		}
		if (strncmp (s, " Extra:        ", 15) == 0) {
			strcpy (extra_string, &s[15]);
			cp = strchr (extra_string, '\n');
			*cp = '\0';
			get_extra = True;
		}
		else if (get_extra) {
			if (strncmp (s, "               ", 15) == 0) {
				strcpy (extra_string, &s[15]);
				cp = strchr (extra_string, '\n');
				*cp = '\0';
			}
			else {
				get_extra = False;
			}

		}
		if (strncmp (s, " Parallel MaGIC running ", 24) == 0) {
			parallel_magic = True;
			sscanf (s, 
			" Parallel MaGIC running %d out of %d processes",
			&no_of_procs, &max_procs);
			update_pro_label();
		}

/*
**	Now display the string in the window. In the future this should
**	become a separate function. Only certain strings need to be
**	displayed!
*/
		if (!verbose) {
			if (err_flag) {
				putout (s, (XawTextPosition) strlen (s));
				err_flag = False;
			}
/*
**			if ((strncmp(s, " Output file:", 13) == 0) ||
**			    (strncmp(s, " Search concludes", 17) == 0) ||
**			    (strncmp(s, " or when", 8) == 0))
**				putout (s, (XawTextPosition) strlen (s));
*/
		}
		else
			putout (s, (XawTextPosition) strlen (s));
	} while (not_prompt);

/*
**	Call the form-update functions now
*/
	update_fragment ();
	if (no_plus && the_flag == OK) {
		for (i = 0; i < BUILT_IN_AXIOMS; last_state [i++] = 0);
		pre_axiom_count = 0;
	}
	if (axioms_up)
		update_axioms ();
/*
**	Return the flag
*/
	return (the_flag);
}

#define OUTPUT_SIZE	65536

void	putout (a_string, length)

char		*a_string;
XawTextPosition	length;

{
	static XawTextPosition	old_length, total_length = 0;
	static XawTextBlock	text_block;
	extern Widget		global_magic_output;
	extern char		*super_string;
	extern Display		*display_ptr;

	old_length = total_length;
	total_length = total_length + length;

#ifdef DEBUG
		fprintf (stderr, "\tputout: received string: %s", a_string);
		fprintf (stderr, "\tputout: total_length   = %d\n",
		   (int) total_length);
		fflush (stderr);
#endif

	if (total_length >= OUTPUT_SIZE) {

#ifdef DEBUG
		fprintf (stderr, "text buffer overflow"); fflush (stderr);
#endif
		total_length = old_length;
		old_length = old_length - length;
		text_block.firstPos = 0;
		text_block.length = old_length;
		text_block.ptr = super_string + length;
		text_block.format = FMT8BIT;
		XawTextReplace (global_magic_output, 0, old_length,
			&text_block);

	}

	text_block.firstPos = 0;
	text_block.length = (int) length;
	text_block.ptr = a_string;
	text_block.format = FMT8BIT;
	XawTextReplace (global_magic_output, old_length, total_length,
		&text_block);
	XawTextSetInsertionPoint (global_magic_output, total_length);
	XFlush (display_ptr);
}