#ifndef lint
static char *sccsid = "%W% (UKC) %G%";
#endif  lint

/*
 * Compute Mandelbrot fractal pattern.  Distributed version for ONE server.
 */

#include "mandel.h"
#include "rmandel.h"
#include <sys/tsbsp.h>
#include <sys/tserrno.h>
#include <libtsb.h>

short		pixel[MAX_NPIXEL];	/* Stores one pixel row		*/
extern	int	hist[];			/* Pixel density histogram	*/
extern	char	line[];			/* General text work area	*/
extern	FILE *	pixfd;			/* Pixel file (binary)		*/
extern	char *	progname;		/* argv[0] for error reporting	*/

static char server[] = "raven/srv/mansrv";

static char tspar2[256];
static char tspar3[256];
static char tspar4[256];

tscmd_t tsin = {
	0,	/* dummy command */
	{
		{ sizeof(pixel),  (char *) &pixel[0] },
		{ sizeof(tspar2), tspar2 },
		{ sizeof(tspar3), tspar3 },
		{ sizeof(tspar4), tspar4 },
	}
};

struct start_block sb;

tscmd_t tsout = {
	TS_PUSH,
	{
		{ sizeof(struct start_block),  (char *) &sb },
		{ sizeof(tspar2), tspar2 },
		{ sizeof(tspar3), tspar3 },
		{ sizeof(tspar4), tspar4 },
	}
};

int tsfd = -1;
tscmd_t *response;	/* for replies from ts_connect etc */


/*
 * Compute the Mandelbrot set.
 */
process()
{
	register int	j;		/* Column counter		*/
	register int	i;		/* Row counter			*/
	double	c_imag;			/* Pixel position (constant)	*/
	double	float_pixels = npixel;	/* To computer pixel position	*/

	/* construct start block (same for all processors) */
	sb.start_real = start_real;
	sb.side = side;
	sb.npixel = npixel;
	sb.maxiter = niter;

	if ((tsfd = gettsb()) < 0) die("Out of tsbsp ports");

	response = tsconnect(tsfd, server, (char*)0, (char *)0, (char *)0);
	if (response->ts_command != TS_ACCEPT) {
		fprintf(stderr, "%s: Connection not ACCEPTed to %s.\n",
			progname, server);
		exit(1);
	}

	/* send start block */
	if (write(tsfd, (char *) &tsout, sizeof(tsout)) != sizeof(tsout))
		die("write of start block fails");

	tsout.ts_par[0].ts_nbytes = sizeof(c_imag);
	tsout.ts_par[0].ts_data   = (char *) &c_imag;

	for (i = 1; i <= npixel; i++) {

		c_imag = start_imag - (side * i / float_pixels);

		if (write(tsfd, (char *)&tsout, sizeof(tsout))
			!= sizeof(tsout)) {
			fprintf(stderr, "%s: write fails on fd %d: ", progname, tsfd);
			perror("");
			if (read(tsfd, (char *)&tsin, sizeof(tsin)) != sizeof(tsin)) die("read also fails.");
			if (tsin.ts_command == TS_DISCONNECT)
				explaindisc(&tsin);
			exit(1);
		}

		readblock(tsfd);
	}					/* All rows in picture	*/
}

readblock(tsfd)
{
	int j;

	if (read(tsfd, (char *) &tsin, sizeof(tsin)) != sizeof(tsin))
		die("read fails");

	switch (tsin.ts_command) {
	case TS_PUSH:	/* ok */
		break;
	case TS_DISCONNECT:
		explaindisc(&tsin);
		return;
	default:
		fprintf(stderr, "%s: Unknown TS command %d.\n", progname, tsin.ts_command);
		exit(1);
	}

	if (tsin.ts_par[0].ts_nbytes != npixel * sizeof(pixel[0]))
		die("wrong size block received");

	(void) fwrite((char *)pixel, sizeof(pixel[0]), npixel, pixfd);
	if (ferror(pixfd)) {
		perror("pixel file write error");
		exit(1);
	}

	for (j=0; j<npixel; j++) hist[pixel[j]]++;
}

/*
 *	Turn disconnect packet into text on stderr for user
 */
explaindisc(response)
tscmd_t *response;
{
	fprintf(stderr, "%s: %s", progname,
		tserror(response->ts_par[0].ts_data[0]) );

	/* Location */
	if (response->ts_par[1].ts_nbytes > 0) {
		fprintf(stderr, ", location=\"%*s\"", 
			response->ts_par[1].ts_nbytes,
			response->ts_par[1].ts_data);
	}

	/* Explanatory text */
	if (response->ts_par[2].ts_nbytes > 0) {
		fprintf(stderr, ", explan=\"%*s\"", 
			response->ts_par[2].ts_nbytes,
			response->ts_par[2].ts_data);
	}
	fputs(".\n", stderr);
}

die(message)
char *message;
{
	if (tsfd >= 0) tsdisconnect(tsfd, TE_FAIL, "", message);
	fprintf(stderr, "%s: %s.\n", progname, message);
	exit(1);
}
