#include <u.h>
#include <libc.h>
#include <draw.h>
#include <cursor.h>
#include <event.h>
#include <bio.h>
#include "proof.h"

static	int	checkmouse(void);
static	int	buttondown(void);
static	char	*getmousestr(void);
static	char	*getkbdstr(int);

extern	Cursor	blot;
extern	char	*track;

Mouse	mouse;

void
mapscreen(void)
{
	if(initdraw(0, 0, "proof") < 0){
		fprint(2, "proof: initdraw failed: %r\n");
		exits("initdraw");
	}
	einit(Ekeyboard|Emouse);
}

void
clearscreen(void)
{
	draw(screen, screen->r, display->black, nil, ZP);
}

void
screenprint(char *fmt, ...)
{
	char buf[100];
	Point p;
	va_list args;

	va_start(args, fmt);
	vseprint(buf, &buf[sizeof buf], fmt, args);
	va_end(args);
	p = Pt(screen->clipr.min.x+40, screen->clipr.max.y-40);
	string(screen, p, display->black, ZP, font, buf);
}

#define	Viewkey	0xb2

char *
getcmdstr(void)
{
	Event ev;
	int e;
	static ulong timekey = 0;
	ulong tracktm = 0;
	Dir *dir;

	if(track){
		if(timekey == 0)
			timekey = etimer(0, 5000);
		dir = dirstat(track);
		if(dir != nil){
			tracktm = dir->mtime;
			free(dir);
		}
	}
	for (;;) {
		e = event(&ev);
		if(resized){
			resized = 0;
			return "p";
		}
		if ((e & Emouse) && ev.mouse.buttons) {
			mouse = ev.mouse;
			return getmousestr();
		} else if (e & Ekeyboard)
			return getkbdstr(ev.kbdc);	/* sadly, no way to unget */
		else if (e & timekey) {
			if((dir = dirstat(track)) != nil){
				if(tracktm < dir->mtime){
					free(dir);
					return "q";
				}
				free(dir);
			}
		}
	}
}

static char *
getkbdstr(int c0)
{
	static char buf[100];
	char *p;
	int c;

	if (c0 == '\n')
		return "";
	buf[0] = c0;
	buf[1] = 0;
	screenprint("%s", buf);
	for (p = buf+1; (c = ekbd()) != '\n' && c != '\r' && c != -1 && c != Viewkey; ) {
		if (c == '\b' && p > buf) {
			*--p = ' ';
		} else {
			*p++ = c;
			*p = 0;
		}
		screenprint("%s", buf);
	}
	*p = 0;
	return buf;
}


#define button3(b)	((b) & 4)
#define button2(b)	((b) & 2)
#define button1(b)	((b) & 1)
#define button23(b)	((b) & 6)
#define button123(b)	((b) & 7)

#define	butcvt(b)	(1 << ((b) - 1))

static int buttondown(void)	/* report state of buttons, if any */
{
	if (!ecanmouse())	/* no event pending */
		return 0;
	mouse = emouse();	/* something, but it could be motion */
	return mouse.buttons & 7;
}

int waitdown(void)	/* wait until some button is down */
{
	while (!(mouse.buttons & 7))
		mouse = emouse();
	return mouse.buttons & 7;
}

int waitup(void)
{
	while (mouse.buttons & 7)
		mouse = emouse();
	return mouse.buttons & 7;
}

char *m3[]	= { "next", "prev", "page n", "again", "bigger", "smaller", "pan", "quit?", 0 };
char *m2[]	= { 0 };

enum { Next = 0, Prev, Page, Again, Bigger, Smaller, Pan, Quit };

Menu	mbut3	= { m3, 0, 0 };
Menu	mbut2	= { m2, 0, 0 };

int	last_hit;
int	last_but;

char *pan(void)
{
	Point dd, xy, lastxy, min, max;

	esetcursor(&blot);
	waitdown();
	xy = mouse.xy;
	do{
		lastxy = mouse.xy;
		mouse = emouse();
		dd = subpt(mouse.xy, lastxy);
		min = addpt(screen->clipr.min, dd);
		max = addpt(screen->clipr.max, dd);
		draw(screen, rectaddpt(screen->r, subpt(mouse.xy, lastxy)),
			screen, nil, screen->r.min);
		if(mouse.xy.x < lastxy.x)	/* moved left, clear right */
			draw(screen, Rect(max.x, screen->r.min.y, screen->r.max.x, screen->r.max.y),
				display->white, nil, ZP);
		else	/* moved right, clear left*/
			draw(screen, Rect(screen->r.min.x, screen->r.min.y, min.x, screen->r.max.y),
				display->white, nil, ZP);
		if(mouse.xy.y < lastxy.y)	/* moved up, clear down */
			draw(screen, Rect(screen->r.min.x, max.y, screen->r.max.x, screen->r.max.y),
				display->white, nil, ZP);
		else		/* moved down, clear up */
			draw(screen, Rect(screen->r.min.x, screen->r.min.y, screen->r.max.x, min.y),
				display->white, nil, ZP);
		flushimage(display, 1);
	}while(mouse.buttons);

	xyoffset = addpt(xyoffset, subpt(mouse.xy, xy));

	esetcursor(0);
	return "p";
}

static char *
getmousestr(void)
{
	static char buf[64];

	checkmouse();
	if (last_but == 1)
		return "p";	/* repaint after panning */
	if (last_but == 2) {
		return "c";
	} else if (last_but == 3) {
		switch (last_hit) {
		case Next:
			return "";
		case Prev:
			return "-1";
		case Page:
			screenprint("page? ");
			return "c";
		case Again:
			return "p";
		case Bigger:
			snprint(buf, sizeof buf, "m%g", mag * 1.1);
			return buf;
		case Smaller:
			snprint(buf, sizeof buf, "m%g", mag / 1.1);
			return buf;
		case Pan:
			return pan();
		case Quit:
			return "q";
		default:
			return "c";
		}
	} else {		/* button 1 or bail out */
		return "c";
	}
}

static int
checkmouse(void)	/* return button touched if any */
{
	int c, b;
	char *p;
	extern int confirm(int);

	b = waitdown();
	last_but = 0;
	last_hit = -1;
	c = 0;
	if (button3(b)) {
		last_hit = emenuhit(3, &mouse, &mbut3);
		last_but = 3;
	} else if (button2(b)) {
		last_hit = emenuhit(2, &mouse, &mbut2);
		last_but = 2;
	} else {		/* button1() */
		pan();
		last_but = 1;
	}
	waitup();
	if (last_but == 3 && last_hit >= 0) {
		p = m3[last_hit];
		c = p[strlen(p) - 1];
	}
	if (c == '?' && !confirm(last_but))
		last_hit = -1;
	return last_but;
}

Cursor deadmouse = {
	{ 0, 0},	/* offset */
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	  0x00, 0x00, 0x00, 0x0C, 0x00, 0x82, 0x04, 0x41,
	  0xFF, 0xE1, 0x5F, 0xF1, 0x3F, 0xFE, 0x17, 0xF0,
	  0x03, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	  0x00, 0x00, 0x00, 0x0C, 0x00, 0x82, 0x04, 0x41,
	  0xFF, 0xE1, 0x5F, 0xF1, 0x3F, 0xFE, 0x17, 0xF0,
	  0x03, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }
};

Cursor blot ={
	{ 0, 0 },
	{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, },
	{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }
};

Cursor skull ={
	{ 0, 0 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x03,
	  0xE7, 0xE7, 0x3F, 0xFC, 0x0F, 0xF0, 0x0D, 0xB0,
	  0x07, 0xE0, 0x06, 0x60, 0x37, 0xEC, 0xE4, 0x27,
	  0xC3, 0xC3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x03,
	  0xE7, 0xE7, 0x3F, 0xFC, 0x0F, 0xF0, 0x0D, 0xB0,
	  0x07, 0xE0, 0x06, 0x60, 0x37, 0xEC, 0xE4, 0x27,
	  0xC3, 0xC3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }
};

confirm(int but)	/* ask for confirmation if menu item ends with '?' */
{
	int c;
	static int but_cvt[8] = { 0, 1, 2, 0, 3, 0, 0, 0 };

	esetcursor(&skull);
	c = waitdown();
	waitup();
	esetcursor(0);
	return but == but_cvt[c];
}
