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

typedef struct Radio Radio;

struct Radio
{
	Control;
	int		value;
	int		lastbut;
	Control	**buttons;
	int		nbuttons;
	char		*eventstr;
};

enum{
	EAdd,
	EButton,
	EFocus,
	EFormat,
	EHide,
	ERect,
	EReveal,
	EShow,
	ESize,
	EValue,
};

static char *cmds[] = {
	[EAdd] =		"add",
	[EButton] =	"button",
	[EFocus] = 	"focus",
	[EFormat] = 	"format",
	[EHide] =		"hide",
	[ERect] =		"rect",
	[EReveal] =	"reveal",
	[EShow] =		"show",
	[ESize] =		"size",
	[EValue] =		"value",
	nil
};

static void	radioshow(Radio*);

static void
radiomouse(Control *c, Mouse *m)
{
	Radio *r;
	int i;

	r = (Radio*)c;
	for(i=0; i<r->nbuttons; i++)
		if(ptinrect(m->xy, r->buttons[i]->rect) && r->buttons[i]->mouse){
			(r->buttons[i]->mouse)(r->buttons[i], m);
			break;
		}
}

static void
radioshow(Radio *r)
{
	int i;

	if (r->hidden)
		return;
	for(i=0; i<r->nbuttons; i++){
		_ctlprint(r->buttons[i], "value %d", (r->value==i));
		_ctlprint(r->buttons[i], "show");
	}
}

static void
radioctl(Control *c, CParse *cp)
{
	int cmd, i;
	Rectangle rect;
	Radio *r;
	char fmt[256];

	r = (Radio*)c;

	cmd = _ctllookup(cp->args[0], cmds, nelem(cmds));
	switch(cmd){
	default:
		ctlerror("%q: unrecognized message '%s'", r->name, cp->str);
		break;
	case EAdd:
		_ctlargcount(r, cp, 2);
		c = controlcalled(cp->args[1]);
		if(c == nil)
			ctlerror("%q: can't add %s: %r", r->name, cp->args[1]);
		snprint(fmt, sizeof fmt, "%%q: %q button %%d", r->name);
		_ctlprint(c, "format %q", fmt);
		controlwire(c, "event", c->controlset->ctl);
		r->buttons = ctlrealloc(r->buttons, (r->nbuttons+1)*sizeof(Control*));
		r->buttons[r->nbuttons] = c;
		r->nbuttons++;
		r->value = -1;
		radioshow(r);
		break;
	case EButton:
		if (cp->sender == nil)
			ctlerror("%q: senderless buttonevent: %q", r->name, cp->str);
		c = controlcalled(cp->sender);
		for(i=0; i<r->nbuttons; i++)
			if (c == r->buttons[i])
				break;
		if (i == r->nbuttons)
			ctlerror("%q: not my event: %q", r->name, cp->str);
		if(cp->iargs[1] == 0){
			/* button was turned off; turn it back on */
			_ctlprint(c, "value 1");
		}else{
			r->value = i;
			chanprint(r->event, r->format, r->name, i);
			radioshow(r);
		}
		break;
	case EFormat:
		_ctlargcount(r, cp, 2);
		r->format = ctlstrdup(cp->args[1]);
		break;
	case EHide:
		_ctlargcount(r, cp, 1);
		r->hidden = 1;
		break;
	case EFocus:
		/* ignore focus change */
		break;
	case ERect:
		_ctlargcount(r, cp, 5);
		rect.min.x = cp->iargs[1];
		rect.min.y = cp->iargs[2];
		rect.max.x = cp->iargs[3];
		rect.max.y = cp->iargs[4];
		r->rect = rect;
		break;
	case EReveal:
		_ctlargcount(r, cp, 1);
		r->hidden = 0;
		radioshow(r);
		break;
	case EShow:
		_ctlargcount(r, cp, 1);
		radioshow(r);
		break;
	case ESize:
		if (cp->nargs == 3)
			rect.max = Pt(0x7fffffff, 0x7fffffff);
		else{
			_ctlargcount(r, cp, 5);
			rect.max.x = cp->iargs[3];
			rect.max.y = cp->iargs[4];
		}
		rect.min.x = cp->iargs[1];
		rect.min.y = cp->iargs[2];
		if(rect.min.x<=0 || rect.min.y<=0 || rect.max.x<=0 || rect.max.y<=0 || rect.max.x < rect.min.x || rect.max.y < rect.min.y)
			ctlerror("%q: bad sizes: %s", r->name, cp->str);
		r->size.min = rect.min;
		r->size.max = rect.max;
		break;
	case EValue:
		_ctlargcount(r, cp, 2);
		r->value = cp->iargs[1];
		radioshow(r);
		break;
	}
}

Control*
createradiobutton(Controlset *cs, char *name)
{
	Radio *r;

	r = (Radio*)_createctl(cs, "label", sizeof(Radio), name);
	r->format = ctlstrdup("%q: value %d");
	r->value = -1;	/* nobody set at first */
	r->mouse = radiomouse;
	r->ctl = radioctl;
	return (Control*)r;
}
