/* This file is part of the hkl library.
 *
 * The hkl library is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * The hkl library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with the hkl library.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Copyright (C) 2003-2019, 2022, 2024, 2025 Synchrotron SOLEIL
 *                         L'Orme des Merisiers Saint-Aubin
 *                         BP 48 91192 GIF-sur-YVETTE CEDEX
 *
 * Authors: Picca Frédéric-Emmanuel <picca@synchrotron-soleil.fr>
 */

#include <stdlib.h>
#include <string.h>
#include <float.h>
#include <math.h>
#include <stdio.h>

#include <glib.h>
#include <glib-object.h>
#include <gtk/gtk.h>
#include <gdk/gdk.h>

#include "hkl.h"
#include "hkl-gui.h"
#include "hkl-gui-diffractometer-private.h"
#include "hkl-gui-macros.h"

/****************/
/* HklGuiWindow */
/****************/

struct _HklGuiWindow {
	GtkApplication parent_instance;

	GListStore *liststore_samples;

	GtkAdjustment *adjustment_wavelength;
	GtkAlertDialog *alert_dialog_solutions;
	GBinding *adjustement_wavelength_binding;

	GtkMultiSelection *multi_selection_sample_reflections;
	GtkSingleSelection *single_selection_axes;
	GtkSingleSelection *single_selection_pseudo_axes;
	GtkSingleSelection *single_selection_samples;
	GtkSingleSelection *single_selection_solutions;

	GtkWidget *button_delete_sample;
	GtkWidget *button_delete_sample_reflection;
	GtkWidget *column_view_axes;
	GtkWidget *column_view_pseudo_axes;
	GtkWidget *column_view_sample_reflections;
	GtkWidget *column_view_samples;
	GtkWidget *column_view_solutions;
	GtkWidget *drop_down_samples;
	GtkWidget *flowbox_engines;
	GtkWidget *notebook1;
	GtkWidget *spinbutton_wavelength;
	GtkWidget *vbox_3d;
	GtkWidget *window1;

	HklGuiFactory *factory; /* not owned */
};

G_DEFINE_FINAL_TYPE (HklGuiWindow, hkl_gui_window, GTK_TYPE_APPLICATION);

/* static gboolean */
/* finalize_liststore_samples(GtkTreeModel *model, */
/*			   GtkTreePath *path, */
/*			   GtkTreeIter *iter, */
/*			   gpointer data) */
/* { */
/*	HklSample *sample = NULL; */

/*	gtk_tree_model_get(model, iter, */
/*			   SAMPLE_COL_SAMPLE, &sample, */
/*			   -1); */
/*	hkl_sample_free(sample); */
/*	return FALSE; */
/* } */

static void
finalize (GObject* object)
{
	G_OBJECT_CLASS (hkl_gui_window_parent_class)->finalize (object);
}


static void
raise_error(HklGuiWindow *self, GError *error)
{
	g_return_if_fail (error != NULL);

	/* show an error message */
	gtk_alert_dialog_set_message(self->alert_dialog_solutions,
				     error->message);
	gtk_alert_dialog_show(self->alert_dialog_solutions,
			      GTK_WINDOW(self->window1));
}

/* static void */
/* update_3d(HklGuiWindow *self) */
/* { */
/* #ifdef HKL3D */
/*	HklGuiWindowPrivate *priv = hkl_gui_window_get_instance_private(self); */

/*	if(priv->frame3d){ */
/*		hkl_gui_3d_is_colliding(priv->frame3d); */
/*		hkl_gui_3d_invalidate(priv->frame3d); */
/*	} */
/* #endif */
/* } */

static void
factory_notify_error_cb(HklGuiFactory *factory,
			GParamSpec* pspec,
			gpointer *user_data)
{
	HklGuiWindow *self = HKL_GUI_WINDOW(user_data);

	raise_error(self, hkl_gui_factory_get_error(factory));
}

static void
column_view_samples_selection_changed_cb (GtkSelectionModel* model,
					  guint position,
					  guint n_items,
					  gpointer user_data)
{
	GListStore *liststore;
	HklGuiWindow* self = HKL_GUI_WINDOW(user_data);
	HklGuiSample *sample;

	sample = HKL_GUI_SAMPLE (gtk_single_selection_get_selected_item (self->single_selection_samples));

	liststore = hkl_gui_sample_get_reflections (sample);

	gtk_multi_selection_set_model (self->multi_selection_sample_reflections,
				       G_LIST_MODEL (liststore));
}


/* select diffractometer */
static void
dropdown1_notify_selected_item_cb(GtkDropDown *dropdown,
				  GParamSpec* pspec,
				  gpointer *user_data)
{
	HklGuiWindow *self = HKL_GUI_WINDOW(user_data);
	HklGuiFactory *factory;

	factory = gtk_drop_down_get_selected_item(dropdown);
	if (NULL != factory) {
		guint i;
		guint n_items;
		GListStore *liststore;
		HklGuiSample *gsample;
		HklGuiFactory *old_factory = self->factory;

		self->factory = factory;

		/* setup spinbutton_wavelength */
		if(self->adjustement_wavelength_binding)
			g_binding_unbind(self->adjustement_wavelength_binding);
		gtk_adjustment_set_value(self->adjustment_wavelength,
					 hkl_gui_factory_get_wavelength(factory));
		gtk_widget_set_sensitive(self->spinbutton_wavelength, TRUE);
		self->adjustement_wavelength_binding = g_object_bind_property(factory, "wavelength",
									      self->adjustment_wavelength, "value",
									      G_BINDING_BIDIRECTIONAL);

		/* sample */
		g_object_bind_property(self->drop_down_samples, "selected-item", factory, "sample", G_BINDING_SYNC_CREATE);

		/* set column view axes model */
		liststore = hkl_gui_factory_get_liststore_axes (factory);
		gtk_single_selection_set_model (self->single_selection_axes,
						G_LIST_MODEL (liststore));

		/* set column view pseudo axes model */
		liststore = hkl_gui_factory_get_liststore_pseudo_axes(factory);
		gtk_single_selection_set_model(self->single_selection_pseudo_axes, G_LIST_MODEL(liststore));

		/* set column view solutions model and columns */
		hkl_gui_factory_setup_column_view_solutions(factory, GTK_COLUMN_VIEW(self->column_view_solutions));

		liststore = hkl_gui_factory_get_liststore_solutions(factory);
		gtk_single_selection_set_model(self->single_selection_solutions, G_LIST_MODEL(liststore));

		/* add the engines frames to the flowbox engines */
		gtk_flow_box_remove_all(GTK_FLOW_BOX(self->flowbox_engines));
		liststore = hkl_gui_factory_get_liststore_engines(factory);
		n_items = g_list_model_get_n_items(G_LIST_MODEL(liststore));
		for (i=0;i<n_items; ++i){
			HklGuiEngine *gengine = g_list_model_get_item(G_LIST_MODEL(liststore), i);

			gtk_flow_box_append(GTK_FLOW_BOX(self->flowbox_engines),
					    hkl_gui_engine_get_frame(gengine));
		}

		/* set column view sample reflections */
		hkl_gui_factory_setup_column_view_sample_reflections(factory,
								     self->single_selection_samples,
								     GTK_COLUMN_VIEW(self->column_view_sample_reflections));

		gsample = hkl_gui_factory_get_sample(factory);
		liststore = hkl_gui_sample_get_reflections(gsample);
		gtk_multi_selection_set_model (self->multi_selection_sample_reflections,
					       G_LIST_MODEL (liststore));

		/* setup the 3d part when relevant */
		hkl_gui_factory_setup_3d(old_factory, factory, GTK_BOX (self->vbox_3d));
	}
}

/* select sample */
static void
drop_down_samples_notify_selected_item_cb(GtkDropDown *dropdown,
					  GParamSpec* pspec,
					  gpointer *user_data)
{
	//HklGuiWindow *self = HKL_GUI_WINDOW(user_data);
	//HklGuiSample *gsample;
	//GtkWidget *frame;

	// gsample = gtk_drop_down_get_selected_item(dropdown);
}

static void
column_view_solutions_activate_cb (GtkColumnView *column_view,
				   guint position,
				   gpointer user_data)
{
	HklGuiWindow* self = HKL_GUI_WINDOW(user_data);
	HklGuiGeometry *ggeometry;

	ggeometry = HKL_GUI_GEOMETRY (gtk_single_selection_get_selected_item (self->single_selection_solutions));

	hkl_gui_factory_set_geometry(self->factory, ggeometry);
	/* if (gtk_tree_model_get_iter (GTK_TREE_MODEL(priv->liststore_solutions), &iter, path)) { */
	/*	gtk_tree_model_get (GTK_TREE_MODEL(priv->liststore_solutions), &iter, */
	/*			    SOLUTION_COL_HKL_GEOMETRY_LIST_ITEM, &solution, */
	/*			    -1); */

	/*	diffractometer_set_solution(priv->diffractometer, solution); */

	/*	update_axes (self); */
	/*	update_pseudo_axes (self); */
	/*	update_pseudo_axes_frames (self); */
	/*	update_3d(self); */

	/*	gtk_tree_path_free (path); */
	/* } */
}


/* /\* reflection flag *\/ */
/* void */
/* hkl_gui_window_cellrenderertoggle1_toggled_cb (GtkCellRendererToggle* renderer, const gchar* path, */
/*					       gpointer self) */
/* { */
/*	HklGuiWindowPrivate *priv = hkl_gui_window_get_instance_private(self); */

/*	g_return_if_fail (self != NULL); */
/*	g_return_if_fail (path != NULL); */

/*	if (priv->sample){ */
/*		gboolean flag; */
/*		HklSampleReflection* reflection = NULL; */
/*		GtkTreeIter iter = {0}; */

/*		gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL(priv->liststore_reflections), */
/*						     &iter, path); */
/*		gtk_tree_model_get (GTK_TREE_MODEL(priv->liststore_reflections), */
/*				    &iter, */
/*				    REFLECTION_COL_REFLECTION, &reflection, */
/*				    -1); */

/*		flag = gtk_cell_renderer_toggle_get_active(renderer); */
/*		hkl_sample_reflection_flag_set (reflection, flag); */
/*		gtk_list_store_set (priv->liststore_reflections, */
/*				    &iter, */
/*				    REFLECTION_COL_FLAG, flag, */
/*				    -1); */
/*	} */
/* } */

/* gboolean */
/* hkl_gui_window_treeview_reflections_key_press_event_cb (GtkWidget* _sender, GdkEvent* event, */
/*							gpointer self) */
/* { */
/*	return TRUE; */
/* } */

/* void */
/* hkl_gui_window_toolbutton_goto_reflection_clicked_cb (GtkButton* _sender, gpointer user_data) */
/* { */
/*	HklGuiWindow *self = HKL_GUI_WINDOW(user_data); */
/*	HklGuiWindowPrivate *priv = hkl_gui_window_get_instance_private(user_data); */

/*	g_return_if_fail (self != NULL); */

/*	if (priv->sample) { */
/*		GtkTreeSelection* selection = NULL; */
/*		guint nb_rows = 0U; */

/*		selection = gtk_tree_view_get_selection (priv->treeview_reflections); */
/*		nb_rows = gtk_tree_selection_count_selected_rows (selection); */

/*		if (nb_rows == 1) { */
/*			HklSampleReflection *reflection; */
/*			GtkTreeIter iter = {0}; */
/*			GtkTreeModel* model = NULL; */
/*			GtkTreePath *treepath; */
/*			GList* list; */

/*			model = GTK_TREE_MODEL(priv->liststore_reflections); */

/*			list = gtk_tree_selection_get_selected_rows (selection, */
/*								     &model); */

/*			treepath = g_list_nth_data(list, 0); */

/*			gtk_tree_model_get_iter (GTK_TREE_MODEL(priv->liststore_reflections), */
/*						 &iter, treepath); */

/*			gtk_tree_model_get (GTK_TREE_MODEL(priv->liststore_reflections), */
/*					    &iter, */
/*					    REFLECTION_COL_REFLECTION, &reflection, */
/*					    -1); */

/*			hkl_geometry_set (priv->diffractometer->geometry, */
/*					  hkl_sample_reflection_geometry_get(reflection)); */

/*			update_source (self); */
/*			update_axes (self); */
/*			update_pseudo_axes (self); */
/*			update_3d(self); */

/*			g_list_free_full (list, (GDestroyNotify) gtk_tree_path_free); */
/*		} else */
/*			if (nb_rows > 1) */
/*				gtk_statusbar_push (priv->statusbar, 0, */
/*						    "Please select only one reflection."); */
/*			else */
/*				gtk_statusbar_push (priv->statusbar, 0, */
/*						    "Please select at least one reflection."); */
/*	} */
/* } */


/* #define set_reciprocal_lattice(lattice, parameter) do{			\ */
/*		const HklParameter *p;					\ */
/*		gdouble value;						\ */
/*		p = hkl_lattice_## parameter ##_get((lattice));		\ */
/*		value = hkl_parameter_value_get(p, HKL_UNIT_USER);	\ */
/*		gtk_spin_button_set_value(priv->spinbutton_## parameter ##_star, value); \ */
/*	}while(0) */

/* static void */
/* update_reciprocal_lattice (HklGuiWindow* self) */
/* { */
/*	HklGuiWindowPrivate *priv = hkl_gui_window_get_instance_private(self); */

/*	g_return_if_fail (self != NULL); */

/*	if (priv->sample != NULL) { */
/*		hkl_lattice_reciprocal (hkl_sample_lattice_get(priv->sample), */
/*					priv->reciprocal); */

/*		set_reciprocal_lattice(priv->reciprocal, a); */
/*		set_reciprocal_lattice(priv->reciprocal, b); */
/*		set_reciprocal_lattice(priv->reciprocal, c); */
/*		set_reciprocal_lattice(priv->reciprocal, alpha); */
/*		set_reciprocal_lattice(priv->reciprocal, beta); */
/*		set_reciprocal_lattice(priv->reciprocal, gamma); */
/*	} */
/* } */

/* #define set_UB(i, j) do{						\ */
/*		gdouble	value = hkl_matrix_get(UB, i - 1, j - 1);	\ */
/*		const char *format = "<tt> %+.4f </tt>";		\ */
/*		gchar *markup;						\ */
/*		markup = g_markup_printf_escaped (format, value);	\ */
/*		gtk_label_set_markup(GTK_LABEL (priv->label_UB ## i ## j), \ */
/*				     markup);				\ */
/*		g_free(markup);						\ */
/*	}while(0) */

/* static void */
/* update_UB (HklGuiWindow* self) */
/* { */
/*	HklGuiWindowPrivate *priv = hkl_gui_window_get_instance_private(self); */

/*	g_return_if_fail (self != NULL); */

/*	if (priv->sample != NULL) { */
/*		const HklMatrix *UB = hkl_sample_UB_get (priv->sample); */
/*		gchar *text = g_new0 (gchar, G_ASCII_DTOSTR_BUF_SIZE); */

/*		set_UB(1, 1); */
/*		set_UB(1, 2); */
/*		set_UB(1, 3); */
/*		set_UB(2, 1); */
/*		set_UB(2, 2); */
/*		set_UB(2, 3); */
/*		set_UB(3, 1); */
/*		set_UB(3, 2); */
/*		set_UB(3, 3); */

/*		g_free(text); */
/*	} */
/* } */

/* void */
/* hkl_gui_window_treeview_crystals_cursor_changed_cb (GtkTreeView* _sender, gpointer user_data) */
/* { */
/*	GtkTreePath* path = NULL; */
/*	GtkTreeViewColumn* column = NULL; */
/*	GtkTreeIter iter = {0}; */

/*	HklGuiWindow *self = HKL_GUI_WINDOW(user_data); */
/*	HklGuiWindowPrivate *priv = hkl_gui_window_get_instance_private(user_data); */
/*	HklSample *sample; */

/*	g_return_if_fail (user_data != NULL); */

/*	gtk_tree_view_get_cursor (priv->treeview_crystals, &path, &column); */
/*	if(path){ */
/*		if (gtk_tree_model_get_iter (GTK_TREE_MODEL(priv->liststore_crystals), */
/*					     &iter, path) == TRUE){ */
/*			gtk_tree_model_get (GTK_TREE_MODEL(priv->liststore_crystals), */
/*					    &iter, */
/*					    SAMPLE_COL_SAMPLE, &sample, */
/*					    -1); */

/*			if(sample && sample != priv->sample){ */
/*				priv->sample = sample; */

/*				update_reflections(self); */
/*				update_lattice(self); */
/*				update_reciprocal_lattice (self); */
/*				update_ux_uy_uz (self); */
/*				update_UB (self); */

/*				if(priv->diffractometer){ */
/*					diffractometer_set_sample(priv->diffractometer, */
/*								  priv->sample); */

/*					update_pseudo_axes (self); */
/*					update_pseudo_axes_frames (self); */
/*					update_solutions(self); */
/*				} */
/*			} */
/*		} */
/*		gtk_tree_path_free (path); */
/*	} */
/* } */



/* void */
/* hkl_gui_window_toolbutton_setUB_clicked_cb(GtkButton* _sender, gpointer user_data) */
/* { */
/*	HklGuiWindow *self = HKL_GUI_WINDOW(user_data); */
/*	HklGuiWindowPrivate *priv = hkl_gui_window_get_instance_private(user_data); */

/*	HklMatrix *UB; */
/*	GError *error = NULL; */

/*	UB = hkl_matrix_new_full(gtk_spin_button_get_value(priv->spinbutton_U11), */
/*				 gtk_spin_button_get_value(priv->spinbutton_U12), */
/*				 gtk_spin_button_get_value(priv->spinbutton_U13), */
/*				 gtk_spin_button_get_value(priv->spinbutton_U21), */
/*				 gtk_spin_button_get_value(priv->spinbutton_U22), */
/*				 gtk_spin_button_get_value(priv->spinbutton_U23), */
/*				 gtk_spin_button_get_value(priv->spinbutton_U31), */
/*				 gtk_spin_button_get_value(priv->spinbutton_U32), */
/*				 gtk_spin_button_get_value(priv->spinbutton_U33)); */

/*	if(!hkl_sample_UB_set (priv->sample, UB, &error)) */
/*		raise_error(self, &error); */
/*	else{ */
/*		if(priv->diffractometer){ */
/*			diffractometer_set_sample(priv->diffractometer, */
/*						  priv->sample); */

/*			update_lattice (self); */
/*			update_crystal_model (self); */
/*			update_reciprocal_lattice (self); */
/*			update_UB (self); */
/*			update_ux_uy_uz (self); */
/*			update_pseudo_axes (self); */
/*			update_pseudo_axes_frames (self); */
/*		} */
/*	} */

/*	hkl_matrix_free(UB); */
/* } */


/* void */
/* hkl_gui_window_toolbutton_affiner_clicked_cb (GtkButton* _sender, gpointer user_data) */
/* { */
/*	HklGuiWindow *self = HKL_GUI_WINDOW(user_data); */
/*	HklGuiWindowPrivate *priv = hkl_gui_window_get_instance_private(user_data); */
/*	GError *error = NULL; */

/*	if(!hkl_sample_affine (priv->sample, &error)){ */
/*		raise_error(self, &error); */
/*	}else{ */
/*		if(priv->diffractometer) */
/*			diffractometer_set_sample(priv->diffractometer, */
/*						  priv->sample); */

/*		update_lattice (self); */
/*		update_crystal_model (self); */
/*		update_reciprocal_lattice (self); */
/*		update_UB (self); */
/*		update_ux_uy_uz (self); */
/*		update_pseudo_axes (self); */
/*		update_pseudo_axes_frames (self); */
/*	} */
/* } */

/* /\* */


static void
add_sample_activated (GSimpleAction *action,
		      GVariant *parameter,
		      gpointer user_data)
{
	HklGuiWindow *self = HKL_GUI_WINDOW(user_data);
	gint n_items;

	g_list_store_append(self->liststore_samples,
			    hkl_gui_sample_new("<edit name>"));
	n_items = g_list_model_get_n_items (G_LIST_MODEL (self->single_selection_samples));
	gtk_single_selection_set_selected (self->single_selection_samples, n_items - 1);

	if(n_items > 1)
		gtk_widget_set_sensitive(self->button_delete_sample, true);
	/* TODO go to the sample name in edit mode */
}

static void
add_sample_reflection_activated (GSimpleAction *action,
				 GVariant *parameter,
				 gpointer user_data)
{
	HklGuiWindow *self = HKL_GUI_WINDOW(user_data);
	HklGuiSample *sample;

	sample = HKL_GUI_SAMPLE (gtk_single_selection_get_selected_item (self->single_selection_samples));

	g_return_if_fail (NULL != sample);

	hkl_gui_factory_add_reflection(self->factory, sample);
}

static void
copy_sample_activated (GSimpleAction *action,
		       GVariant *parameter,
		       gpointer user_data)
{
	HklGuiWindow *self = HKL_GUI_WINDOW(user_data);
	HklGuiSample *gsample;
	gint n_items;

	gsample = gtk_single_selection_get_selected_item (self->single_selection_samples);

	g_list_store_append(self->liststore_samples,
			    hkl_gui_sample_new_copy(gsample));

	n_items = g_list_model_get_n_items (G_LIST_MODEL (self->single_selection_samples));
	if(n_items > 1)
		gtk_widget_set_sensitive(self->button_delete_sample, true);

	/* TODO go to the edit name */
}

static void
delete_sample_activated (GSimpleAction *action,
			 GVariant *parameter,
			 gpointer user_data)
{
	HklGuiWindow *self = HKL_GUI_WINDOW(user_data);
	gint n_items;
	gint selected;

	selected = gtk_single_selection_get_selected(self->single_selection_samples);

	g_list_store_remove(self->liststore_samples, selected);
	n_items = g_list_model_get_n_items (G_LIST_MODEL (self->single_selection_samples));
	if (1 == n_items)
		gtk_widget_set_sensitive(self->button_delete_sample, false);
}

static void
delete_sample_reflection_activated (GSimpleAction *action,
				    GVariant *parameter,
				    gpointer user_data)
{
	HklGuiWindow *self = HKL_GUI_WINDOW(user_data);
	HklGuiSample *sample;
	GtkBitset *selected;

	sample = HKL_GUI_SAMPLE (gtk_single_selection_get_selected_item (self->single_selection_samples));

	g_return_if_fail (NULL != sample);

	selected = gtk_selection_model_get_selection (GTK_SELECTION_MODEL (self->multi_selection_sample_reflections));

	if (gtk_bitset_is_empty(selected) == false)
		hkl_gui_factory_del_reflection(self->factory, sample, selected);

	gtk_bitset_unref(selected);
}

static void
compute_ub_activated (GSimpleAction *action,
		      GVariant *parameter,
		      gpointer user_data)
{
	HklGuiWindow *self = HKL_GUI_WINDOW(user_data);
	HklGuiSample *sample;

	sample = gtk_single_selection_get_selected_item (self->single_selection_samples);

	g_return_if_fail (NULL != sample);

	hkl_gui_factory_compute_ub(self->factory, sample);
}

static GActionEntry win_entries[] = {
	{ "add-sample", add_sample_activated, NULL, NULL, NULL },
	{ "add-sample-reflection", add_sample_reflection_activated, NULL, NULL, NULL },
	{ "compute-ub", compute_ub_activated, NULL, NULL, NULL },
	{ "copy-sample", copy_sample_activated, NULL, NULL, NULL },
	{ "delete-sample", delete_sample_activated, NULL, NULL, NULL },
	{ "delete-sample-reflection", delete_sample_reflection_activated, NULL, NULL, NULL },
};

static void
new_window (GApplication *app,
            GFile        *file)
{
	size_t i;
	size_t n;

	GListStore *liststore1;

	GtkListItemFactory *item_factory_drop_down_factories;
	GtkListItemFactory *item_factory_drop_down_samples;

	GtkWidget *button_add_sample;
	GtkWidget *button_add_sample_reflection;
	GtkWidget *button_compute_ub;
	GtkWidget *button_copy_sample;
	GtkWidget *dropdown1;
	GtkWidget *frame_diffractometer;
	GtkWidget *frame_wavelength;
	GtkWidget *frame_axes;
	GtkWidget *frame_pseudo_axes;
	GtkWidget *frame_sample;
	GtkWidget *frame_sample_reflections;
	GtkWidget *frame_samples;
	GtkWidget *frame_solutions;
	GtkWidget *hbox1;
	GtkWidget *hbox2;
	GtkWidget *hbox3;
	GtkWidget *label;
	GtkWidget *scrolledwindow1;
	GtkWidget *scrolledwindow2;
	GtkWidget *scrolledwindow3;
	GtkWidget *vbox1;
	GtkWidget *vbox2;
	GtkWidget *vbox3;
	GtkWidget *vbox4;
	GtkWidget *vbox5;

	HklFactory **factories;

	HklGuiWindow *self = HKL_GUI_WINDOW(app);

        /**********/
	/* Models */
	/**********/

	/* liststore1 factories */
	liststore1 = g_list_store_new (HKL_GUI_TYPE_FACTORY);
	factories = hkl_factory_get_all(&n);
	for(i=0; i<n; ++i){
		HklGuiFactory *factory = hkl_gui_factory_new(factories[i]);
		g_signal_connect (factory, "notify::error",
				  G_CALLBACK (factory_notify_error_cb), self);
		g_list_store_append (liststore1, factory);
	}

	/* liststore samples */
	self->liststore_samples = g_list_store_new (HKL_GUI_TYPE_SAMPLE);
	g_list_store_append(self->liststore_samples, hkl_gui_sample_new("default"));

	/*********************/
	/* ListItemFactories */
	/*********************/

	/* drop down factories */

	item_factory_drop_down_factories = gtk_signal_list_item_factory_new ();
	g_signal_connect (item_factory_drop_down_factories, "setup", G_CALLBACK (hkl_gui_setup_item_factory_label_cb), NULL);
	g_signal_connect (item_factory_drop_down_factories, "bind", G_CALLBACK (hkl_gui_bind_item_factory_label_property_cb), "name");

	/* drop down samples */

	item_factory_drop_down_samples = gtk_signal_list_item_factory_new ();
	g_signal_connect (item_factory_drop_down_samples,
			  "setup", G_CALLBACK (hkl_gui_setup_item_factory_label_cb), NULL);
	g_signal_connect (item_factory_drop_down_samples,
			  "bind", G_CALLBACK (hkl_gui_bind_item_factory_label_property_cb), "name");

	/*********************/
	/* Selections	     */
	/*********************/

	self->multi_selection_sample_reflections = gtk_multi_selection_new(NULL);
	self->single_selection_axes = gtk_single_selection_new(NULL);
	self->single_selection_pseudo_axes = gtk_single_selection_new(NULL);
	self->single_selection_samples = gtk_single_selection_new (G_LIST_MODEL (self->liststore_samples));
	self->single_selection_solutions = gtk_single_selection_new(NULL);

	/***********/
	/* widgets */
	/***********/

	self->alert_dialog_solutions = gtk_alert_dialog_new("Solutions");
	self->button_delete_sample = gtk_button_new();
	self->button_delete_sample_reflection = gtk_button_new();
	self->column_view_axes = gtk_column_view_new (GTK_SELECTION_MODEL (self->single_selection_axes));
	self->column_view_pseudo_axes = gtk_column_view_new (GTK_SELECTION_MODEL (self->single_selection_pseudo_axes));
	self->column_view_sample_reflections = gtk_column_view_new (GTK_SELECTION_MODEL (self->multi_selection_sample_reflections));
	self->column_view_samples = gtk_column_view_new (GTK_SELECTION_MODEL (self->single_selection_samples));
	self->column_view_solutions = gtk_column_view_new (GTK_SELECTION_MODEL (self->single_selection_solutions));
	self->drop_down_samples = gtk_drop_down_new(G_LIST_MODEL(self->liststore_samples), NULL);
	self->flowbox_engines = gtk_flow_box_new();
	self->notebook1 = gtk_notebook_new();
	self->spinbutton_wavelength = gtk_spin_button_new(self->adjustment_wavelength, 0.0001, 4);
	self->vbox_3d = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
	self->window1 = gtk_application_window_new (GTK_APPLICATION (app));

	button_add_sample = gtk_button_new();
	button_add_sample_reflection = gtk_button_new();
	button_compute_ub = gtk_button_new_with_label("Compute UB");
	button_copy_sample = gtk_button_new();
	dropdown1 = gtk_drop_down_new(G_LIST_MODEL(liststore1), NULL);
	frame_diffractometer = gtk_frame_new("Diffractometer");
	frame_wavelength = gtk_frame_new("Wavelength");
	frame_axes = gtk_frame_new("Axes");
	frame_pseudo_axes = gtk_frame_new("Pseudo Axes");
	frame_sample = gtk_frame_new("Sample");
	frame_sample_reflections = gtk_frame_new("Reflections");
	frame_samples = gtk_frame_new("Samples");
	frame_solutions = gtk_frame_new("Solutions");
	hbox1 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
	hbox2 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
	hbox3 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
	scrolledwindow1 = gtk_scrolled_window_new();
	scrolledwindow2 = gtk_scrolled_window_new();
	scrolledwindow3 = gtk_scrolled_window_new();
	vbox1 = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
	vbox2 = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
	vbox3 = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
	vbox4 = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
	vbox5 = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);

	/* button_add_sample */
	gtk_widget_set_tooltip_text(button_add_sample, "Add a new sample");
	gtk_button_set_icon_name (GTK_BUTTON (button_add_sample), "list-add-symbolic");
	gtk_actionable_set_action_name (GTK_ACTIONABLE (button_add_sample), "win.add-sample");

	/* button_add_sample_reflection */
	gtk_widget_set_tooltip_text(button_add_sample_reflection, "Add a new reflection");
	gtk_button_set_icon_name (GTK_BUTTON (button_add_sample_reflection), "list-add-symbolic");
	gtk_actionable_set_action_name (GTK_ACTIONABLE (button_add_sample_reflection), "win.add-sample-reflection");

	/* button_compute_ub */
	gtk_widget_set_tooltip_text(button_compute_ub, "Compute the UB matrix with or0 and or1 reflections");
	gtk_actionable_set_action_name (GTK_ACTIONABLE (button_compute_ub), "win.compute-ub");

	/* button_copy_sample */
	gtk_widget_set_tooltip_text(button_copy_sample, "Copy the selected sample");
	gtk_button_set_icon_name (GTK_BUTTON (button_copy_sample), "edit-copy-symbolic");
	gtk_actionable_set_action_name (GTK_ACTIONABLE (button_copy_sample), "win.copy-sample");

	/* button_delete_sample */
	gtk_widget_set_tooltip_text(self->button_delete_sample, "Delete the selected sample");
	gtk_button_set_icon_name (GTK_BUTTON (self->button_delete_sample), "list-remove-symbolic");
	gtk_actionable_set_action_name (GTK_ACTIONABLE (self->button_delete_sample), "win.delete-sample");

	/* button_delete_sample_reflection */
	gtk_widget_set_tooltip_text(self->button_delete_sample_reflection, "Delete the selected reflection");
	gtk_button_set_icon_name (GTK_BUTTON (self->button_delete_sample_reflection), "list-remove-symbolic");
	gtk_actionable_set_action_name (GTK_ACTIONABLE (self->button_delete_sample_reflection), "win.delete-sample-reflection");

	/* column view axes */
	add_column(self->column_view_axes, "name", label_property, "name");
	add_column(self->column_view_axes, "value", spin_button_parameter_value);
	add_column(self->column_view_axes, "min", spin_button_parameter_min);
	add_column(self->column_view_axes, "max", spin_button_parameter_max);

	/* column view pseudo axes */
	add_column(self->column_view_pseudo_axes, "name", label_property, "name");
	add_column(self->column_view_pseudo_axes, "value", label_property, "value");

	/* column view sample reflections */
	gtk_widget_set_vexpand(self->column_view_sample_reflections, true);

	/* column view samples */
	gtk_widget_set_vexpand(self->column_view_samples, true);

	add_column(self->column_view_samples, "name", entry_property, "name");
	add_column(self->column_view_samples, "a", entry_numeric_property, "a");
	add_column(self->column_view_samples, "b", entry_numeric_property, "b");
	add_column(self->column_view_samples, "c", entry_numeric_property, "c");
	add_column(self->column_view_samples, "alpha", entry_numeric_property, "alpha");
	add_column(self->column_view_samples, "beta", entry_numeric_property, "beta");
	add_column(self->column_view_samples, "gamma", entry_numeric_property, "gamma");
	add_column(self->column_view_samples, "ux", entry_numeric_property, "ux");
	add_column(self->column_view_samples, "uy", entry_numeric_property, "uy");
	add_column(self->column_view_samples, "uz", entry_numeric_property, "uz");

	g_signal_connect (self->single_selection_samples, "selection-changed",
			  G_CALLBACK (column_view_samples_selection_changed_cb), self);

	/* column view solutions */
	g_signal_connect (self->column_view_solutions, "activate", G_CALLBACK (column_view_solutions_activate_cb), self);

	/* dropdown1 */
	gtk_widget_set_tooltip_text(dropdown1, "Select a diffractometer");
	gtk_drop_down_set_show_arrow(GTK_DROP_DOWN(dropdown1), true);
	gtk_drop_down_set_factory(GTK_DROP_DOWN(dropdown1), item_factory_drop_down_factories);
	g_signal_connect (dropdown1, "notify::selected-item", G_CALLBACK (dropdown1_notify_selected_item_cb), self);

	/* drop_down_samples */
	gtk_widget_set_tooltip_text(self->drop_down_samples, "Select a sample");
	gtk_drop_down_set_show_arrow(GTK_DROP_DOWN(self->drop_down_samples), true);
	gtk_drop_down_set_factory(GTK_DROP_DOWN(self->drop_down_samples), item_factory_drop_down_samples);
	g_signal_connect (self->drop_down_samples, "notify::selected-item",
			  G_CALLBACK (drop_down_samples_notify_selected_item_cb), self);

	/* flowbox engines */
	gtk_flow_box_set_homogeneous(GTK_FLOW_BOX(self->flowbox_engines), FALSE);
	gtk_flow_box_set_selection_mode(GTK_FLOW_BOX(self->flowbox_engines),
					GTK_SELECTION_NONE);

	/* frame diffractometer */
	gtk_frame_set_child(GTK_FRAME(frame_diffractometer), dropdown1);

	/* frame wavelength */
	gtk_frame_set_child(GTK_FRAME(frame_wavelength), self->spinbutton_wavelength);

	/* frame axes */
	gtk_frame_set_child(GTK_FRAME(frame_axes), self->column_view_axes);

        /* frame pseudo axes */
	// gtk_frame_set_child(GTK_FRAME(frame_pseudo_axes), scrolledwindow1);
	gtk_frame_set_child(GTK_FRAME(frame_pseudo_axes), self->column_view_pseudo_axes);

	/* frame sample */
	gtk_frame_set_child(GTK_FRAME(frame_sample), self->drop_down_samples);

	/* frame sample reflections */
	gtk_frame_set_child(GTK_FRAME(frame_sample_reflections), vbox5);

	/* frame samples */
	gtk_frame_set_child(GTK_FRAME(frame_samples), vbox4);

	/* frame solutions*/
	gtk_frame_set_child(GTK_FRAME(frame_solutions), self->column_view_solutions);

	/* hbox1 */
	gtk_box_append(GTK_BOX(hbox1), vbox2);
	gtk_box_append(GTK_BOX(hbox1), self->notebook1);

	/* hbox2 */
	gtk_box_append(GTK_BOX(hbox2), button_add_sample);
	gtk_box_append(GTK_BOX(hbox2), button_copy_sample);
	gtk_box_append(GTK_BOX(hbox2), self->button_delete_sample);

	/* hbox3 */
	gtk_box_append(GTK_BOX(hbox3), button_add_sample_reflection);
	gtk_box_append(GTK_BOX(hbox3), self->button_delete_sample_reflection);
	gtk_box_append(GTK_BOX(hbox3), button_compute_ub);

	/* notebook1 */
	gtk_widget_set_hexpand(self->notebook1, true);
	label = gtk_label_new("Pseudo Axes");
	gtk_notebook_append_page (GTK_NOTEBOOK (self->notebook1),
				  scrolledwindow1,
				  label);
	label =  gtk_label_new("Samples Configuration");
	gtk_notebook_append_page (GTK_NOTEBOOK (self->notebook1),
				  vbox3,
				  label);
#if HKL3D
	label =  gtk_label_new("Diffractometer 3D");
	gtk_notebook_append_page (GTK_NOTEBOOK (self->notebook1),
				  self->vbox_3d,
				  label);
#endif
	/* scrolledwindow1 */
	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwindow1),
				       GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
	gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scrolledwindow1), self->flowbox_engines);

	/* scrolledwindow2 */
	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwindow2),
				       GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
	gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scrolledwindow2), self->column_view_samples);

	/* scrolledwindow3 */
	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwindow3),
				       GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
	gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scrolledwindow3), self->column_view_sample_reflections);

	/* spinbutton_wavelength */
	gtk_widget_set_sensitive(self->spinbutton_wavelength, FALSE);

	/* vbox1 */
	gtk_box_append(GTK_BOX(vbox1), hbox1);
	gtk_box_set_homogeneous(GTK_BOX (vbox1), true);

	/* vbox2 */
	gtk_box_append(GTK_BOX(vbox2), frame_diffractometer);
	gtk_box_append(GTK_BOX(vbox2), frame_wavelength);
	gtk_box_append(GTK_BOX(vbox2), frame_sample);
	gtk_box_append(GTK_BOX(vbox2), frame_axes);
	gtk_box_append(GTK_BOX(vbox2), frame_solutions);

	/* vbox3 */
	gtk_box_append(GTK_BOX(vbox3), frame_samples);
	gtk_box_append(GTK_BOX(vbox3), frame_sample_reflections);

	/* vbox4 */
	gtk_box_append(GTK_BOX(vbox4), hbox2);
	gtk_box_append(GTK_BOX(vbox4), scrolledwindow2);

	/* vbox5 */
	gtk_box_append(GTK_BOX(vbox5), hbox3);
	gtk_box_append(GTK_BOX(vbox5), scrolledwindow3);

	/* gtk_paned_set_start_child (GTK_PANED (hpaned1), vbox2); */
	/* gtk_paned_set_shrink_start_child (GTK_PANED (hpaned1), false); */

	/* gtk_paned_set_end_child (GTK_PANED (hpaned1), notebook1); */
	/* gtk_paned_set_shrink_end_child (GTK_PANED (hpaned1), false); */

	/*  window1 */
	gtk_window_set_default_size (GTK_WINDOW(self->window1), 1024, 768);

	g_action_map_add_action_entries (G_ACTION_MAP (self->window1), win_entries, G_N_ELEMENTS (win_entries), self);
	gtk_window_set_title (GTK_WINDOW (self->window1), "hkl library GUI");
	gtk_application_window_set_show_menubar (GTK_APPLICATION_WINDOW (self->window1), TRUE);
	gtk_window_set_child (GTK_WINDOW (self->window1), vbox1);

	gtk_window_present (GTK_WINDOW (self->window1));
}

static void hkl_gui_window_startup (GApplication *application)
{
	G_APPLICATION_CLASS (hkl_gui_window_parent_class)->startup (application);

	/* priv->diffractometer = NULL; */
	/* priv->sample = hkl_sample_new("default"); */

	/* darray_init(priv->pseudo_frames); */

	/* priv->reciprocal = hkl_lattice_new_default (); */

	/* hkl_gui_window_get_widgets_and_objects_from_ui (ghkl); */

	/* set_up_diffractometer_model (ghkl); */

	/* set_up_tree_view_crystals (ghkl); */

	/* set_up_tree_view_reflections(ghkl); */
}

static void
hkl_gui_window_shutdown (GApplication *application)
{
	G_APPLICATION_CLASS (hkl_gui_window_parent_class)->shutdown (application);
}


static void hkl_gui_window_activate (GApplication *application)
{
	G_APPLICATION_CLASS (hkl_gui_window_parent_class)->activate (application);
	new_window (application, NULL);
}

static void hkl_gui_window_open (GApplication  *application,
				 GFile        **files,
				 int            n_files,
				 const char    *hint)
{
}

static void hkl_gui_window_init (HklGuiWindow * self)
{
	self->adjustment_wavelength = gtk_adjustment_new (0.0, 0.0, G_MAXDOUBLE,
							  0.0001, 0.01, 0.0);
	self->adjustement_wavelength_binding = NULL;
}

static void hkl_gui_window_class_init (HklGuiWindowClass *class)
{
	GApplicationClass *application_class = G_APPLICATION_CLASS (class);
	GObjectClass *object_class = G_OBJECT_CLASS (class);

	application_class->startup = hkl_gui_window_startup;
	application_class->shutdown = hkl_gui_window_shutdown;
	application_class->activate = hkl_gui_window_activate;
	application_class->open = hkl_gui_window_open;

	/* virtual method */
	object_class->finalize = finalize;
}

static HklGuiWindow* hkl_gui_window_new (void)
{
	HklGuiWindow *ghkl;

	g_set_application_name ("Ghkl");
	ghkl = g_object_new (HKL_GUI_TYPE_WINDOW,
			     "application-id", "fr.synchrotron-soleil.ghkl",
			     "flags", G_APPLICATION_HANDLES_OPEN,
			     "inactivity-timeout", 30000,
			     "register-session", TRUE,
			     NULL);
	return ghkl;
}

int main (int argc, char ** argv)
{
	HklGuiWindow *ghkl;
	int status;
	const char *accels[] = { "F11", NULL };

	ghkl = hkl_gui_window_new ();
	gtk_application_set_accels_for_action (GTK_APPLICATION (ghkl),
					       "win.fullscreen", accels);
	status = g_application_run (G_APPLICATION (ghkl), argc, argv);
	g_object_unref (ghkl);

	return status;
}
