/* Bluefish HTML Editor
 * stringlist.c - functions that deal with stringlists
 *
 * Copyright (C) 1999 Olivier Sessink and Hylke van der Schaaf
 * 
 * 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
 */
#include "default_include.h"


#include <stdio.h>
#include <string.h>  	/* strspn() */
#include "bluefish.h"
#include "bf_lib.h"
#include "html.h"
#include "coloursel.h" /* color_but_new() */
#include "stringlist.h"
#include "gtk_easy.h"

#define STRING_MAX_SIZE 1024
#define MAX_ARRAY_LENGTH 10

typedef struct {
	GtkWidget *window;
	GtkWidget *ins_upd_entry[MAX_ARRAY_LENGTH];
	GtkWidget *clist;
	guint num_columns;
	gint last_row;
	GList *the_list;
} Teditstringlist;

/************************************************************************/


/************************************************************************/

typedef struct {
	GtkWidget *win;
	GtkWidget *ins_upd_entry[MAX_ARRAY_LENGTH];
	GtkWidget *clist;
	gint num_columns;
	gint last_row;
	GList **the_list;
	void *(*function) ();
} Testrl;


static void estrl_destroy_lcb(GtkWidget * widget, GdkEvent *event, Testrl *estrl) {
	window_destroy(estrl->win);
	g_free(estrl);
}

static void estrl_cancel_clicked_lcb(GtkWidget * widget, Testrl *estrl) {
	estrl_destroy_lcb(NULL, NULL, estrl);
}

static void estrl_ok_clicked_lcb(GtkWidget * widget, Testrl *estrl) {

	guint i;
	gchar *tmpstring;
	gchar **tmparray;
	gint row=0, retval=1;
	GList *the_list=NULL, *orig_list;

	retval = gtk_clist_get_text(GTK_CLIST(estrl->clist), row, 0, &tmpstring);
	while (retval == 1) {
		tmparray = g_malloc(((estrl->num_columns ? estrl->num_columns : 1)+2)*sizeof(char *));
		for (i = 0; i < (estrl->num_columns ? estrl->num_columns  : 1); i++) {
			gtk_clist_get_text(GTK_CLIST(estrl->clist), row, i, &tmpstring);
			tmparray[i] = g_strdup(tmpstring);
		}
		tmparray[i] = NULL;
		if (estrl->num_columns == 0) {
			the_list = g_list_append(the_list, tmparray[0]);
			g_free(tmparray);
		} else {
			the_list = g_list_append(the_list, tmparray);
		}
		row++;
		retval = gtk_clist_get_text(GTK_CLIST(estrl->clist), row, 0, &tmpstring);
	}
	DEBUG_MSG("estrl_ok_clicked_lcb, going to add %p to the list\n", the_list);
	orig_list = *estrl->the_list;
	*estrl->the_list = the_list;

	if (estrl->num_columns) {
		free_arraylist(orig_list);
	} else {
		free_stringlist(orig_list);
	}

	if (estrl->function)
		estrl->function();

	estrl_destroy_lcb(NULL, NULL, estrl);
}

static void estrl_select_row_lcb(GtkWidget * widget, gint row, gint column, GdkEventButton * event, Testrl *estrl){
	gchar *text;
	guint i;

	for (i = 0; i < ( estrl->num_columns ? estrl->num_columns : 1); i++) {
		gtk_clist_get_text(GTK_CLIST(estrl->clist), row, i, &text);
		gtk_entry_set_text(GTK_ENTRY(estrl->ins_upd_entry[i]), text);
	}
	estrl->last_row = row;
}

static void estrl_unselect_row_lcb(GtkWidget * widget, gint row, gint column, GdkEventButton * event, Testrl *estrl) {
	estrl->last_row = -1;
}

static void estrl_up_clicked_lcb(GtkWidget * widget, Testrl *estrl) {
	if (estrl->last_row >= 1) {
		gtk_clist_swap_rows(GTK_CLIST(estrl->clist), estrl->last_row, estrl->last_row - 1);
		estrl->last_row--;
	}
}

static void estrl_down_clicked_lcb(GtkWidget * widget, Testrl *estrl) {
	if (estrl->last_row < GTK_CLIST(estrl->clist)->rows - 1) {
		gtk_clist_swap_rows(GTK_CLIST(estrl->clist), estrl->last_row, estrl->last_row + 1);
		estrl->last_row++;
	}
}

static void estrl_add_clicked_lcb(GtkWidget * widget, Testrl *estrl) {

#ifdef __GNUC__
	gchar *tmplistentry[(estrl->num_columns ? estrl->num_columns  : 1)];
#else
	gchar *tmplistentry[65535];
#endif
	guint i;

	for (i = 0; i < (estrl->num_columns ? estrl->num_columns  : 1); i++) {
		tmplistentry[i] = gtk_entry_get_text(GTK_ENTRY(estrl->ins_upd_entry[i]));
	}		
	gtk_clist_append(GTK_CLIST(estrl->clist), tmplistentry);
}

static void estrl_update_clicked_lcb(GtkWidget * widget, Testrl *estrl) {
	guint i;

	for (i = 0; i < (estrl->num_columns ? estrl->num_columns  : 1); i++) {
		gtk_clist_set_text(GTK_CLIST(estrl->clist)
					   , estrl->last_row, i, gtk_entry_get_text(GTK_ENTRY(estrl->ins_upd_entry[i])));
	}
}

static void estrl_delete_clicked_lcb(GtkWidget * widget, Testrl *estrl) {
	gtk_clist_remove(GTK_CLIST(estrl->clist), estrl->last_row);
}

static void estrl_sort_clicked_lcb(GtkWidget * widget, Testrl *estrl) {
	gtk_clist_set_auto_sort(GTK_CLIST(estrl->clist), 1);
}

void estrl_dialog(GList **which_list, gchar *title, gint what_list
				, gint column_num, gchar **column_titles, void *post_dialog_func) {
	Testrl *estrl;
	GList *tmplist;
	GtkWidget *but_var=NULL, *hbox, *scrolwin, *vbox2, *vbox;
	GtkWidget *table2, *but;
	gint i;
	gchar *tmplistentry[1];


	estrl = g_malloc(sizeof(Testrl));
	estrl->num_columns = column_num;
	estrl->the_list = which_list;
	estrl->function = post_dialog_func;
	estrl->win = window_full(title, GTK_WIN_POS_MOUSE, GTK_WINDOW_DIALOG, 5, estrl_destroy_lcb, estrl);

	vbox = gtk_vbox_new(FALSE, 1);
	gtk_container_add(GTK_CONTAINER(estrl->win), vbox);
	gtk_widget_realize(estrl->win);

	table2 = gtk_table_new(column_num ? column_num : 1, 3, 0);
	for (i = 0; i < (column_num ? column_num : 1); i++) {
		estrl->ins_upd_entry[i] = gtk_entry_new_with_max_length(950/(column_num ? column_num : 1));
		if (column_titles) {
			gtk_table_attach_defaults(GTK_TABLE(table2), gtk_label_new(column_titles[i]), 0, 1, i, i+1);
		}
		gtk_table_attach_defaults(GTK_TABLE(table2), estrl->ins_upd_entry[i], 1, 2, i, i+1);
	}
	gtk_box_pack_start(GTK_BOX(vbox), table2, FALSE, FALSE, 0);

	switch (what_list) {
	case 1:
		/* files */
		but_var = file_but_new(estrl->ins_upd_entry[0], estrl->win, 1);
		break;
	case 2:
		/* color */
		but_var = color_but_new(estrl->ins_upd_entry[0], estrl->win);
		break;
	case 4:
		/* url */
		but_var = file_but_new(estrl->ins_upd_entry[0], estrl->win, 0);
		break;
	case 7:
		/* external filters and commands */

		break;
	case 8:
		/* syntax highlighting patterns */
		but_var = color_but_new(estrl->ins_upd_entry[0], estrl->win);
		break;
	default:
		/* targets(5), fonts(3) meta_cb (6) */
		break;
	}
	if (but_var) {
		gtk_table_attach_defaults(GTK_TABLE(table2), but_var, 2, 3, 0, 1);
		GTK_WIDGET_SET_FLAGS(but_var, GTK_CAN_DEFAULT);	
	}

	hbox = gtk_hbox_new(FALSE, 0);
	gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0);
	scrolwin = gtk_scrolled_window_new(NULL, NULL);
	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolwin), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
	gtk_box_pack_start(GTK_BOX(hbox), scrolwin, TRUE, TRUE, 0);
	vbox2 = gtk_vbox_new(FALSE, 0);
	gtk_box_pack_start(GTK_BOX(hbox), vbox2, FALSE, FALSE, 0);

	if (column_num == 0) {
		estrl->clist = gtk_clist_new(1);
	} else {
		if (column_titles != NULL) {
			estrl->clist = gtk_clist_new_with_titles(column_num, column_titles);
		} else {
			estrl->clist = gtk_clist_new(column_num);
		}
	}

	gtk_signal_connect(GTK_OBJECT(estrl->clist), "select_row", GTK_SIGNAL_FUNC(estrl_select_row_lcb), estrl);
	gtk_signal_connect(GTK_OBJECT(estrl->clist), "unselect_row", GTK_SIGNAL_FUNC(estrl_unselect_row_lcb), estrl);
	gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolwin), estrl->clist);
	gtk_clist_set_reorderable(GTK_CLIST(estrl->clist), TRUE);
	gtk_clist_freeze(GTK_CLIST(estrl->clist));

	tmplist = g_list_first(*which_list);
	if (column_num == 0) {
		while (tmplist != NULL) {
			tmplistentry[0] = (gchar *) tmplist->data;
			gtk_clist_append(GTK_CLIST(estrl->clist), tmplistentry);
			tmplist = g_list_next(tmplist);
		}
	} else {
		while (tmplist != NULL) {
			gtk_clist_append(GTK_CLIST(estrl->clist), (gchar **) tmplist->data);
			tmplist = g_list_next(tmplist);
		}
	}
	gtk_clist_thaw(GTK_CLIST(estrl->clist));

	but = bf_stock_button(_(" Add "), estrl_add_clicked_lcb, estrl);
	gtk_box_pack_start(GTK_BOX(vbox2),but , TRUE, TRUE, 0);
	but = bf_stock_button(_(" Update "), estrl_update_clicked_lcb, estrl);
	gtk_box_pack_start(GTK_BOX(vbox2),but , TRUE, TRUE, 0);
	but = bf_stock_button(_(" Delete "), estrl_delete_clicked_lcb, estrl);
	gtk_box_pack_start(GTK_BOX(vbox2),but , TRUE, TRUE, 0);
	but = bf_stock_button(_(" Up "), estrl_up_clicked_lcb, estrl);
	gtk_box_pack_start(GTK_BOX(vbox2),but , TRUE, TRUE, 0);
	but = bf_stock_button(_(" Down "), estrl_down_clicked_lcb, estrl);
	gtk_box_pack_start(GTK_BOX(vbox2),but , TRUE, TRUE, 0);
	but = bf_stock_button(_(" Sort "), estrl_sort_clicked_lcb, estrl);
	gtk_box_pack_start(GTK_BOX(vbox2),but , TRUE, TRUE, 0);

	hbox = gtk_hbutton_box_new();
	gtk_hbutton_box_set_layout_default(GTK_BUTTONBOX_END);
	gtk_button_box_set_spacing(GTK_BUTTON_BOX(hbox), 1);
	gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
	
	but = bf_stock_ok_button(estrl_ok_clicked_lcb, estrl);
	gtk_box_pack_start(GTK_BOX(hbox), but, TRUE, TRUE, 0);
	gtk_window_set_default(GTK_WINDOW(estrl->win), but);

	but = bf_stock_cancel_button(estrl_cancel_clicked_lcb, estrl);
	gtk_box_pack_start(GTK_BOX(hbox), but, TRUE, TRUE, 0);

	gtk_widget_show_all(estrl->win);
}


/************************************************************************/

gint count_array(gchar **array) {
	gint count=0;
	gchar **tmpchar=array;	
	
	while (*tmpchar != NULL) {
		count++;
		tmpchar++;
	}
	return count;
}

GList *duplicate_stringlist(GList *list, gint dup_data) {
	GList *retlist=NULL;
	if (list) {
		GList *tmplist;
		tmplist = g_list_first(list);
		while (tmplist) {
			if (tmplist->data) {
				gchar *data;
				if (dup_data) {
					data = g_strdup((gchar *)tmplist->data);
				} else {
					data = (gchar *)tmplist->data;
				}
				retlist = g_list_append(retlist, data);
			}
			tmplist = g_list_next(tmplist);
		}
	}
	return retlist;
}

gint free_stringlist(GList * which_list)
{
	GList *tmplist;

	DEBUG_MSG("free_stringlist, started\n");

	tmplist = g_list_first(which_list);
	while (tmplist != NULL) {
		DEBUG_MSG("free_stringlist, tmplist->data(%p)\n", tmplist->data);
		g_free(tmplist->data);
		tmplist = g_list_next(tmplist);
	}
	DEBUG_MSG("free_stringlist, strings free-ed, about to free list itself\n");
	g_list_free(which_list);
	which_list = NULL;
	return 1;
}

gint free_arraylist(GList * which_list)
{
	GList *tmplist;
#ifdef DEBUGGING
	gchar **tmpchar;
#endif
	DEBUG_MSG("free_arraylist, started\n");

	tmplist = g_list_first(which_list);
	while (tmplist != NULL) {

#ifdef DEBUGGING
		DEBUG_MSG("free_arraylist, starting list %p with data %p\n", tmplist, tmplist->data);
		tmpchar = (gchar **)tmplist->data;
		while (*tmpchar) {
			DEBUG_MSG("free_arraylist, freeing %p\n", *tmpchar);
			DEBUG_MSG("free_arraylist, containing %s\n", *tmpchar);
			g_free(*tmpchar);
			tmpchar++;
		}
		DEBUG_MSG("free_arraylist, content freed\n");
		g_free((gchar **)tmplist->data);
		DEBUG_MSG("free_arraylist, array freed\n");
#else
		g_strfreev((gchar **)tmplist->data);
#endif
		tmplist = g_list_next(tmplist);
	}
	g_list_free(which_list);
	which_list = NULL;
	return 1;
}

gchar **duplicate_stringarray(gchar **array) {
	gchar **newchar;
	gint i;

	newchar = g_malloc0((count_array(array)+1)*sizeof(gchar *));
	for (i=0; array[i] != NULL ; i++) {
		newchar[i] = g_strdup(array[i]);
	}
	return newchar;
}

GList *duplicate_arraylist(GList *arraylist) {
	GList *tmplist;
	GList *newlist=NULL;

	gchar **tmpchar;

	tmplist = g_list_first(arraylist);
	while (tmplist != NULL) {
		gchar **newchar;
		tmpchar = (gchar **)tmplist->data;
		newchar = duplicate_stringarray(tmpchar);
		newlist = g_list_append(newlist, newchar);
		tmplist = g_list_next(tmplist);
	}
	return newlist;
}


GList *get_stringlist(gchar * filename, GList * which_list)
{
	char *tempstr, *tmpbuf;
	FILE *fd;

	DEBUG_MSG("get_stringlist, started with filename=%s\n", filename);
	if (filename == NULL) {
		return NULL;
	}
	tmpbuf = g_malloc(STRING_MAX_SIZE);
	if (file_exists_and_readable(filename)) {
		DEBUG_MSG("get_stringlist, opening %s\n", filename);
		fd = fopen(filename, "r");
		if (fd == NULL) {
			return NULL;
		}
		while (fgets(tmpbuf, STRING_MAX_SIZE, fd) != NULL) {
			tmpbuf = trunc_on_char(tmpbuf, '\n');
			tempstr = g_strdup(tmpbuf);
			DEBUG_MSG("get_stringlist, adding string \"%s\" to the list=%p\n", tempstr, which_list);
			which_list = g_list_append(which_list, tempstr);
		}
		fclose(fd);
	}
	g_free(tmpbuf);
	return which_list;
}

gint put_stringlist(gchar * filename, GList * which_list)
{
	char *tmpstr;
	FILE *fd;
	GList *tmplist;

	DEBUG_MSG("put_stringlist, started with filename=%s\n", filename);

	DEBUG_MSG("put_stringlist, opening %s for saving list(%p)\n", filename, which_list);
	fd = fopen(filename, "w");
	if (fd == NULL) {
		return 0;
	}

	tmplist = g_list_first(which_list);
	while (tmplist != NULL) {
		tmpstr = g_strndup((char *) tmplist->data, STRING_MAX_SIZE - 1);
		DEBUG_MSG("put_stringlist, tmplist(%p), adding string(%p)=%s (strlen=%d)the file\n", tmplist, tmpstr, tmpstr, strlen(tmpstr));
		fputs(tmpstr, fd);
		g_free(tmpstr);
		fputs("\n", fd);
		tmplist = g_list_next(tmplist);
	}
	fclose(fd);
	DEBUG_MSG("put_stringlist, finished, filedescriptor closed\n");
	return 1;
}


/* designed for adding strings to colorlist, urllist, fontlist and targetlist */
GList *add_to_stringlist(GList * which_list, gchar * string) {
	if (string && strlen(string) ) {
		gchar *tempstr2;
		gint add;
		GList *tmplist;

		tempstr2 = g_strdup(string);
		g_assert(tempstr2);
		add = 1;
		tmplist = g_list_first(which_list);
		while (tmplist && add) {
			if (strcmp((gchar *) tmplist->data, tempstr2) == 0) {
				add = 0;
				DEBUG_MSG("add_to_stringlist, strings are the same, don't add!!\n");
			}
			tmplist = g_list_next(tmplist);
		}
		if (add) {
			DEBUG_MSG("add_to_stringlist, adding string=%s, listlenght=%d\n", string, g_list_length(which_list));
			which_list = g_list_append(which_list, tempstr2);
		} else {
			DEBUG_MSG("add_to_stringlist, string is already in there, freeing\n");
			g_free(tempstr2);
		}
	}
	return which_list;
}
