// 9 june 2016
#include "uipriv_unix.h"

struct gridChild {
	uiControl *c;
	GtkWidget *label;
	gboolean oldhexpand;
	GtkAlign oldhalign;
	gboolean oldvexpand;
	GtkAlign oldvalign;
};

struct uiGrid {
	uiUnixControl c;
	GtkWidget *widget;
	GtkContainer *container;
	GtkGrid *grid;
	GArray *children;
	int padded;
};

uiUnixControlAllDefaultsExceptDestroy(uiGrid)

#define ctrl(g, i) &g_array_index(g->children, struct gridChild, i)

static void uiGridDestroy(uiControl *c)
{
	uiGrid *g = uiGrid(c);
	struct gridChild *gc;
	guint i;

	// free all controls
	for (i = 0; i < g->children->len; i++) {
		gc = ctrl(g, i);
		uiControlSetParent(gc->c, NULL);
		uiUnixControlSetContainer(uiUnixControl(gc->c), g->container, TRUE);
		uiControlDestroy(gc->c);
	}
	g_array_free(g->children, TRUE);
	// and then ourselves
	g_object_unref(g->widget);
	uiFreeControl(uiControl(g));
}

#define TODO_MASSIVE_HACK(c) \
	if (!uiUnixControl(c)->addedBefore) { \
		g_object_ref_sink(GTK_WIDGET(uiControlHandle(uiControl(c)))); \
		gtk_widget_show(GTK_WIDGET(uiControlHandle(uiControl(c)))); \
		uiUnixControl(c)->addedBefore = TRUE; \
	}

static const GtkAlign gtkAligns[] = {
	[uiAlignFill] = GTK_ALIGN_FILL,
	[uiAlignStart] = GTK_ALIGN_START,
	[uiAlignCenter] = GTK_ALIGN_CENTER,
	[uiAlignEnd] = GTK_ALIGN_END,
};

static const GtkPositionType gtkPositions[] = {
	[uiAtLeading] = GTK_POS_LEFT,
	[uiAtTop] = GTK_POS_TOP,
	[uiAtTrailing] = GTK_POS_RIGHT,
	[uiAtBottom] = GTK_POS_BOTTOM,
};

static GtkWidget *prepare(struct gridChild *gc, uiControl *c, int hexpand, uiAlign halign, int vexpand, uiAlign valign)
{
	GtkWidget *widget;

	gc->c = c;
	widget = GTK_WIDGET(uiControlHandle(gc->c));
	gc->oldhexpand = gtk_widget_get_hexpand(widget);
	gc->oldhalign = gtk_widget_get_halign(widget);
	gc->oldvexpand = gtk_widget_get_vexpand(widget);
	gc->oldvalign = gtk_widget_get_valign(widget);
	gtk_widget_set_hexpand(widget, hexpand != 0);
	gtk_widget_set_halign(widget, gtkAligns[halign]);
	gtk_widget_set_vexpand(widget, vexpand != 0);
	gtk_widget_set_valign(widget, gtkAligns[valign]);
	return widget;
}

void uiGridAppend(uiGrid *g, uiControl *c, int left, int top, int xspan, int yspan, int hexpand, uiAlign halign, int vexpand, uiAlign valign)
{
	struct gridChild gc;
	GtkWidget *widget;

	widget = prepare(&gc, c, hexpand, halign, vexpand, valign);
	uiControlSetParent(gc.c, uiControl(g));
	TODO_MASSIVE_HACK(uiUnixControl(gc.c));
	gtk_grid_attach(g->grid, widget,
		left, top,
		xspan, yspan);
	g_array_append_val(g->children, gc);
}

void uiGridInsertAt(uiGrid *g, uiControl *c, uiControl *existing, uiAt at, int xspan, int yspan, int hexpand, uiAlign halign, int vexpand, uiAlign valign)
{
	struct gridChild gc;
	GtkWidget *widget;

	widget = prepare(&gc, c, hexpand, halign, vexpand, valign);
	uiControlSetParent(gc.c, uiControl(g));
	TODO_MASSIVE_HACK(uiUnixControl(gc.c));
	gtk_grid_attach_next_to(g->grid, widget,
		GTK_WIDGET(uiControlHandle(existing)), gtkPositions[at],
		xspan, yspan);
	g_array_append_val(g->children, gc);
}

int uiGridPadded(uiGrid *g)
{
	return g->padded;
}

void uiGridSetPadded(uiGrid *g, int padded)
{
	g->padded = padded;
	if (g->padded) {
		gtk_grid_set_row_spacing(g->grid, uiprivGTKYPadding);
		gtk_grid_set_column_spacing(g->grid, uiprivGTKXPadding);
	} else {
		gtk_grid_set_row_spacing(g->grid, 0);
		gtk_grid_set_column_spacing(g->grid, 0);
	}
}

uiGrid *uiNewGrid(void)
{
	uiGrid *g;

	uiUnixNewControl(uiGrid, g);

	g->widget = gtk_grid_new();
	g->container = GTK_CONTAINER(g->widget);
	g->grid = GTK_GRID(g->widget);

	g->children = g_array_new(FALSE, TRUE, sizeof (struct gridChild));

	return g;
}