/*  pledit.c - plugin list editor
 *  Copyright (C) 1999  Charles <int@linuxcore.com>
 *
 *  various changes for EFXmms (c) 2001 mld@users.sourceforge.net
 *
 *  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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 *
 * $Id: pledit.c,v 1.2 1999/12/27 13:08:25 int Exp $
 */


#ifdef HAVE_CONFIG_H
#include "config.h"
#endif /* HAVE_CONFIG_H */

#include <gtk/gtk.h>

#include "efx.h"

#define EFX_PAD 8
#define EFX_PAD_SMALL 4

enum
{
	TARGET_PLUGIN,
};


/*
 * list of drag types
 */
static GtkTargetEntry drag_types[] = {
	{"efx-plugin-name", 0, TARGET_PLUGIN},
};

static gint n_drag_types = sizeof (drag_types) / sizeof (drag_types[0]);


/*
 * list of drop types we can handle
 */
static GtkTargetEntry drop_types[] = {
	{"efx-plugin-name", 0, TARGET_PLUGIN},
};

static gint n_drop_types = sizeof (drop_types) / sizeof (drop_types[0]);



GtkCList *d_clist = NULL;
GtkCList *p_clist = NULL;

static GtkWidget *about_label = NULL;

/* Mutex */
static pthread_mutex_t efx_mutex = PTHREAD_MUTEX_INITIALIZER;
#define efx_lock() pthread_mutex_lock(&efx_mutex)
#define efx_unlock() pthread_mutex_unlock(&efx_mutex)

/*
 * return row at y pixel.  is there a better way to do this?
 */
static int get_row_at_ypixel (GtkCList * clist, gint y)
{
	GtkWidget *widget;
	int row;

	widget = GTK_WIDGET (clist);

	y -= (GTK_CONTAINER (clist)->border_width +
	      widget->style->klass->ythickness +
	      clist->column_title_area.height);

	row = ((y - clist->voffset) / (clist->row_height + 1));

	return row;
}

/*
 * return the clicked row
 */
static int get_clicked_row (GtkCList * clist)
{
	return clist->click_cell.row;
}


static void drag_begin (GtkWidget * widget, GdkDragContext * context)
{
	//g_print("DRAG_BEGIN\n");
}


/*
 * set plugin name in selection data
 */
static void drag_data_get (GtkWidget * widget, GdkDragContext * context,
			   GtkSelectionData * selection_data, guint info,
			   guint time, gpointer arg)
{
	GtkCList *clist;
	gchar *name;
	int row;

	g_return_if_fail (widget != NULL);
	g_return_if_fail (GTK_IS_CLIST (widget));

	clist = GTK_CLIST (widget);


	row = clist->click_cell.row;
	if (row < 0)
		return;

	name = gtk_clist_get_row_data (clist, row);

	if (!name)
		return;

	gtk_selection_data_set (selection_data,
				selection_data->target, 0,
				name, strlen (name) + 1);



}
/*
 * reorder active plugin list
 */
static void reorder_list (GtkCList * clist)
{
	EffectPlugin *efx = NULL;
	GList *newlist = NULL;
	int i,a;

	/* Does not work yet :( */

	a = clist->rows;

	for(i = 0; i < a; i++)
	{
	    //g_print ("reorder: %d\n",i);
	    newlist = g_list_append(newlist, gtk_clist_get_row_data(clist, i));
	}

	g_list_free (active_efx_list);
	active_efx_list = g_list_copy (newlist);
}


static void drag_data_received (GtkWidget * widget,
				GdkDragContext * context,
				gint x,
				gint y,
				GtkSelectionData * selection_data,
				guint info, guint time, gint dest_id)
{
	gchar *name;
	GtkWidget *source, *target;

	source = gtk_drag_get_source_widget (context);
	target = widget;
	name = selection_data->data;

	switch (info)
	{
		case TARGET_PLUGIN:
			{
				GtkCList *clist1 = GTK_CLIST (source);
				GtkCList *clist2 = GTK_CLIST (target);


				int r1 = get_clicked_row (clist1);
				int r2 = get_row_at_ypixel (clist2, y);

				r1 = MAX (r1, 0);
				r2 = MAX (r2, 0);
				r1 = MIN (r1, clist1->rows);
				r2 = MIN (r2, clist2->rows);


				gtk_clist_freeze (clist1);
				gtk_clist_freeze (clist2);
				efx_lock();

				if (source == target)
				{
					gtk_clist_row_move(clist1, r1, r2);
					if(dest_id == 0)
					reorder_list(clist1);
				}
				else if (dest_id == 0)
				{
					GList *entry;
					gchar *col[1];
					EffectPlugin *effect;

					gtk_clist_get_text (clist1, r1, 0,
							    &col[0]);

					gtk_clist_insert(clist2, r2, col);
					gtk_clist_set_row_data(clist2, r2, effect);

					for (entry = installed_efx_list;
					     entry != NULL;
					     entry = entry->next)
					{
						effect = entry->data;
						if (!strcasecmp
						    (effect->filename, name))
						gtk_clist_set_row_data(clist2, r2, effect);
					}

					reorder_list(clist2);

				}
				else if (dest_id == 1)
				{
					GList *tmp =
						g_list_nth (active_efx_list,
							    r1);
					active_efx_list =
						g_list_remove_link
						(active_efx_list, tmp);
					g_list_free_1 (tmp);
					gtk_clist_remove (clist1, r1);
				}
				efx_unlock();
				gtk_clist_thaw (clist1);
				gtk_clist_thaw (clist2);
			}
			break;

		default:
			//g_print("info(%d): %s\n", info, selection_data->data);
			break;
	}

}


/*
 * setup DnD stuff for widget
 */
static void dnd_add (GtkWidget * widget, gint id)
{
	gtk_drag_source_set (GTK_WIDGET (widget),
			     GDK_BUTTON1_MASK,
			     drag_types, n_drag_types, GDK_ACTION_COPY);


	gtk_drag_dest_set (GTK_WIDGET (widget),
			   GTK_DEST_DEFAULT_DROP |
			   GTK_DEST_DEFAULT_MOTION |
			   GTK_DEST_DEFAULT_HIGHLIGHT,
			   drop_types, n_drop_types, GDK_ACTION_COPY);


	gtk_signal_connect (GTK_OBJECT (widget), "drag_data_get",
			    GTK_SIGNAL_FUNC (drag_data_get), (gpointer) id);

	gtk_signal_connect (GTK_OBJECT (widget), "drag_begin",
			    GTK_SIGNAL_FUNC (drag_begin), widget);

	gtk_signal_connect (GTK_OBJECT (widget), "drag_data_received",
			    GTK_SIGNAL_FUNC (drag_data_received),
			    (gpointer) id);

}




/*
 * check for a double click on a plugin name, then popup either
 * plugin config dialog or about dialog
 */
static gint button_pressed (GtkWidget * widget, GdkEventButton * event,
			    gint id)
{
	int row = 0, col = 0;

	if (!gtk_clist_get_selection_info (GTK_CLIST (widget),
					   event->x, event->y, &row, &col))
		return FALSE;

	if (event->type != GDK_2BUTTON_PRESS)
		return FALSE;

	switch (id)
	{
		case 0:
			{
				EffectPlugin *effect =
					g_list_nth_data (active_efx_list,
							 row);

				if (effect && effect->configure)
					effect->configure ();
			}
			break;

		case 1:
			{
				EffectPlugin *effect =
					g_list_nth_data (active_efx_list,
							 row);

				if (effect && effect->about)
					effect->about ();
			}
			break;
	}

	return TRUE;
}



/*
 * setup clist contents with the active plugin list
 */
void add_dlist_to_clist (GtkCList * clist, GList * dlist)
{
	GList *gle;
	gchar *col[1];

	g_return_if_fail (clist != NULL);
	g_return_if_fail (dlist != NULL);


	for (gle = dlist; gle != NULL; gle = gle->next)
	{
		EffectPlugin *effect = gle->data;

		col[0] = g_strdup (effect->description);


		gtk_clist_freeze (clist);
		gtk_clist_append (clist, col);
		gtk_clist_set_row_data (clist, clist->rows - 1, effect);
		gtk_clist_thaw (clist);


	}
}

/*
 * setup clist with list of available plugins
 */
void add_plugins_to_clist (GtkCList * clist)
{
	GList *entry;
	gchar *col[1];
	EffectPlugin *effect;

	g_return_if_fail (clist != NULL);

	for (entry = installed_efx_list; entry != NULL; entry = entry->next)
	{

		effect = entry->data;
		col[0] = g_strdup (effect->description);

		gtk_clist_freeze (clist);
		gtk_clist_append (clist, col);
		gtk_clist_set_row_data (clist, clist->rows - 1,
					g_strdup (effect->filename));
		gtk_clist_thaw (clist);

	}


}



GtkWidget *make_framed_box (GtkWidget * box, const char *title)
{
	GtkWidget *frame, *vbox;

	frame = gtk_frame_new (title);
	vbox = gtk_vbox_new (FALSE, EFX_PAD);
	gtk_container_add (GTK_CONTAINER (frame), vbox);
	gtk_box_pack_start (GTK_BOX (box), frame, TRUE, TRUE, EFX_PAD_SMALL);

	return vbox;
}

/*
 * util function, returns a clist in a scrolled window
 */
static GtkWidget *add_scrolled_clist (GtkWidget * box, int cols,
				      gchar ** text)
{
	GtkWidget *clist, *scroller;

	clist = gtk_clist_new_with_titles (cols, text);
	scroller = gtk_scrolled_window_new (NULL, NULL);
	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroller),
					GTK_POLICY_AUTOMATIC,
					GTK_POLICY_AUTOMATIC);
	gtk_box_pack_start (GTK_BOX (box), scroller, TRUE, TRUE, 0);
	gtk_container_add (GTK_CONTAINER (scroller), clist);

	return clist;
}

/*
 * util function, returns a button with label & connects to signal.
 */
static GtkWidget *add_button (GtkWidget * box, gchar * text,
			      void (*f), gpointer id)
{
	GtkWidget *button;

	button = gtk_button_new_with_label (text);
	gtk_box_pack_start (GTK_BOX (box), button,
			    FALSE, FALSE, EFX_PAD_SMALL);
	gtk_signal_connect (GTK_OBJECT (button), "clicked",
			    GTK_SIGNAL_FUNC (f), id);
	return button;
}

static EffectPlugin *sel_efx = NULL;
static EffectPlugin *sel_p_name = NULL;


static void select_row_cb (GtkCList * clist, gint row, gint col,
			   GdkEvent * event, GtkWidget * button)
{
	if (clist == d_clist)
	{
		sel_efx = g_list_nth_data (active_efx_list, row);
		gtk_widget_set_sensitive (button, TRUE);
	}
	else
	{
		gtk_label_set_text (GTK_LABEL (about_label), _("About Plugin"));
		sel_p_name = g_list_nth_data (installed_efx_list, row);
	}
}

static void unselect_row_cb (GtkCList * clist, gint row, gint col,
			     GdkEvent * event, GtkWidget * button)
{
	if (clist == d_clist)
	{
		gtk_widget_set_sensitive (button, FALSE);
		sel_efx = NULL;
	}
	else
	{
		gtk_label_set_text (GTK_LABEL (about_label), _("About EFXmms"));
		sel_p_name = NULL;
	}
}



static void button_cb (GtkWidget * button, int id)
{

	switch (id)
	{
		case 0:	//configure plugin
			{

				EffectPlugin *efx = sel_efx;

				if (efx->configure)
					efx->configure ();
			}
			break;
			break;
		case 1:	//about plugin
			{
				EffectPlugin *efx = sel_p_name;

				if (!efx)
				{
					show_about_dialog ();
				}
				else if (efx->about)
				{
					show_about_plugin (efx);
				}
			}
	}
}


//TODO: make popup menus for both lists
GtkWidget *create_plugins_page ()
{
	GtkWidget *hbox, *box, *button;
	gchar *dtitles[] = { _("Name") };

	sel_p_name = NULL;

	hbox = gtk_hbox_new (TRUE, 0);

	// Active plugins list

	box = make_framed_box (hbox, _("Active Plugins"));
	gtk_container_border_width (GTK_CONTAINER (box), EFX_PAD);
	d_clist = GTK_CLIST (add_scrolled_clist (box, 1, dtitles));

	dnd_add (GTK_WIDGET (d_clist), 0);
	if (active_efx_list)
		add_dlist_to_clist (d_clist, active_efx_list);

	gtk_signal_connect (GTK_OBJECT (d_clist), "button_press_event",
			    GTK_SIGNAL_FUNC (button_pressed), (gpointer) 0);

	button = add_button (box, _("Configure"), button_cb, (gpointer) 0);
	gtk_widget_set_sensitive (button, FALSE);

	gtk_signal_connect (GTK_OBJECT (d_clist), "select_row",
			    GTK_SIGNAL_FUNC (select_row_cb), button);
	gtk_signal_connect (GTK_OBJECT (d_clist), "unselect_row",
			    GTK_SIGNAL_FUNC (unselect_row_cb), button);


	// Plugin List

	box = make_framed_box (hbox, _("Available Plugins"));
	gtk_container_border_width (GTK_CONTAINER (box), EFX_PAD);

	p_clist = GTK_CLIST (add_scrolled_clist (box, 1, dtitles));

	dnd_add (GTK_WIDGET (p_clist), 1);
	add_plugins_to_clist (p_clist);

	gtk_signal_connect (GTK_OBJECT (p_clist), "button_press_event",
			    GTK_SIGNAL_FUNC (button_pressed), (gpointer) 1);

	button = add_button (box, "abc", button_cb, (gpointer) 1);
	gtk_container_remove (GTK_CONTAINER (button),
			      gtk_container_children (GTK_CONTAINER
						      (button))->data);
	about_label = gtk_label_new (_("About EFXmms"));
	gtk_container_add (GTK_CONTAINER (button), about_label);

	gtk_signal_connect (GTK_OBJECT (p_clist), "select_row",
			    GTK_SIGNAL_FUNC (select_row_cb), button);
	gtk_signal_connect (GTK_OBJECT (p_clist), "unselect_row",
			    GTK_SIGNAL_FUNC (unselect_row_cb), button);

	return hbox;
}

