// 7 april 2015
#include "uipriv_unix.h"

typedef struct uiSingleWidgetControl uiSingleWidgetControl;

struct uiSingleWidgetControl {
	uiControl control;
	GtkWidget *widget;
	GtkWidget *scrolledWindow;
	GtkWidget *immediate;		// the widget that is added to the parent container; either widget or scrolledWindow
	void *data;
	uintptr_t parent;
};

#define S(c) ((uiSingleWidgetControl *) (c))

static void singleDestroy(uiControl *c)
{
	gtk_widget_destroy(S(c)->immediate);
}

static uintptr_t singleHandle(uiControl *c)
{
	return (uintptr_t) (S(c)->widget);
}

static void singleSetParent(uiControl *c, uintptr_t parent)
{
	uiSingleWidgetControl *s = S(c);
	uintptr_t oldparent;

	oldparent = s->parent;
	s->parent = parent;
	if (oldparent != 0)
		gtk_container_remove(GTK_CONTAINER(oldparent), s->immediate);
	gtk_container_add(GTK_CONTAINER(s->parent), s->immediate);
	updateParent(oldparent);
	updateParent(s->parent);
}

static uiSize singlePreferredSize(uiControl *c, uiSizing *d)
{
	uiSize size;
	GtkRequisition natural;

	// use the natural size as the minimum size is an *absolute* minimum
	// for example, if a label has ellipsizing on, it can be the width of the ellipses, not the text
	// there is a warning about height-for-width sizing, but in my tests this isn't an issue
	gtk_widget_get_preferred_size(S(c)->widget, NULL, &natural);
	size.width = natural.width;
	size.height = natural.height;
	return size;
}

static void singleResize(uiControl *c, intmax_t x, intmax_t y, intmax_t width, intmax_t height, uiSizing *d)
{
	GtkAllocation a;

	a.x = x;
	a.y = y;
	a.width = width;
	a.height = height;
	gtk_widget_size_allocate(S(c)->immediate, &a);
}

static void onDestroy(GtkWidget *widget, gpointer data)
{
	uiSingleWidgetControl *c = (uiSingleWidgetControl *) data;

	uiFree(c);
}

uiControl *uiUnixNewControl(GType type, gboolean inScrolledWindow, gboolean scrolledWindowHasBorder, void *data, const char *firstProperty, ...)
{
	uiSingleWidgetControl *c;
	va_list ap;

	c = uiNew(uiSingleWidgetControl);

	va_start(ap, firstProperty);
	c->widget = GTK_WIDGET(g_object_new_valist(type, firstProperty, ap));
	va_end(ap);
	c->immediate = c->widget;

	if (inScrolledWindow) {
		c->scrolledWindow = gtk_scrolled_window_new(NULL, NULL);
		if (!GTK_IS_SCROLLABLE(c->widget))
			gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(c->scrolledWindow), c->widget);
		else
			gtk_container_add(GTK_CONTAINER(c->scrolledWindow), c->widget);
		if (scrolledWindowHasBorder)
			gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(c->scrolledWindow), GTK_SHADOW_IN);
		c->immediate = c->scrolledWindow;
	}

	// we need to keep an extra reference on the immediate widget
	// this is so uiControlDestroy() can work regardless of when it is called and who calls it
	// without this:
	// - end user call works (only one ref)
	// - call in uiContainer destructor fails (uiContainer ref freed)
	// with this:
	// - end user call works (shoudn't be in any container)
	// - call in uiContainer works (both refs freed)
	// this also ensures singleSetParent() works properly when changing parents
	g_object_ref_sink(c->immediate);
	// and let's free the uiSingleWidgetControl with it
	g_signal_connect(c->immediate, "destroy", G_CALLBACK(onDestroy), c);

	c->control.destroy = singleDestroy;
	c->control.handle = singleHandle;
	c->control.setParent = singleSetParent;
	c->control.preferredSize = singlePreferredSize;
	c->control.resize = singleResize;

	c->data = data;

	return (uiControl *) c;
}

void *uiUnixControlData(uiControl *c)
{
	return S(c)->data;
}