#include <u.h>
#include <libc.h>
#include <draw.h>
#include <thread.h>
#include <mouse.h>
#include <keyboard.h>
#include <control.h>

typedef struct Label Label;

struct Label
{
	Control;
	int		border;
	CFont	*font;
	CImage	*image;
	CImage	*textcolor;
	CImage	*bordercolor;
	char		*text;
	int		align;
};

enum{
	EAlign,
	EBorder,
	EBordercolor,
	EFocus,
	EFont,
	EHide,
	EImage,
	ERect,
	EReveal,
	EShow,
	ESize,
	ETextcolor,
	EValue,
};

static char *cmds[] = {
	[EAlign] =			"align",
	[EBorder] =		"border",
	[EBordercolor] =	"bordercolor",
	[EFocus] = 		"focus",
	[EFont] =			"font",
	[EHide] =			"hide",
	[EImage] =		"image",
	[ERect] =			"rect",
	[EReveal] =		"reveal",
	[EShow] =			"show",
	[ESize] =			"size",
	[ETextcolor] =		"textcolor",
	[EValue] =			"value",
	nil
};

static void	labelshow(Label*);

static void
labelfree(Control *c)
{
	Label *l;

	l = (Label*)c;
	_putctlfont(l->font);
	_putctlimage(l->image);
	_putctlimage(l->textcolor);
	_putctlimage(l->bordercolor);
	free(l->text);
}


static void
labelshow(Label *l)
{
	Rectangle r;
	Point p;

	if (l->hidden)
		return;
	r = l->rect;
	draw(l->screen, r, l->image->image, nil, l->image->image->r.min);
	if(l->border > 0){
		border(l->screen, r, l->border, l->bordercolor->image, l->bordercolor->image->r.min);
		r = insetrect(r, l->border);
	}
	p = _ctlalignpoint(r,
		stringwidth(l->font->font, l->text),
		l->font->font->height, l->align);
	_string(l->screen, p, l->textcolor->image,
		ZP, l->font->font, l->text, nil, strlen(l->text),
		r, nil, ZP, SoverD);
	flushimage(display, 1);
}

static void
labelctl(Control *c, CParse *cp)
{
	int cmd;
	Rectangle r;
	Label *l;

	l = (Label*)c;
	cmd = _ctllookup(cp->args[0], cmds, nelem(cmds));
	switch(cmd){
	default:
		ctlerror("%q: unrecognized message '%s'", l->name, cp->str);
		break;
	case EAlign:
		_ctlargcount(l, cp, 2);
		l->align = _ctlalignment(cp->args[1]);
		break;
	case EBorder:
		_ctlargcount(l, cp, 2);
		if(cp->iargs[1] < 0)
			ctlerror("%q: bad border: %c", l->name, cp->str);
		l->border = cp->iargs[1];
		break;
	case EBordercolor:
		_ctlargcount(l, cp, 2);
		_setctlimage(l, &l->bordercolor, cp->args[1]);
		break;
	case EFocus:
		/* ignore focus change */
		break;
	case EFont:
		_ctlargcount(l, cp, 2);
		_setctlfont(l, &l->font, cp->args[1]);
		break;
	case EHide:
		_ctlargcount(l, cp, 1);
		l->hidden = 1;
		break;
	case EImage:
		_ctlargcount(l, cp, 2);
		_setctlimage(l, &l->image, cp->args[1]);
		break;
	case ERect:
		_ctlargcount(l, cp, 5);
		r.min.x = cp->iargs[1];
		r.min.y = cp->iargs[2];
		r.max.x = cp->iargs[3];
		r.max.y = cp->iargs[4];
		if(Dx(r)<=0 || Dy(r)<=0)
			ctlerror("%q: bad rectangle: %s", l->name, cp->str);
		l->rect = r;
		break;
	case EReveal:
		_ctlargcount(l, cp, 1);
		l->hidden = 0;
		labelshow(l);
		break;
	case EShow:
		_ctlargcount(l, cp, 1);
		labelshow(l);
		/*
		_ctlargcount(l, cp, 2);
		_setctlimage(l, &l->textcolor, cp->args[1]);
		*/
		break;
	case ESize:
		if (cp->nargs == 3)
			r.max = Pt(0x7fffffff, 0x7fffffff);
		else{
			_ctlargcount(l, cp, 5);
			r.max.x = cp->iargs[3];
			r.max.y = cp->iargs[4];
		}
		r.min.x = cp->iargs[1];
		r.min.y = cp->iargs[2];
		if(r.min.x<=0 || r.min.y<=0 || r.max.x<=0 || r.max.y<=0 || r.max.x < r.min.x || r.max.y < r.min.y)
			ctlerror("%q: bad sizes: %s", l->name, cp->str);
		l->size.min = r.min;
		l->size.max = r.max;
		break;
	case ETextcolor:
		_ctlargcount(l, cp, 2);
		_setctlimage(l, &l->textcolor, cp->args[1]);
		break;
	case EValue:
		_ctlargcount(l, cp, 2);
		if(strcmp(cp->args[1], l->text) != 0){
			free(l->text);
			l->text = ctlstrdup(cp->args[1]);
			labelshow(l);
		}
		break;
	}
}

Control*
createlabel(Controlset *cs, char *name)
{
	Label *l;

	l = (Label*)_createctl(cs, "label", sizeof(Label), name);
	l->text = ctlstrdup("");
	l->image = _getctlimage("white");
	l->textcolor = _getctlimage("black");
	l->bordercolor = _getctlimage("black");
	l->font = _getctlfont("font");
	l->border = 0;
	l->ctl = labelctl;
	l->exit = labelfree;
	return (Control *)l;
}
