#include	<9pm/u.h>
#include	<9pm/libc.h>
#include	<9pm/draw.h>
#include	<9pm/memdraw.h>
#include	<9pm/cursor.h>
#include	<9pm/ns.h>
#include	<9pm/thread.h>
#include	<9pm/screen.h>

Memimage *gscreen;
Cursor	arrow = {
	{ -1, -1 },
	{ 0xFF, 0xFF, 0x80, 0x01, 0x80, 0x02, 0x80, 0x0C, 
	  0x80, 0x10, 0x80, 0x10, 0x80, 0x08, 0x80, 0x04, 
	  0x80, 0x02, 0x80, 0x01, 0x80, 0x02, 0x8C, 0x04, 
	  0x92, 0x08, 0x91, 0x10, 0xA0, 0xA0, 0xC0, 0x40, 
	},
	{ 0x00, 0x00, 0x7F, 0xFE, 0x7F, 0xFC, 0x7F, 0xF0, 
	  0x7F, 0xE0, 0x7F, 0xE0, 0x7F, 0xF0, 0x7F, 0xF8, 
	  0x7F, 0xFC, 0x7F, 0xFE, 0x7F, 0xFC, 0x73, 0xF8, 
	  0x61, 0xF0, 0x60, 0xE0, 0x40, 0x40, 0x00, 0x00, 
	},
};

int
cursoron(int dolock)
{
	int v;

	if(dolock)
		lock(&cursor.lk);
	v = cursormove(mousexy());
	if(dolock)
		unlock(&cursor.lk);

	return v;
}

void
getcolor(ulong p, ulong *pr, ulong *pg, ulong *pb)
{
	*pr = p;
	*pg = p;
	*pb = p;
}

int
setcolor(ulong i, ulong r, ulong g, ulong b)
{	
	USED(i);
	USED(r);
	USED(g);
	USED(b);
	return ~0;
}

static Memimage* back;
static Memimage *conscol;
static Memsubfont *memdefont;

static Point curpos;
static Rectangle window;
static int *xp;
static int xbuf[256];
static Lock screenlock;
int _drawdebug;

static void
drawconsscroll(void)
{
	int h, o;
	Point p;
	Rectangle r;

	h = memdefont->height;
	o = 8*h;
	r = Rpt(window.min, Pt(window.max.x, window.max.y-o));
	p = Pt(window.min.x, window.min.y+o);
	memimagedraw(gscreen, r, gscreen, p, nil, p);
	r = Rpt(Pt(window.min.x, window.max.y-o), window.max);
	memimagedraw(gscreen, r, back, ZP, nil, ZP);

	curpos.y -= o;
}

static void
drawconsputc(char* buf, Rectangle *flushr)
{
	Point p;
	int h, w, pos;
	Rectangle r;

	if(xp < xbuf || xp >= &xbuf[sizeof(xbuf)])
		xp = xbuf;

	h = memdefont->height;
	switch(buf[0]){

	case '\n':
		if(curpos.y+h >= window.max.y){
			drawconsscroll();
			*flushr = window;
		}
		curpos.y += h;
		drawconsputc("\r", flushr);
		break;

	case '\r':
		xp = xbuf;
		curpos.x = window.min.x;
		break;

	case '\t':
		p = memsubfontwidth(memdefont, " ");
		w = p.x;
		if(curpos.x >= window.max.x-4*w)
			drawconsputc("\n", flushr);

		pos = (curpos.x-window.min.x)/w;
		pos = 4-(pos%4);
		*xp++ = curpos.x;
		r = Rect(curpos.x, curpos.y, curpos.x+pos*w, curpos.y + h);
		memimagedraw(gscreen, r, back, back->r.min, nil, back->r.min);
		curpos.x += pos*w;
		break;

	case '\b':
		if(xp <= xbuf)
			break;
		xp--;
		r = Rect(*xp, curpos.y, curpos.x, curpos.y+h);
		memimagedraw(gscreen, r, back, back->r.min, nil, ZP);
		combinerect(flushr, r);
		curpos.x = *xp;
		break;

	case '\0':
		break;

	default:
		p = memsubfontwidth(memdefont, buf);
		w = p.x;

		if(curpos.x >= window.max.x-w)
			drawconsputc("\n", flushr);

		*xp++ = curpos.x;
		r = Rect(curpos.x, curpos.y, curpos.x+w, curpos.y+h);
		memimagedraw(gscreen, r, back, back->r.min, nil, back->r.min);
		memimagestring(gscreen, curpos, conscol, ZP, memdefont, buf);
		combinerect(flushr, r);
		curpos.x += w;
	}
}

static void
drawconsputs(char* s, int n)
{
	int i;
	Rune r;
	char buf[4];
	Rectangle flushr;

	lock(&screenlock);
	flushr = Rect(10000, 10000, -10000, -10000);
	while(n > 0){
		i = chartorune(&r, s);
		if(i == 0){
			s++;
			--n;
			continue;
		}
		memmove(buf, s, i);
		buf[i] = 0;
		n -= i;
		s += i;
		drawconsputc(buf, &flushr);
	}
	flushmemscreen(flushr);
	unlock(&screenlock);
}

void
drawconsinit(void)
{
	Memimage *grey;
	int h, w;
	char *greet;
	Point p, q;

	kbdq = qopen(4*1024, 0, 0, 0);
	if(kbdq == nil)
		panic("kbdinit");
	qnoblock(pm_kbdq, 1);

	back = memwhite;
	conscol = memblack;
	memfillcolor(gscreen, 0x444488FF);

	memdefont = getmemdefont();
	h = memdefont->height;
	w = memdefont->info[' '].width;

	window = insetrect(gscreen->r, 48);
	window.max.x = window.min.x+((window.max.x-window.min.x)/w)*w;
	window.max.y = window.min.y+((window.max.y-window.min.y)/h)*h;
	memimagedraw(gscreen, window, memblack, ZP, memopaque, ZP);
	window = insetrect(window, 4);
	memimagedraw(gscreen, window, memwhite, ZP, memopaque, ZP);

	/* a lot of work to get a grey color */
	grey = allocmemimage(Rect(0,0,1,1), CMAP8);
	grey->flags |= Frepl;
	grey->clipr = gscreen->r;
	grey->data->bdata[0] = 0xAA;
	memimagedraw(gscreen, Rect(window.min.x, window.min.y,
			window.max.x, window.min.y+h+5+6), grey, ZP, nil, ZP);
	freememimage(grey);
	window = insetrect(window, 5);

	greet = " Drawterm Console (9P2000) ";
	p = addpt(window.min, Pt(10, 0));
	q = memsubfontwidth(memdefont, greet);
	memimagestring(gscreen, p, conscol, ZP, memdefont, greet);
	window.min.y += h+6;
	curpos = window.min;
	window.max.y = window.min.y+((window.max.y-window.min.y)/h)*h;
	flushmemscreen(gscreen->r);

	screenputs = drawconsputs;
}

