/*
 * plot3.c
 *
 * commands associated with the 3-d error plots.
 *
 */

#include <stdio.h>
#include <errno.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/file.h>
#include <X11/Xlib.h>
#include <X11/X10.h>
#include "xplot.h"
#include "../defs.h"
#include "win.h"

int	plot3_event();
int	plot3;
extern	Display *display;

XAssocTable	*win_table;

plot3_cmd(args)
	char	*args[];
{
	extern	struct win *win_leftmouse();
	extern	struct win *win_create();
	extern	int clean_up();
	extern	Window init_win();
	extern	int no_X;
	struct	xpinfo *Xp;
	char	geom[80];
	struct	win *wp;

	if (no_X) {
		fprintf(stderr, "No X display available\n");
		return;
	}
	if (args[1]) {
		if (startsame(args[1], "close")) {
			wp = win_leftmouse("hit left mouse in window to be killed\n");
			if (wp == 0)
				return;
			win_destroy(wp);
			XFlush(display);
			plot3--;
			return;
		}
	}
	if ((wp = win_create(args[1], geom)) == 0) {
		printf("window creation failed\n");
		return;
	}
	Xp = (struct xpinfo *) malloc(sizeof(*Xp));
	wp->w_data = (caddr_t) Xp;
	wp->w_event = plot3_event;
	if (plot3_info(args, wp, Xp) < 0) {
		win_destroy(wp);
		return;
	}
	XMapWindow(display, wp->w_win);
	(void) win_resize(wp);
	plot3_resize(wp, Xp);	
	plot3++;
	XFlush(display);
}

plot3_resize(wp, Xp)
	struct	win *wp;
	struct	xpinfo *Xp;
{
	/*
	 * These should eventually get the new window size and set 
	 * things accordingly
	 */
	Xp->Window_X = wp->w_width;
	Xp->Window_Y = wp->w_height;
	Xp->Window_Z = (wp->w_width + wp->w_height) / 2;
}

/*
 * I don't know if this should be here.  Its kind of tacky,
 * but I don't know where else to put it.  I guess it kind of
 * fits here.
 *
 * take current state of network, systematically vary 2 weights
 * and save the error.  Weights are identified in terms of
 * layer/node-from, layer/node-to pairs (e.g., 0/0,1/0 refers
 * to the connection between layer0, node0 and layer1, node0.
 */
plot3_info(args, wp, Xp)
	char	*args[];
	struct	win *wp;
	struct	xpinfo *Xp;
{
	extern	float wtstart, wtstop;
	extern	float ndtokens;
	extern	float global_error;
	extern	int wtstep;
	extern	int test;
	extern	int nolearn;
	extern	int ecount;
	extern	int errsig;
	extern	int run;
	extern	int cur_token;
	extern	char *targs[];
	register float *errdata;
	register int p;
	register int x;
	register int y;
	float	wtinc;
	extern	int *layer_descp;
	extern	float **weightp;
	float	*result;
	float	*ptr;
	float	*wp1;
	float	*wp2;
	float	*w1;
	float	*w2;
	int	*sizp1;
	int	*sizp2;
	int	trun;
	int	layfrom1;
	int	layfrom2;
	int	nodefrom1;
	int	nodefrom2;
	int	layto1;
	int	layto2;
	int	nodeto1;
	int	nodeto2;
	register float min;
	register float max;
	register float val;
	char	buf[80];

	if (args[1] == NULL) {
		printf("weight 1:\n");
		printf("\tlayer/node from:  ");
		scanf("%d/%d", &layfrom1, &nodefrom1);
		printf("\tlayer/node to:  ");
		scanf("%d/%d", &layto1, &nodeto1);
		printf("weight 2:\n");
		printf("\tlayer/node from:  ");
		scanf("%d/%d", &layfrom2, &nodefrom2);
		printf("\tlayer/node to:  ");
		scanf("%d/%d", &layto2, &nodeto2);
	} else {
		sscanf(args[1], "%d/%d,%d/%d",
			&layfrom1, &nodefrom1, &layto1, &nodeto1);
		sscanf(args[2], "%d/%d,%d/%d",
			&layfrom2, &nodefrom2, &layto2, &nodeto2);
	}
	sprintf(buf, "%d.%d/%d.%d and %d.%d/%d.%d",
		layfrom1, nodefrom1, layto1, nodeto1,
		layfrom2, nodefrom2, layto2, nodeto2);
	/*
	 * A: set up some flags, malloc space, save existing data structures
	 * B: 3 part loop:
	 *	for each value of wt1
	 *		for each value of wt2
	 *			for each pattern
	 *				copy in original network,
	 *				cycle and accumulate error
	 *			then plot the average across all patterns
	 * C: reset flags, free space
	 */
	test=1;
	nolearn=1;
	ecount=1;
	errsig=1;
	trun = run;
	run=0;	
	saveweights1("/tmp/learntmp");
	/* Dave made me do it */
	wtinc = ((wtstop+9999.0) - (wtstart+9999.0)) / wtstep;
	errdata = (float *) malloc(sizeof(float) * (wtstep*wtstep));
	bzero(errdata, (sizeof(float)*(wtstep*wtstep)));
	sizp1 = layer_descp + layfrom1;
	sizp2 = layer_descp + layfrom2;
	wp1 = weightp[layfrom1];
	wp2 = weightp[layfrom2];
	w1 = (wp1 + nodefrom1 + (nodeto1 * *sizp1));
	w2 = (wp2 + nodefrom2 + (nodeto2 * *sizp2));
	for (x=0; x<=wtstep; x++) {
		for (y=0; y<=wtstep;  y++) {
			loadweights1("/tmp/learntmp.0.wts");
			*w1 = wtstart + (wtinc * x);
			*w2 = wtstart + (wtinc * y);
			for (p=0; p<(int)ndtokens; p++) {
				cur_token = p;
				do_cycle(targs);
				*(errdata+x+(y*wtstep)) += global_error;
			}
			*(errdata+x+(y*wtstep)) /= (int)ndtokens;
		}
	}
	/*
	 * save result of stuff in an array
	 * pass array to xplot3_create.
	 */
	result = (float *) malloc(wtstep * wtstep * sizeof(float));
	ptr = result;
	max = -9999;
	min = 9999;
	for (x=0; x<wtstep; x++) {
		for (y=0; y<wtstep;  y++) {
			val = *(errdata+x+(y*wtstep));
			if (val < min)
				min = val;
			if (val > max)
				max = val;
			*ptr++ = val;
		}
	}
	loadweights1("/tmp/learntmp.0.wts");
	run = trun;
	test = 0; 
	nolearn = 0;
	ecount = 0;
	errsig = 0;
	/*
	 * Now that we have the data, we can set up the other
	 * xplot information
	 */
	Xp->doxyz = 0;
	Xp->Xtheta = 60;	/* give an initial rotation */
	Xp->Ytheta = 0;
	Xp->Ztheta = 85;
	Xp->X_scale = 1.0;
	Xp->Y_scale = 1.0;
	Xp->Z_scale = 1.0;
	Xp->data = result;
	Xp->numgraphs = wtstep;
	Xp->numz = wtstep;
	Xp->min_x = 0;
	Xp->max_x = wtstep;
	Xp->min_y = 0;
	Xp->max_y = wtstep;
	Xp->min_z = min;
	Xp->max_z = max;
	Xp->dpy = display;
	Xp->gc = wp->w_gc;
	Xp->plot = wp->w_win;
}

plot3_event(ep, wp)
	XEvent	*ep;
	struct	win *wp;
{
	struct	xpinfo *Xp;

	Xp = (struct xpinfo *) wp->w_data;
	switch (ep->type) {
	case Expose:
		if (win_resize(wp))
			plot3_resize(wp, Xp);
		plot3_repaint(wp, Xp);
		break;
	default:
		break;
	}
}

plot3_repaint(wp, xp)
	struct	win *wp;
	register struct xpinfo *xp;
{
	XClearWindow(display, wp->w_win);
	xplot(xp);
	XFlush(display);
	if (xp->wmap.first) {
			xp->Xtheta = 0;
			xp->Ytheta = 0;
			xp->Ztheta = 0;
		}
}
