/*
 * box.c
 *
 * create xlearn boxes and randomly fill them up
 *
 */

#include <stdio.h>
#include <errno.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/file.h>
#include <X/Xlib.h>
#include "defs.h"
#include "win.h"
#include "box.h"

XAssocTable	*win_table;
int	box;
int	box_event();

struct	win *box_hidden;
struct	win *box_output;

box_cmd(args) 
	char	*args[];
{
	extern	struct win *win_leftmouse();
	extern	char fileroot[];
	extern	int dispout;
	extern	int disphid;
	extern	int no_X;
	struct	boxinfo *bp;
	struct	win *wp;
	char	buf[80];
	int	type;
	int	i;

	if (no_X) {
		fprintf(stderr, "No X display\n");
		return;
	}
	if (args[1] && startsame(args[1], "close")) {
		wp = win_leftmouse("hit left mouse in window to be killed\n");
		if (wp == 0)
			return;
		XDeleteAssoc(win_table, wp->w_win, wp);
		bp = (struct boxinfo *) wp->w_data;
		for (i=0; i<bp->lwidth; i++)
			free(bp->collabels[i]);
		free(bp->collabels);
		for (i=0; i<bp->lheight; i++)
			free(bp->rowlabels[i]);
		free(bp->rowlabels);
		free(bp->map);
		if (bp->what == BOX_HID) {
			box_hidden = 0;
			disphid--;
		} else {
			box_output = 0;
			dispout--;
		}
		box--;
		win_destroy(wp);
		XFlush();
		return;
	}
	if (fileroot[0] == NULL) {
		printf("No fileroot specified.\n");
		return -1;
	}
	if (args[1] == NULL)  {
		printf("output units or hidden units [o/h]? ");
		gets(buf);
	} else {
		strcpy(buf, args[1]);
	}
	if (startsame(buf, "output")) {
		type = BOX_OUT;
	} else if (startsame(buf, "hidden")) {
		type = BOX_HID;
	} else {
		printf("%s: unknown\n", buf);
		return -1;
	}
	return box_create(type);
}

box_create(type)
	int	type;
{
	extern	Display *display;
	extern	struct win *win_create();
	extern	char *strsave();
	extern	int *layer_descp;
	extern	int nlayers;
	extern	int num_hidden;
	extern	char *progname;
	extern	FontInfo fi;
	extern	char title[];
	extern	int width;
	extern	int height;
	extern	char type_list[1000][50];
	Window	win;
	int	i;
	int	n;
	int	minw;
	int	minh;
	char	geom[32];
	char	*label;
	char	buf[80];
	struct	win *wp;
	struct	boxinfo *bp;
	OpaqueFrame frame;

	if (display == 0 && win_init(0) == 0)
		return;
	bp = (struct boxinfo *) calloc(sizeof(*bp), 1);
	if (type == BOX_OUT)
		n = *(layer_descp+nlayers-1);
	else
		n = num_hidden; 
	bp->lwidth = width;
	bp->lheight = height;
	bp->boxwidth = BOX_WIDTH;
	bp->boxheight = BOX_HEIGHT;
	bp->bitwidth = (bp->lwidth * bp->boxwidth + 15) & ~0xf;
	bp->bitheight = bp->lheight * bp->boxheight;
	bp->mapx = 7 * (fi.width + 2);
	bp->mapy = 4 * (fi.height + 2);
	bp->map = (char *) malloc(BitmapSize(bp->bitwidth, bp->bitheight));
	minw = bp->bitwidth + bp->mapx;
	minh = bp->bitheight + bp->mapy;
	bzero(bp->map, BitmapSize(bp->bitwidth, bp->bitheight));
	sprintf(geom, "%dx%d-0-0", minw, minh);
	if (type == BOX_HID)
		label = "box: hidden";
	else
		label = "box: output";
	if ((wp = win_create(label, geom)) == 0) {
		printf("window creation failed\n");
		free(bp->map);
		free(bp);
		return 0;
	}
	strcpy(bp->name, label);
	wp->w_data = (char *) bp;
	wp->w_event = box_event;
	bp->what = type;
	if (type == BOX_OUT) {
		box_output = wp;
		dispout++;
	} else {
		box_hidden = wp;
		disphid++;
	}
	bp->rowlabels = (char **) malloc((width+1) * sizeof(char *));
	bp->collabels = (char **) malloc((height+1) * sizeof(char *));
	for (i=0; i<width; i++)
		bp->collabels[i] = strsave(sprintf(buf, "%d", i));
	bp->collabels[i] = 0;
	for (i=0; i<height; i++)
		bp->rowlabels[i] = strsave(type_list[i]);
	bp->rowlabels[i] = 0;
	XMakeAssoc(win_table, wp->w_win, wp);
	XMapWindow(wp->w_win);
	XClear(wp->w_win);
	labels(wp, bp);
	box++;
	return 1;
}

int
box_dot(type, x, y, on)
	int	type;
	int	x;
	int	y;
	int	on;
{
	register struct boxinfo *bp;
	register struct win *wp;
	register int xoff;
	register int yoff;
	register short *ptr;

	if (type == BOX_HID)
		wp = box_hidden;
	else
		wp = box_output;
	bp = (struct boxinfo *) wp->w_data;
	xoff = (random() % bp->boxwidth) + x * bp->boxwidth;
	yoff = (random() % bp->boxheight) + y * bp->boxheight;
	if (xoff < 0 || xoff > bp->bitwidth || yoff < 0 ||
	    yoff > bp->bitheight) {
		fprintf(stderr, "bot_dot: Bad x/y (%d,%d)\n",
			xoff/bp->boxwidth, yoff/bp->boxheight);
		return;
	}
	XPixSet(wp->w_win, xoff + bp->mapx, yoff + bp->mapy, 1, 1,
		on ? wp->w_forepixel : wp->w_backpixel);
	ptr = (short *) (bp->map + BitmapSize(bp->bitwidth, 1) * yoff);
	ptr += xoff/16;
	if (on)
		*ptr |= (1 << (xoff % 16));
	else
		*ptr &= ~(1 << (xoff % 16));
}

box_event(ep, wp)
	XEvent	*ep;
	struct	win *wp;
{
	extern	int interactive;
	struct	boxinfo *bp;

	bp = (struct boxinfo *) wp->w_data;
	switch (ep->type) {
	case ExposeWindow:
		win_resize(wp);
		/* fall thru */
	case EnterWindow:
	case ExposeRegion:
	case ExposeCopy:
		XClear(wp->w_win);
		labels(wp, bp);
		XBitmapBitsPut(wp->w_win, bp->mapx, bp->mapy, bp->bitwidth,
			bp->bitheight, bp->map, wp->w_forepixel,
			wp->w_backpixel, 0, GXcopy, AllPlanes);
		break;
	default:
		break;
	}
}

labels(wp, bp)
	register struct win *wp;
	register struct boxinfo *bp;
{
	extern	Font font;
	char	*p;
	int	i, j, k;
	int	len;
	int	cw;
	char	buf[2];

	buf[1] = 0;
	for (i=0; p = bp->collabels[i]; i++) {
		len = strlen(p);
		if (len > 3)
			len = 3;
		for (j=len-1,k=0; j >= 0; j--, k++) {
			buf[0] = p[k];
			XTextMask(wp->w_win,
				i * bp->boxwidth + bp->mapx + bp->boxwidth/2,
				fi.height * (j + 2), buf, 1, font,
				wp->w_forepixel);
		}
	}
	for (i=0; p = bp->rowlabels[i]; i++) {
		XTextMask(wp->w_win, fi.width,
			(i * bp->boxheight) + bp->mapy + fi.height/2,
			p, strlen(p), font, wp->w_forepixel);
	}
	XTextMask(wp->w_win, 3, 3, bp->name, strlen(bp->name),
		font, wp->w_forepixel);
}
