/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
/*
    editor.c
    Copyright (C) 2003 Biswapesh Chattopadhyay

    This program 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 2 of the License, or
    (at your option) any later version.

    This program 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 this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/

/*
 * Tool editor dialog
 * This is used to set all tool informations.
 * 
 *---------------------------------------------------------------------------*/

#include <config.h>
#include <errno.h>
#include <sys/stat.h>
#include "editor.h"

#include "dialog.h"
#include "tool.h"
#include "variable.h"

#include <libanjuta/anjuta-utils.h>
#include <libanjuta/interfaces/ianjuta-document-manager.h>
#include <libanjuta/interfaces/ianjuta-editor.h>
#include <libanjuta/interfaces/ianjuta-file-loader.h>
#include <glib.h>
#include <gdk/gdk.h>
#include <gtk/gtk.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

/*---------------------------------------------------------------------------*/

/* Variable dialog */

typedef enum {
	ATP_VARIABLE_DEFAULT = 0,
	ATP_VARIABLE_REPLACE = 1 << 1
} ATPVariableType;

typedef struct _ATPVariableDialog
{
	GtkDialog* dialog;
	GtkTreeView* view;
	ATPToolEditor* editor;
	GtkEditable* entry;
	ATPVariableType type;
} ATPVariableDialog;	

enum {
	ATP_VARIABLE_NAME_COLUMN,
	ATP_VARIABLE_MEAN_COLUMN,
	ATP_VARIABLE_VALUE_COLUMN,
	ATP_N_VARIABLE_COLUMNS,
};

/* Structure containing the required properties of the tool editor GUI */
struct _ATPToolEditor
{
	GtkWidget *dialog;
	GtkEditable *name_en;
	GtkEditable *command_en;
	GtkEditable *param_en;
	ATPVariableDialog param_var;
	GtkEditable *dir_en;
	ATPVariableDialog dir_var;
	GtkToggleButton *enabled_tb;
	GtkToggleButton *terminal_tb;
	GtkToggleButton *autosave_tb;
	GtkToggleButton *script_tb;
	GtkComboBox *output_com;
	GtkComboBox *error_com;
	GtkComboBox *input_com;
	GtkEditable *input_en;
	GtkButton *input_var_bt;
	ATPVariableDialog input_file_var;
	ATPVariableDialog input_string_var;
	GtkToggleButton *shortcut_bt;
	GtkButton *icon_en;
	gchar* shortcut;
	ATPUserTool *tool;
	ATPToolDialog* parent;
	ATPToolEditorList* owner;
	ATPToolEditor* next;
};

/*---------------------------------------------------------------------------*/

/* Widget and signal name found in glade file
 *---------------------------------------------------------------------------*/

#define TOOL_EDITOR "editor_dialog"
#define TOOL_NAME "name_entry"
#define TOOL_COMMAND "command_entry"
#define TOOL_PARAM "parameter_entry"
#define TOOL_WORKING_DIR "directory_entry"
#define TOOL_ENABLED "enable_checkbox"
#define TOOL_AUTOSAVE "save_checkbox"
#define TOOL_TERMINAL "terminal_checkbox"
#define TOOL_SCRIPT "script_checkbox"
#define TOOL_OUTPUT "output_combo"
#define TOOL_ERROR "error_combo"
#define TOOL_INPUT "input_combo"
#define TOOL_INPUT_VALUE "input_entry"
#define TOOL_INPUT_VARIABLE "input_button"
#define TOOL_SHORTCUT "shortcut_bt"
#define TOOL_ICON "icon_entry"
#define TOOL_BROWSE_WORKING_DIR "browse_button_directory_entry"
#define TOOL_BROWSE_COMMAND "browse_button_command_entry"
#define TOOL_VARIABLE "variable_dialog"
#define VARIABLE_TREEVIEW "variable_treeview"

void atp_on_variable_activate_row (GtkTreeView *treeview, GtkTreePath *path, GtkTreeViewColumn *column, gpointer user_data);
void atp_on_variable_dialog_response (GtkDialog *dialog, gint response, gpointer user_data);
void atp_on_editor_icon_entry_clicked (GtkButton *button, gpointer user_data);
void atp_on_editor_terminal_toggle (GtkToggleButton *tb, gpointer user_data);
void atp_on_editor_script_toggle (GtkToggleButton *tb, gpointer user_data);
void atp_on_editor_input_changed (GtkComboBox *combo, gpointer user_data);
void atp_on_editor_dialog_response (GtkDialog *dialog, gint response, gpointer user_data);
void atp_on_editor_param_variable_show (GtkButton *button, gpointer user_data);
void atp_on_editor_dir_variable_show (GtkButton *button, gpointer user_data);
void atp_on_editor_input_variable_show (GtkButton *button, gpointer user_data);
void atp_on_editor_shortcut_toggle (GtkToggleButton *tb, gpointer user_data);
void atp_on_editor_browse_button_clicked (GtkButton *button, GtkEntry *entry);
void atp_on_editor_browse_button_dir_clicked (GtkButton *button, GtkEntry *entry);


/* Add helper function
 *---------------------------------------------------------------------------*/

static gboolean
make_directory (gchar* path)
{
	gchar c;
	gchar* ptr;

	for (ptr = path; *ptr;)
	{
		/* Get next directory */
		for (c = '\0'; *ptr; ++ptr)
		{
			if (*ptr == G_DIR_SEPARATOR)
			{
				/* Strip leading directory separator */
				do
				{
					++ptr;
				} while (*ptr == G_DIR_SEPARATOR);
				c = *ptr;
				*ptr = '\0';
				break;
			}
		}

		/* Create it */
		if (mkdir (path, 0755) < 0)
		{
			/* Error creating directory */
			*ptr = c;
			if (errno != EEXIST)
			{
		 		/* An already existing directory is not an error */		
				return FALSE;
			}
		}
		else
		{
			/* New directory created */
			*ptr = c;
		}
	}

	return TRUE;
}

static void
set_combo_box_enum_model (GtkComboBox* combo_box, const ATPEnumType* list)
{
	GtkTreeModel *model;
	GtkCellRenderer * renderer;

	model = GTK_TREE_MODEL (gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_INT));

	for (; list->id != -1;++list)
	{
		GtkTreeIter iter;

		gtk_list_store_append (GTK_LIST_STORE(model), &iter);
		gtk_list_store_set (GTK_LIST_STORE(model), &iter, 0, _(list->name), 1, list->id, -1);
	}
	gtk_combo_box_set_model (combo_box, model);
	renderer = gtk_cell_renderer_text_new();
	gtk_cell_layout_clear (GTK_CELL_LAYOUT(combo_box));
    gtk_cell_layout_pack_start (GTK_CELL_LAYOUT(combo_box), renderer, TRUE);
    gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT(combo_box), renderer, "text", 0 );
}

static gint
get_combo_box_value (GtkComboBox* combo_box)
{
	GtkTreeIter iter;
	GtkTreeModel *model;
	gint value = -1;

	if (gtk_combo_box_get_active_iter (combo_box, &iter))
	{
		model = gtk_combo_box_get_model (combo_box);
		gtk_tree_model_get (model, &iter, 1, &value, -1);
	}

	return value;
}

static gboolean
set_combo_box_value (GtkComboBox* combo_box, gint value)
{
	GtkTreeIter iter;
	GtkTreeModel *model;
	gint current;

	if (value != -1)
	{
		model = gtk_combo_box_get_model (combo_box);
		if (gtk_tree_model_get_iter_first (model, &iter))
		{
			do
			{
				gtk_tree_model_get (model, &iter, 1, &current, -1);
				if (value == current)
				{
					gtk_combo_box_set_active_iter (combo_box, &iter);
	
					return TRUE;
				}
			}
			while (gtk_tree_model_iter_next (model, &iter));
		}
	}

	gtk_combo_box_set_active (combo_box, 0);

	return FALSE;
}

/* Tool variable dialog
 * Display a list of variables useable as command line parameters or working
 * directory with their values. Clicking on a variable add it in the current
 * entry widget.
 *---------------------------------------------------------------------------*/

static ATPVariableDialog*
atp_variable_dialog_construct (ATPVariableDialog* this, ATPToolEditor* editor, ATPVariableType type)
{
	this->dialog = NULL;
	this->editor = editor;
	this->type = type;

	return this;
}

static void
atp_variable_dialog_destroy (ATPVariableDialog* this)
{
	if (this->dialog)
	{
		gtk_widget_destroy (GTK_WIDGET (this->dialog));
		this->dialog = NULL;
	}
}

static void
atp_variable_dialog_set_entry (ATPVariableDialog *this, GtkEditable* entry)
{
	this->entry = entry;
}

static void
atp_variable_dialog_populate (ATPVariableDialog* this, ATPFlags flag)
{
	GtkTreeModel *model;
	ATPVariable* variable;
	guint i;

	variable = atp_tool_dialog_get_variable (this->editor->parent);
	model = gtk_tree_view_get_model (this->view);
	gtk_list_store_clear (GTK_LIST_STORE(model));

	for (i = atp_variable_get_count(variable); i > 0;)
	{
		GtkTreeIter iter;
		gchar* value;
		const gchar* value_col;
		ATPFlags var_flags;

		--i;
		var_flags = atp_variable_get_flag (variable, i);
		if (!(var_flags & ATP_NO_VARIABLE) && ((flag == ATP_DEFAULT_VARIABLE) || (var_flags & flag)))
		{
			if (var_flags & ATP_INTERACTIVE_VARIABLE)
			{
				value = NULL;
				value_col = _("ask at runtime");
			}
			else
			{
				value = atp_variable_get_value_from_id (variable, i);
				value_col = (value == NULL) ? _("undefined") : value;
			}
			gtk_list_store_append (GTK_LIST_STORE(model), &iter);
			gtk_list_store_set (GTK_LIST_STORE(model), &iter,
				ATP_VARIABLE_NAME_COLUMN,
				atp_variable_get_name(variable, i),
				ATP_VARIABLE_MEAN_COLUMN,
				_(atp_variable_get_help(variable, i)),
				ATP_VARIABLE_VALUE_COLUMN,
				value_col,
				-1);
			if (value) g_free (value);
		}
	}
}

static void
atp_variable_dialog_add_variable(ATPVariableDialog *this, const gchar* text)
{
	gint pos;

	g_return_if_fail (this->entry);

	if (text != NULL)
	{
		gchar* next;

		if (this->type == ATP_VARIABLE_REPLACE)
		{
			gtk_editable_delete_text (this->entry, 0, -1);
		}
	
		pos = gtk_editable_get_position(this->entry);
		/* Add space before if useful */
		if (pos != 0)
		{
			next = gtk_editable_get_chars (this->entry, pos - 1, pos);

			if (!g_ascii_isspace (*next))
			{
				gtk_editable_insert_text (this->entry, " ", 1, &pos);
			}
			g_free (next);
		}
		gtk_editable_insert_text (this->entry, "$(", 2, &pos);
		gtk_editable_insert_text (this->entry, text, strlen(text), &pos);
		gtk_editable_insert_text (this->entry, ")", 1, &pos);
		/* Add space after if useful */
		next = gtk_editable_get_chars (this->entry, pos, pos + 1);
		if (next != NULL)
		{
			if ((*next != '\0') && (!g_ascii_isspace (*next)))
			{
				gtk_editable_insert_text (this->entry, " ",1, &pos);
			}
			g_free (next);
		}
	}
}

static gchar*
get_current_name (GtkTreeView *view)
{
	GtkTreeModel *model;
	GtkTreeSelection *sel;
	GtkTreeIter iter;
	gchar* name;

	model = gtk_tree_view_get_model (view);
	sel = gtk_tree_view_get_selection (view);
	if (gtk_tree_selection_get_selected (sel, &model, &iter))
	{
		gtk_tree_model_get (model, &iter, ATP_VARIABLE_NAME_COLUMN, &name, -1);

		return name;
	}

	return NULL;
}

void
atp_on_variable_activate_row (GtkTreeView *treeview, GtkTreePath *path, GtkTreeViewColumn *column, gpointer user_data)
{
	ATPVariableDialog *this = (ATPVariableDialog*)user_data;
	GtkTreeIter iter;
	GtkTreeModel *model;
	gchar* name;

	/* Get Selected variable name */
	model = gtk_tree_view_get_model (treeview);
	gtk_tree_model_get_iter (model, &iter, path);
	gtk_tree_model_get (model, &iter, ATP_VARIABLE_NAME_COLUMN, &name, -1);

	atp_variable_dialog_add_variable (this, name);	

	gtk_widget_hide (GTK_WIDGET (this->dialog));
}

void
atp_on_variable_dialog_response (GtkDialog *dialog, gint response, gpointer user_data)
{
	ATPVariableDialog *this = (ATPVariableDialog *)user_data;
	gchar* name;

	switch (response)
	{
	case GTK_RESPONSE_OK:
		name = get_current_name (this->view);
		atp_variable_dialog_add_variable (this, name);
		break;
	default:
		break;
	}

	gtk_widget_hide (GTK_WIDGET (this->dialog));
}

static gboolean
atp_variable_dialog_show (ATPVariableDialog* this, ATPFlags flag)
{
	GtkBuilder *bxml;
	GtkTreeModel *model;
	GtkCellRenderer *renderer;
	GtkTreeViewColumn *column;

	if (this->dialog != NULL)
	{
		/* Display dialog box */
		if (this->dialog) gtk_window_present (GTK_WINDOW (this->dialog));
		return TRUE;
	}

	bxml = anjuta_util_builder_new (GLADE_FILE, NULL);
	if (!bxml) return FALSE;
	anjuta_util_builder_get_objects (bxml,
	    TOOL_VARIABLE, &this->dialog,
	    VARIABLE_TREEVIEW, &this->view,
	    NULL);
	
	gtk_widget_show (GTK_WIDGET (this->dialog));
	gtk_window_set_transient_for (GTK_WINDOW (this->dialog), GTK_WINDOW (this->editor->dialog));

	/* Create variable list */
	model = GTK_TREE_MODEL (gtk_list_store_new (ATP_N_VARIABLE_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING));
	gtk_tree_view_set_model (this->view, model);

	renderer = gtk_cell_renderer_text_new ();
	column = gtk_tree_view_column_new_with_attributes (_("Variable"), renderer, "text", ATP_VARIABLE_NAME_COLUMN, NULL);
	gtk_tree_view_append_column (this->view, column);
	renderer = gtk_cell_renderer_text_new ();
	column = gtk_tree_view_column_new_with_attributes (_("Meaning"), renderer, "text", ATP_VARIABLE_MEAN_COLUMN, NULL);
	gtk_tree_view_append_column (this->view, column);
	renderer = gtk_cell_renderer_text_new ();
	column = gtk_tree_view_column_new_with_attributes (_("Value"), renderer, "text", ATP_VARIABLE_VALUE_COLUMN, NULL);
	gtk_tree_view_append_column (this->view, column);
	g_object_unref (model);
	atp_variable_dialog_populate (this, flag);

	/* Connect all signals */
	gtk_builder_connect_signals (bxml, this);
	g_signal_connect (G_OBJECT (this->dialog), "delete_event", G_CALLBACK (gtk_widget_hide_on_delete), NULL);

	g_object_unref (bxml);

	return TRUE;
}

/* Tool editor dialog
 *---------------------------------------------------------------------------*/

static void
cb_preview_update (GtkFileChooser *fc,
		   GtkImage *preview)
{
	char *filename;
	GdkPixbuf *pixbuf;

	filename = gtk_file_chooser_get_preview_filename (fc);
	if (filename) {
		pixbuf = gdk_pixbuf_new_from_file (filename, NULL);

		gtk_file_chooser_set_preview_widget_active (fc, pixbuf != NULL);
		
		if (pixbuf) {
			gtk_image_set_from_pixbuf (preview, pixbuf);
			g_object_unref (pixbuf);
		}
		
		g_free (filename);
	}
}

void
atp_on_editor_icon_entry_clicked (GtkButton *button, gpointer user_data)
{
	ATPToolEditor *this = (ATPToolEditor *)user_data;
	GtkWidget *dialog;
	GtkFileFilter *filter;
	GtkWidget *preview;
	int res;

	dialog = gtk_file_chooser_dialog_new (_("Select an Image File"),
											NULL,
					      					GTK_FILE_CHOOSER_ACTION_OPEN, 
					      					GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
					      					GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
					      					NULL);
	gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog),
	    									PACKAGE_PIXMAPS_DIR);
	filter = gtk_file_filter_new ();
	gtk_file_filter_add_pixbuf_formats (filter);
	gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (dialog), filter);

	preview = gtk_image_new ();
	gtk_file_chooser_set_preview_widget (GTK_FILE_CHOOSER (dialog),
	    								    preview);
	g_signal_connect (dialog, "update-preview",
			  								G_CALLBACK (cb_preview_update), preview);

	res = gtk_dialog_run (GTK_DIALOG (dialog));

	if (res == GTK_RESPONSE_ACCEPT) {
    	gchar *filename;

    	filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
		if (filename != NULL)
		{
			GtkWidget* image;
			image = gtk_image_new_from_file (filename);
			gtk_button_set_image (button, image);
			gtk_button_set_label (button, NULL);
		}
		else
		{
			gtk_button_set_image (button, NULL);
			gtk_button_set_label (button, _("Choose Icon"));
		}
		atp_user_tool_set_icon (this->tool, filename);
		g_free (filename);
	}

	gtk_widget_destroy (dialog);
}

static void
atp_clear_tool_editor(ATPToolEditor* this)
{
	g_return_if_fail (this != NULL);

	gtk_editable_delete_text(this->name_en, 0, -1);
	gtk_editable_delete_text(this->command_en, 0, -1);
	gtk_editable_delete_text(this->param_en, 0, -1);
	gtk_editable_delete_text(this->dir_en, 0, -1);
}

static void
atp_update_sensitivity(ATPToolEditor *this)
{
	gboolean en;

	/* Deactivate output and input setting if a terminal is used */
	en = gtk_toggle_button_get_active (this->terminal_tb);
	gtk_widget_set_sensitive(GTK_WIDGET (this->output_com), !en);
	gtk_widget_set_sensitive(GTK_WIDGET (this->error_com), !en);
	gtk_widget_set_sensitive(GTK_WIDGET (this->input_com), !en);

	/* input value is available for a few input type only */
	if (!en)
	{
		switch (get_combo_box_value (this->input_com))
		{
		case ATP_TIN_FILE:
		case ATP_TIN_STRING:
			en = TRUE;
			break;
		default:
			en = FALSE;
			break;
		}
		gtk_widget_set_sensitive(GTK_WIDGET (this->input_en), en);
		gtk_widget_set_sensitive(GTK_WIDGET (this->input_var_bt), en);
	}
	else
	{
		gtk_widget_set_sensitive(GTK_WIDGET (this->input_en), FALSE);
		gtk_widget_set_sensitive(GTK_WIDGET (this->input_var_bt), FALSE);
	}
}

static void
atp_editor_update_shortcut (ATPToolEditor* this)
{
	if (this->shortcut != NULL)
	{
		gtk_button_set_label (GTK_BUTTON (this->shortcut_bt), this->shortcut);
	}
	else
	{
		gtk_button_set_label (GTK_BUTTON (this->shortcut_bt), _("Disabled"));
	}
}

static void
atp_populate_tool_editor(ATPToolEditor* this)
{
	gint pos;
	const gchar* value;
	guint accel_key;
	GdkModifierType accel_mods;

	g_return_if_fail (this != NULL);

	/* Nothing to fill */
	if (this->tool == NULL) return;

	value = atp_user_tool_get_name (this->tool);
	if (value)
	{
		gtk_editable_insert_text(this->name_en, value
			  , strlen(value), &pos);
	}
	value = atp_user_tool_get_command (this->tool);
	if (value)
	{
		gtk_editable_insert_text(this->command_en, value
		  , strlen(value), &pos);
	}
	value = atp_user_tool_get_param (this->tool);
	if (value)
	{
		gtk_editable_insert_text(this->param_en, value
		  , strlen(value), &pos);
	}
	value = atp_user_tool_get_working_dir (this->tool);
	if (value)
	{
		gtk_editable_insert_text(this->dir_en, value
		  , strlen(value), &pos);
	}
	gtk_toggle_button_set_active (this->enabled_tb, atp_user_tool_get_flag (this->tool, ATP_TOOL_ENABLE));
	gtk_toggle_button_set_active (this->autosave_tb, atp_user_tool_get_flag (this->tool, ATP_TOOL_AUTOSAVE));
	gtk_toggle_button_set_active (this->terminal_tb, atp_user_tool_get_flag (this->tool, ATP_TOOL_TERMINAL));

	set_combo_box_value (this->output_com, atp_user_tool_get_output (this->tool));
	set_combo_box_value (this->error_com, atp_user_tool_get_error (this->tool));
	set_combo_box_value (this->input_com, atp_user_tool_get_input (this->tool));
	switch (atp_user_tool_get_input (this->tool))
	{
	case ATP_TIN_FILE:
	case ATP_TIN_STRING:
		value = atp_user_tool_get_input_string (this->tool);
		if (value)
		{
			gtk_editable_insert_text(this->input_en, value, strlen(value), &pos);
		}
		break;
	default:
		break;
	}
	atp_update_sensitivity (this);

	if (this->shortcut != NULL) g_free (this->shortcut);
	if (atp_user_tool_get_accelerator (this->tool, &accel_key, &accel_mods))
	{
		this->shortcut = gtk_accelerator_name (accel_key, accel_mods);
	}
	else
	{
		this->shortcut = NULL;
	}
	atp_editor_update_shortcut (this);

	if (atp_user_tool_get_icon (this->tool))
	{
		GtkWidget* image;
		image = gtk_image_new_from_file (atp_user_tool_get_icon (this->tool));
		gtk_button_set_image (this->icon_en, image);
		gtk_button_set_label (this->icon_en, NULL);
	}
	else
	{
		gtk_button_set_image (this->icon_en, NULL);
		gtk_button_set_label (this->icon_en, _("Choose Icon"));
	}
}

void
atp_on_editor_terminal_toggle (GtkToggleButton *tb, gpointer user_data)
{
	ATPToolEditor *this = (ATPToolEditor *)user_data;

	atp_update_sensitivity (this);
}

void
atp_on_editor_script_toggle (GtkToggleButton *tb, gpointer user_data)
{
	ATPToolEditor *this = (ATPToolEditor *)user_data;
	gchar* command;

	if (gtk_toggle_button_get_active(tb))
	{
		/* Get current command */
		command = gtk_editable_get_chars(this->command_en, 0, -1);

		if ((command == NULL) || (*command == '\0'))
		{
			gchar* name;
			gint pos;

			if (command) g_free (command);
			/* Generate a new script file name */
			command = gtk_editable_get_chars(this->name_en, 0, -1);
			if ((command == NULL) || (*command == '\0'))
			{
				command = g_strdup("script");
			}
			name = atp_remove_mnemonic (command);
			g_free (command);

			command = anjuta_util_get_user_data_file_path ("scripts/", name, NULL);
			g_free (name);

			/* Find a new file name */
			name = command;
			pos = 0;
			while (g_file_test (command, G_FILE_TEST_EXISTS))
			{
				if (command != name) g_free (command);
				command = g_strdup_printf("%s%d", name, pos); 
				pos++;	
			}
			if (command != name) g_free (name);

			/* Fill command line */
			gtk_editable_delete_text(this->command_en, 0, -1);
			gtk_editable_insert_text(this->command_en, command,
									 strlen(command), &pos);
		}
		if (command) g_free (command);
	}
}

void
atp_on_editor_input_changed (GtkComboBox *combo, gpointer user_data)
{
	ATPToolEditor *this = (ATPToolEditor *)user_data;

	atp_update_sensitivity (this);
}

void
atp_on_editor_dialog_response (GtkDialog *dialog, gint response, gpointer user_data)
{
	ATPToolEditor* this = (ATPToolEditor*)user_data;
	gchar* name;
	gchar* data;
	ATPInputType in_type;
	guint accel_key;
	GdkModifierType accel_mods;
	GtkAccelGroup* group;
	AnjutaUI* ui;

	if (response == GTK_RESPONSE_OK)
	{
		/* Check for all mandatory fields */
		name = gtk_editable_get_chars(this->name_en, 0, -1);
		if (!name || '\0' == name[0])
		{
			if (name) g_free (name);
			anjuta_util_dialog_error(GTK_WINDOW (this->dialog), _("You must provide a tool name!"));
			return;
		}
		data = gtk_editable_get_chars(this->command_en, 0, -1);
		if (!data || '\0' == data[0])
		{
			if (name) g_free (name);
			if (data) g_free (data);
			anjuta_util_dialog_error(GTK_WINDOW (this->dialog), _("You must provide a tool command!"));
			return;
		}

		if (!atp_user_tool_set_name (this->tool, name))
		{
			if (name) g_free (name);
			if (data) g_free (data);
			anjuta_util_dialog_error(GTK_WINDOW (this->dialog), _("A tool with the same name already exists!"));
			return;
		}
		g_free (name);
		
		if (this->shortcut == NULL)
		{
			accel_key = 0;
			accel_mods = 0;
		}
		else
		{
			gtk_accelerator_parse (this->shortcut, &accel_key, &accel_mods);
			ui = anjuta_shell_get_ui (ANJUTA_PLUGIN(this->parent->plugin)->shell, NULL);
			group = anjuta_ui_get_accel_group(ui);
			if (gtk_accel_group_query (group, accel_key, accel_mods, NULL) != NULL)
			{
				if (!anjuta_util_dialog_boolean_question (GTK_WINDOW (this->dialog), FALSE,
				    _("The shortcut is already used by another component in Anjuta. Do you want to keep it anyway?")))
				{
					return;
				}
			}
		}

		/* Set new tool data */
		atp_user_tool_set_command (this->tool, data);
		g_free (data);

		data = gtk_editable_get_chars(this->param_en, 0, -1);
		atp_user_tool_set_param (this->tool, data);
		g_free (data);

		data = gtk_editable_get_chars(this->dir_en, 0, -1);
		atp_user_tool_set_working_dir (this->tool, data);
		g_free (data);

		atp_user_tool_set_flag (this->tool, ATP_TOOL_ENABLE | (gtk_toggle_button_get_active(this->enabled_tb) ? ATP_SET : ATP_CLEAR));

		atp_user_tool_set_flag (this->tool, ATP_TOOL_AUTOSAVE | (gtk_toggle_button_get_active(this->autosave_tb) ? ATP_SET : ATP_CLEAR));

		atp_user_tool_set_flag (this->tool, ATP_TOOL_TERMINAL | (gtk_toggle_button_get_active(this->terminal_tb) ? ATP_SET : ATP_CLEAR));


		atp_user_tool_set_output (this->tool, get_combo_box_value (this->output_com));
		atp_user_tool_set_error (this->tool, get_combo_box_value (this->error_com));
		in_type = get_combo_box_value (this->input_com);
		switch (in_type)
		{
		case ATP_TIN_FILE:
		case ATP_TIN_STRING:
			data = gtk_editable_get_chars(this->input_en, 0, -1);
			atp_user_tool_set_input (this->tool, in_type, data);
			g_free (data);
			break;
		default:
			atp_user_tool_set_input (this->tool, in_type, NULL);
			break;
		}

		atp_user_tool_set_accelerator (this->tool, accel_key, accel_mods);

		/* Open script in editor if requested */
		if (gtk_toggle_button_get_active (this->script_tb))
		{
			IAnjutaDocumentManager *docman;
			IAnjutaDocument *doc;
			GFile* file;

			/* Check that default script directory exist */
			data = anjuta_util_get_user_data_file_path ("scripts/", NULL);

			// TODO: Replace with g_mkdir_with_parents
			make_directory (data);
			g_free (data);

			data = gtk_editable_get_chars(this->command_en, 0, -1);

			if (!g_file_test (data, G_FILE_TEST_EXISTS))
			{
				FILE* sh;

				/* Create default script */
				sh = fopen (data, "wt");
				if (sh != NULL)
				{
					gint previous;

					fprintf(sh, "#!\n#\tScript template generated by Anjuta.\n#\tYou can pass argument using command line parameters\n#\n\n");
					fclose (sh);

					/* Make this file executable */
					previous = umask (0666);
					chmod (data, 0777 & ~previous);
					umask (previous);
				}
			}

			/* Load the script in an editor window */
			docman = anjuta_shell_get_interface (ANJUTA_PLUGIN (this->parent->plugin)->shell, IAnjutaDocumentManager, NULL);
			if (docman == NULL)
			{	       
				anjuta_util_dialog_error(GTK_WINDOW (this->dialog), _("Unable to edit script"));
				return;
			}

			file = g_file_new_for_path (data);
			g_free (data);
			doc =
				ianjuta_document_manager_find_document_with_file 
							   (docman, file, NULL);
			if (doc == NULL)
			{
				IAnjutaFileLoader* loader;

				/* Not found, load file */
				loader = IANJUTA_FILE_LOADER (anjuta_shell_get_interface (ANJUTA_PLUGIN (this->parent->plugin)->shell, IAnjutaFileLoader, NULL));
				ianjuta_file_loader_load (loader, file, FALSE, NULL);
			}
			else
			{
				/* Set as current */
				ianjuta_document_manager_set_current_document (docman, doc, NULL);
			}
			g_object_unref (file);
		}
	}
	
	atp_tool_dialog_refresh (this->parent, atp_user_tool_get_name (this->tool));
	
	atp_tool_editor_free (this);
}

void
atp_on_editor_param_variable_show (GtkButton *button, gpointer user_data)
{
	ATPToolEditor* this = (ATPToolEditor*)user_data;

	atp_variable_dialog_show (&this->param_var, ATP_DEFAULT_VARIABLE);	
}

void
atp_on_editor_dir_variable_show (GtkButton *button, gpointer user_data)
{
	ATPToolEditor* this = (ATPToolEditor*)user_data;

	atp_variable_dialog_show (&this->dir_var, ATP_DIRECTORY_VARIABLE);
}

void
atp_on_editor_input_variable_show (GtkButton *button, gpointer user_data)
{
	ATPToolEditor* this = (ATPToolEditor*)user_data;

	switch (get_combo_box_value (this->input_com))
	{
	case ATP_TIN_FILE:
		atp_variable_dialog_show (&this->input_file_var, ATP_FILE_VARIABLE);
		break;
	case ATP_TIN_STRING:
		atp_variable_dialog_show (&this->input_string_var, ATP_DEFAULT_VARIABLE);
		break;
	}
}

static gboolean
on_editor_get_keys(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
{
	ATPToolEditor *this = (ATPToolEditor*)user_data;
  	GdkDisplay *display;
  	guint accel_key = 0;
	GdkModifierType	accel_mods = 0;
  	GdkModifierType consumed_mods = 0;
	gboolean delete = FALSE;
	gboolean edited = FALSE;

  	switch (event->keyval)
    	{
	case GDK_KEY_Shift_L:
	case GDK_KEY_Shift_R:
	case GDK_KEY_Control_L:
	case GDK_KEY_Control_R:
	case GDK_KEY_Alt_L:
	case GDK_KEY_Alt_R:
		return TRUE;
	case GDK_KEY_Escape:
		break;
	case GDK_KEY_Delete:
	case GDK_KEY_KP_Delete:
	case GDK_KEY_BackSpace:
		delete = TRUE;
		break;
	default:
  		display = gtk_widget_get_display (widget);
		gdk_keymap_translate_keyboard_state (gdk_keymap_get_for_display (display),
                                       event->hardware_keycode,
                                       event->state,
                                       event->group,
                                       NULL, NULL, NULL, &consumed_mods);

		accel_key = gdk_keyval_to_lower (event->keyval);
		accel_mods = (event->state & gtk_accelerator_get_default_mod_mask () & ~consumed_mods);

		/* If lowercasing affects the keysym, then we need to include SHIFT
		* in the modifiers, We re-upper case when we match against the
		* keyval, but display and save in caseless form.
		*/
		if (accel_key != event->keyval)
			accel_mods |= GDK_SHIFT_MASK;

		edited = gtk_accelerator_valid (accel_key, accel_mods);
		break;
	}

	if (delete || edited)
	{
		/* Remove previous shortcut */
		if (this->shortcut != NULL) g_free (this->shortcut);

		/* Set new one */
		this->shortcut = delete ? NULL : gtk_accelerator_name (accel_key, accel_mods);
	}
	
	gtk_toggle_button_set_active (this->shortcut_bt, FALSE);

	return TRUE;
}

void
atp_on_editor_shortcut_toggle (GtkToggleButton *tb, gpointer user_data)
{
	ATPToolEditor *this = (ATPToolEditor *)user_data;

	if (gtk_toggle_button_get_active (tb))
	{
		gtk_grab_add(GTK_WIDGET(tb));

  		g_signal_connect (G_OBJECT (tb), "key_press_event", G_CALLBACK (on_editor_get_keys), this);
  		gtk_button_set_label (GTK_BUTTON (tb), _("New accelerator…"));
	}
	else
	{
		g_signal_handlers_disconnect_by_func (G_OBJECT (this->shortcut_bt), G_CALLBACK (on_editor_get_keys), this);
		gtk_grab_remove (GTK_WIDGET(this->shortcut_bt));

		atp_editor_update_shortcut (this);
	}
}

void
atp_on_editor_browse_button_clicked (GtkButton *button, GtkEntry *entry)
{
	GtkWidget *dialog;
	dialog = gtk_file_chooser_dialog_new ("Open File",
					      NULL,
					      GTK_FILE_CHOOSER_ACTION_OPEN,
					      GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
					      GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
					      NULL);
	if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
	{
		char *filename;
		filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));

		gtk_entry_set_text (entry, filename);

		g_free (filename);
	}
	gtk_widget_destroy(dialog);
}

void
atp_on_editor_browse_button_dir_clicked (GtkButton *button, GtkEntry *entry)
{
	GtkWidget *dialog;
	dialog = gtk_file_chooser_dialog_new ("Open",
					      NULL,
					      GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
					      GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
					      GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
					      NULL);
	if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
	{
		char *filename;
		filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));

		gtk_entry_set_text (entry, filename);

		g_free (filename);
	}
	gtk_widget_destroy(dialog);
}

gboolean
atp_tool_editor_show (ATPToolEditor* this)
{
	GtkBuilder *bxml;

	if (this->dialog != NULL)
	{
		/* dialog is already displayed */
		gtk_window_present (GTK_WINDOW (this->dialog));
		return TRUE;
	}

	bxml = anjuta_util_builder_new (GLADE_FILE, NULL);
	if (!bxml) return FALSE;

	/* Get all objects */
	anjuta_util_builder_get_objects (bxml,
	    TOOL_EDITOR, &this->dialog,
		TOOL_NAME, &this->name_en ,
		TOOL_COMMAND, &this->command_en,
		TOOL_PARAM, &this->param_en,
		TOOL_WORKING_DIR, &this->dir_en,
		TOOL_ENABLED, &this->enabled_tb,
		TOOL_TERMINAL, &this->terminal_tb,
		TOOL_AUTOSAVE, &this->autosave_tb,
		TOOL_SCRIPT, &this->script_tb,
		TOOL_OUTPUT, &this->output_com,
		TOOL_ERROR, &this->error_com,
		TOOL_INPUT, &this->input_com,
		TOOL_INPUT_VALUE, &this->input_en,
		TOOL_INPUT_VARIABLE, &this->input_var_bt,
		TOOL_SHORTCUT, &this->shortcut_bt,
		TOOL_ICON, &this->icon_en,
	    NULL);
	    
	gtk_widget_show (this->dialog);
	gtk_window_set_transient_for (GTK_WINDOW (this->dialog), atp_plugin_get_app_window (this->parent->plugin));

	/* Initialize entries */
	atp_variable_dialog_set_entry (&this->param_var, this->param_en);
	atp_variable_dialog_set_entry (&this->dir_var, this->dir_en);
	atp_variable_dialog_set_entry (&this->input_file_var, this->input_en);
	atp_variable_dialog_set_entry (&this->input_string_var, this->input_en);

	/* Add combox box value */
	set_combo_box_enum_model (this->error_com, atp_get_error_type_list());
	set_combo_box_enum_model (this->output_com, atp_get_output_type_list());
	set_combo_box_enum_model (this->input_com, atp_get_input_type_list());

	atp_clear_tool_editor (this);
	atp_populate_tool_editor (this);
	atp_update_sensitivity (this);

	/* Connect all signals */
	gtk_builder_connect_signals (bxml, this);
	
	g_object_unref (bxml);

	return TRUE;
}

ATPToolEditor* 
atp_tool_editor_new (ATPUserTool *tool, ATPToolEditorList *list, struct _ATPToolDialog *dialog)
{
	ATPToolEditor *this;

	/* Search a already existing tool editor with same name */
	for (this = list->first; this != NULL; this = this->next)
	{
		/* Name use the same string, so a string comparaison is not necessary */
		if (atp_user_tool_get_name (this->tool) == atp_user_tool_get_name (tool))
		{
			return this;
		}
	}

	/* Not found, create a new object */
	this = g_new0(ATPToolEditor, 1);
	this->parent = dialog;
	this->owner = list;
	this->tool = tool;
	atp_variable_dialog_construct (&this->param_var, this, ATP_VARIABLE_DEFAULT);
	atp_variable_dialog_construct (&this->dir_var, this, ATP_VARIABLE_REPLACE);
	atp_variable_dialog_construct (&this->input_file_var, this, ATP_VARIABLE_REPLACE);
	atp_variable_dialog_construct (&this->input_string_var, this, ATP_VARIABLE_REPLACE);

	/* Add it in the list */
	if (list != NULL)
	{
		this->next = list->first;
		list->first = this;
	}

	return this;	
}

gboolean
atp_tool_editor_free (ATPToolEditor *this)
{
	ATPToolEditor **prev;

	atp_variable_dialog_destroy (&this->input_string_var);
	atp_variable_dialog_destroy (&this->input_file_var);
	atp_variable_dialog_destroy (&this->dir_var);
	atp_variable_dialog_destroy (&this->param_var);

	if (this->shortcut != NULL) g_free (this->shortcut);

	if (atp_user_tool_get_name (this->tool) == NULL) atp_user_tool_free(this->tool);
	
	if (this->owner == NULL)
	{
		/* tool editor is not in a list */
		gtk_widget_destroy (GTK_WIDGET (this->dialog));
		g_free (this);

		return TRUE;
	}

	/* Search tool editor in list */
	for (prev = &this->owner->first; *prev != NULL; prev = &((*prev)->next))
	{
		if (*prev == this)
		{
			/* remove tool editor from list */
			*prev = this->next;
			/* delete tool editor object */
			gtk_widget_destroy (GTK_WIDGET (this->dialog));
			g_free (this);

			return TRUE;
		}
	}

	/* tool editor not found in list */
	return FALSE;
}

/* Tool editor list
 * This list all the current active tool editors, it is mainly useful for
 * avoiding to have two dialogs editing the same tool. It could be possible
 * because the tool editing dialog is not modal.
 *---------------------------------------------------------------------------*/

ATPToolEditorList*
atp_tool_editor_list_construct (ATPToolEditorList* this)
{
	this->first = NULL;

	return this;
}

void
atp_tool_editor_list_destroy (ATPToolEditorList* this)
{
	ATPToolEditor *ted;

	for ( ; (ted = this->first) != NULL;)
	{
		atp_tool_editor_free (ted);
		
	}		
}

