/*  Copyright (C) 2001-2002  Kenichi Suto
 *
 *  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 "defs.h"
#include "global.h"
#include "eb.h"
#include "xml.h"
#include "misc.h"
#include "dictbar.h"
#include "dialog.h"

static GtkWidget *group_dlg;
static GtkWidget *subbook_dlg;
//static GtkWidget *clist_group;
static GtkWidget *ctree_group;
static GtkWidget *clist_dict;
static GtkWidget *entry_group_name;
static GtkWidget *entry_book_name;
static GtkWidget *entry_directory_name;
static GtkWidget *label_book_path;
static GtkWidget *label_subbook_no;
static GtkWidget *entry_appendix_path;
static GtkWidget *spin_appendix_subbook_no;
static GtkWidget *spin_search_depth;
static GtkCTreeNode *current_node=NULL;

GList *group_list = NULL;
GList *book_list = NULL;

void print_dict_group();
void save_dictgroup();

extern GtkWidget *combo_method;


extern void remove_space(gchar *f);

static void recursive_func(GtkCTree *ctree, GtkCTreeNode *node, gpointer data)
{
	gchar *text;
	gboolean is_leaf;
	GList *item;
	DICT_GROUP *group;
	DICT_MEMBER *member;

	gtk_ctree_get_node_info(ctree, node, &text, NULL, NULL, NULL, NULL, NULL, &is_leaf, NULL);

	if(is_leaf == TRUE){
		// $B%0%k!<%W$G$J$$>l9g(B
		member = gtk_ctree_node_get_row_data(GTK_CTREE(ctree_group), node);
		item = g_list_last(group_list);
		group = (DICT_GROUP *)(item->data);
		group->member = g_list_append(group->member, member);
	} else {
		// $B%0%k!<%W$N>l9g(B
		group = gtk_ctree_node_get_row_data(GTK_CTREE(ctree_group), node);
		g_list_free(group->member);
		group->member = NULL;
		group_list = g_list_append(group_list, group);
		
	}

}

void ok_group(GtkWidget *widget,gpointer *data){
	GList *method_list=NULL;
	int i;

	g_list_free(group_list);
	group_list = NULL;

	gtk_ctree_pre_recursive(GTK_CTREE(ctree_group),  NULL, recursive_func, NULL);

	gtk_grab_remove(group_dlg);
	gtk_widget_destroy(GTK_WIDGET(group_dlg));

	save_dictgroup();
	check_search_method();

	for(i=0 ; search_method[i].name != 0 ; i ++){
		search_method[i].name = _(search_method[i].name);
	}


	for(i=0 ; ; i ++){
		if(search_method[i].name == NULL)
			break;
		method_list = g_list_append(method_list, search_method[i].name);
	}
	if(i != 0)
		gtk_combo_set_popdown_strings( GTK_COMBO(combo_method), method_list) ;

	create_dict_bar();


}

static void delete_event( GtkWidget *widget,
		   GdkEvent  *event,
		   gpointer   data )
{
	ok_group(NULL, NULL);
}

void ok_subbook(GtkWidget *widget,gpointer *data){
	gtk_grab_remove(subbook_dlg);
	gtk_widget_destroy(GTK_WIDGET(subbook_dlg));
}

static void clear_group(GtkCTree *ctree, GtkCTreeNode *list){
	gtk_ctree_remove_node(GTK_CTREE(ctree),list);
}


static void show_group_tree()
{

	DICT_GROUP *group;
	DICT_MEMBER *member;
	char *text[1];
	GtkCTreeNode *node=NULL, *leaf=NULL;
	GList *member_item;
	GList *group_item;

	gtk_clist_freeze(GTK_CLIST(ctree_group));

	// $B$^$:$OA4It%/%j%"$9$k(B

	while(1){
		node = gtk_ctree_node_nth(GTK_CTREE(ctree_group), 0);
		if(node == NULL)
			break;
		gtk_ctree_post_recursive(GTK_CTREE(ctree_group), 
					 node, 
					 (GtkCTreeFunc)clear_group, 
					 NULL);

	}

	group_item = g_list_first(group_list);

	if(group_item == NULL){
//		warning(_("No dictionary defined. Please do the following steps.\n1. Add dictionary group. \n2. Search dictionary from disk. \n3. Add dictionary to group."));
		return;
	}

	while(group_item != NULL){
		group = (DICT_GROUP *)(group_item->data);

		text[0] = group->name;

		node = gtk_ctree_insert_node(GTK_CTREE(ctree_group), 
				      NULL, //parent
				      NULL, //sibling
				      text, //text
				      0,    //spacing
				      NULL, NULL,
				      NULL, NULL,
				      FALSE,//is leaf
				      TRUE);//expanded
		gtk_ctree_node_set_row_data(GTK_CTREE(ctree_group), node, group_item->data);

		leaf = NULL;

		member_item = ((DICT_GROUP *)(group_item->data))->member;
		while(member_item != NULL){
   		        member = (DICT_MEMBER *)(member_item->data);
			text[0] = member->name;
			leaf = gtk_ctree_insert_node(GTK_CTREE(ctree_group), 
					      node, //parent
					      NULL, //sibling
					      text, //text
					      0,    //spacing
					      NULL, NULL,
					      NULL, NULL,
					      TRUE,//is leaf
					      TRUE);//expanded

			gtk_ctree_node_set_row_data(GTK_CTREE(ctree_group), leaf, member_item->data);
			if(member->binfo->available == FALSE){
				gtk_widget_set_sensitive(GTK_WIDGET(leaf), FALSE);
			}
			member_item = g_list_next(member_item);
		}
		group_item = g_list_next(group_item);
	}

	gtk_clist_thaw(GTK_CLIST(ctree_group));	
}


static void add_dict(GtkWidget *widget,gpointer *data)
{
	char *path;
	gchar *subbook_no;
	gchar *name;
	gchar *appendix_path;
	gint  appendix_subbook_no;
	char *text[1];
	BOOK_INFO *binfo=NULL;
	GtkCTreeRow *row;
	GtkCTreeNode *node;

	DICT_MEMBER *member;
	DICT_GROUP *group;
	GList *member_item;


	if(current_node == NULL){
		warning(_("Please select group."));
		return;
	}

	row = GTK_CTREE_ROW(current_node);
	if(row == NULL){
		warning(_("Please select group."));
		return;
	}

	if(row->is_leaf){
		group = gtk_ctree_node_get_row_data(GTK_CTREE(ctree_group), row->parent);		
	} else {
		group = gtk_ctree_node_get_row_data(GTK_CTREE(ctree_group), current_node); 
	}

	name = gtk_entry_get_text(GTK_ENTRY(entry_book_name));
	gtk_label_get(GTK_LABEL(label_book_path), &path);
	gtk_label_get(GTK_LABEL(label_subbook_no), &subbook_no);
	appendix_path = gtk_entry_get_text(GTK_ENTRY(entry_appendix_path));
	if(strlen(appendix_path) == 0){
		appendix_path = NULL;
	}
	appendix_subbook_no = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spin_appendix_subbook_no));

	member_item = g_list_first(group->member);
	while(member_item){
		member = (DICT_MEMBER *)(member_item->data);
		if((strcmp(member->binfo->book_path, path) == 0 ) &&
		   (member->binfo->subbook_no == atoi(subbook_no)))
		{
			warning(_("Already in member."));
			return;
		}
		member_item = g_list_next(member_item);
	}

	member = (DICT_MEMBER *)calloc(sizeof(DICT_MEMBER), 1);
	binfo = load_book(path, atoi(subbook_no),
			  appendix_path, appendix_subbook_no);
	member->binfo = binfo;
	member->name = strdup(name);
	member->active = TRUE;
	text[0] = member->name;

	if(row->is_leaf){
		node = gtk_ctree_insert_node(GTK_CTREE(ctree_group), 
				      row->parent, //parent
				      NULL, //sibling
				      text, //text
				      0,    //spacing
				      NULL, NULL,
				      NULL, NULL,
				      TRUE,//is leaf
				      TRUE);//expanded


	} else {
		node = gtk_ctree_insert_node(GTK_CTREE(ctree_group), 
				      current_node, //parent
				      NULL, //sibling
				      text, //text
				      0,    //spacing
				      NULL, NULL,
				      NULL, NULL,
				      TRUE,//is leaf
				      TRUE);//expanded
	}

	gtk_ctree_expand(GTK_CTREE(ctree_group), (GTK_CTREE_ROW(node))->parent);

	gtk_ctree_node_set_row_data(GTK_CTREE(ctree_group), node, member);

}


static void change_dict(GtkWidget *widget, gpointer *data)
{

	GtkCTreeRow *row;
	DICT_MEMBER *member;
	gchar *path;
	gchar *subbook_no;
	gchar *appendix_path;
	gint  appendix_subbook_no;

	BOOK_INFO *binfo;

	if(current_node == NULL){
		warning(_("Please select dictionary."));
		return;
	}

	row = GTK_CTREE_ROW(current_node);
	g_assert(row != NULL);

	if(row->is_leaf){
		member = gtk_ctree_node_get_row_data(GTK_CTREE(ctree_group), current_node);
		free(member->name);

		gtk_label_get(GTK_LABEL(label_book_path), &path);
		gtk_label_get(GTK_LABEL(label_subbook_no), &subbook_no);
		appendix_path = gtk_entry_get_text(GTK_ENTRY(entry_appendix_path));
		if(strlen(appendix_path) == 0){
			appendix_path = NULL;
		}
		appendix_subbook_no = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spin_appendix_subbook_no));
		binfo = load_book(path, atoi(subbook_no),
				  appendix_path, appendix_subbook_no);
		member->binfo = binfo;
		member->name = strdup(gtk_entry_get_text(GTK_ENTRY(entry_book_name)));

		gtk_ctree_node_set_text(GTK_CTREE(ctree_group), current_node, 0, member->name);

	}

	//print_dict_group();
}






static void up_item(GtkWidget *widget,gpointer *data)
{
	GtkCTreeRow *row;
	GtkCTreeNode *previous;
	GtkCTreeNode *parent;

	if(current_node == NULL){
		warning(_("Please select dictionary."));
		return;
	}

	row = GTK_CTREE_ROW(current_node);
	g_assert(row != NULL);

	if(row->is_leaf){
		parent = row->parent;
		// $B<+J,$HF1$8%l%Y%k$N%N!<%I$rC5$9(B
		previous = GTK_CTREE_NODE_PREV(current_node);
		while(previous){
			if((GTK_CTREE_ROW(previous))->parent == parent)
				break;
			previous = GTK_CTREE_NODE_PREV(previous);
		}

		if(previous != NULL){
			gtk_ctree_move(GTK_CTREE(ctree_group), 
					      current_node,
					      parent,
					      previous);
		}
	} else {
		parent = row->parent;
		// $B<+J,$HF1$8%l%Y%k$N%N!<%I$rC5$9(B
		previous = GTK_CTREE_NODE_PREV(current_node);
		while(previous){
			if((GTK_CTREE_ROW(previous))->parent == parent)
				break;
			previous = GTK_CTREE_NODE_PREV(previous);
		}

		if(previous != NULL){
			gtk_ctree_move(GTK_CTREE(ctree_group), 
					      current_node,
					      parent,
					      previous);
		}
	}

//	print_dict_group();

	return;
}


static void down_item(GtkWidget *widget,gpointer *data)
{
	GtkCTreeRow *row;
	GtkCTreeNode *next;
	GtkCTreeNode *parent;

	if(current_node == NULL){
		warning(_("Please select dictionary."));
		return;
	}

	row = GTK_CTREE_ROW(current_node);
	g_assert(row != NULL);

	if(row->is_leaf){
		parent = row->parent;
		// $B<+J,$HF1$8%l%Y%k$N%N!<%I$rC5$9(B
		next = GTK_CTREE_NODE_NEXT(current_node);
		while(next){
			if((GTK_CTREE_ROW(next))->parent == parent)
				break;
			next = GTK_CTREE_NODE_NEXT(next);
		}

		if(next != NULL){
			gtk_ctree_move(GTK_CTREE(ctree_group), 
					      next,
					      parent,
					      current_node);
		}
	} else {
		parent = row->parent;
		// $B<+J,$HF1$8%l%Y%k$N%N!<%I$rC5$9(B
		next = GTK_CTREE_NODE_NEXT(current_node);
		while(next){
			if((GTK_CTREE_ROW(next))->parent == parent)
				break;
			next = GTK_CTREE_NODE_NEXT(next);
		}

		if(next != NULL){
			gtk_ctree_move(GTK_CTREE(ctree_group), 
					      next,
					      parent,
					      current_node);
		}
	}

//	print_dict_group();

	return;
}



static void remove_item(GtkWidget *widget, gpointer *data)
{
	GtkCTreeRow *row;

	if(current_node == NULL){
		warning(_("Please select dictionary."));
		return;
	}

	row = GTK_CTREE_ROW(current_node);
	g_assert(row != NULL);

	if(row->is_leaf){
		gtk_ctree_remove_node(GTK_CTREE(ctree_group), current_node);
	} else {
		gtk_ctree_remove_node(GTK_CTREE(ctree_group), current_node);
	}


	return;
}


static void add_group(GtkWidget *widget,gpointer *data)
{
	char *name;
	char *text[1];
	DICT_GROUP *group;
	GtkCTreeNode *node;

	name = gtk_entry_get_text(GTK_ENTRY(entry_group_name));
	remove_space(name);
	if(strlen(name) == 0){
	  return;
	}
	text[0] = name;


	group = (DICT_GROUP *)calloc(sizeof(DICT_GROUP), 1);
	group->name = strdup(name);
	group_list = g_list_append(group_list, group);

	node = gtk_ctree_insert_node(GTK_CTREE(ctree_group), 
				     NULL, //parent
				     NULL, //sibling
				     text, //text
				     0,    //spacing
				     NULL, NULL,
				     NULL, NULL,
				     FALSE,//is leaf
				     TRUE);//expanded
	gtk_ctree_node_set_row_data(GTK_CTREE(ctree_group), node, group);

	//print_dict_group();

	gtk_entry_set_text(GTK_ENTRY(entry_group_name), "");
	
}

static void dict_select_row(GtkWidget *widget,
			       gint row, 
			       gint column, 
			       GdkEventButton *bevent,
			       gpointer user_data)
{
	gchar *temp=NULL;
	BOOK_INFO *binfo;
	gchar buff[512];

	gtk_clist_get_text (GTK_CLIST(clist_dict), row, 0, &temp);
	
	if (bevent && temp)
	{

	        binfo = gtk_clist_get_row_data(GTK_CLIST(clist_dict), row);
		gtk_entry_set_text(GTK_ENTRY(entry_book_name), binfo->subbook_title);
		gtk_label_set_text(GTK_LABEL(label_book_path), binfo->book_path);
		sprintf(buff, "%d", binfo->subbook_no);
		gtk_label_set_text(GTK_LABEL(label_subbook_no), buff);

		if(binfo->appendix_path){
			gtk_entry_set_text(GTK_ENTRY(entry_appendix_path), binfo->appendix_path);
			sprintf(buff, "%d", binfo->appendix_subbook_no);
			gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin_appendix_subbook_no), binfo->appendix_subbook_no);
		} else {
			gtk_entry_set_text(GTK_ENTRY(entry_appendix_path), "");
			gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin_appendix_subbook_no), 0);
		}

		switch (bevent->type)
		{
		case GDK_BUTTON_PRESS:
			break;
			
		case GDK_2BUTTON_PRESS:
			add_dict(widget, NULL);
			break;
			
		default:
			break;
		}
	}
  
}


static int enumerate_subbook(char *path)
{
	EB_Book book;
	EB_Error_Code error_code;
	int subcount, i;
	EB_Subbook_Code sublist[EB_MAX_SUBBOOKS];
	char buff[512];
	char *text[1];
	gint row;
	BOOK_INFO *binfo;
	EB_Multi_Search_Code multi_list[EB_MAX_MULTI_SEARCHES];
	int multi_count;


	eb_initialize_book(&book);
	error_code = eb_bind(&book, path);
	if(error_code != EB_SUCCESS){
		//fprint(stderr, "Failed to bind book. Maybe wrong directory.\n");
		return(1);
	}

	error_code = eb_subbook_list(&book, sublist, &subcount);
	if(error_code != EB_SUCCESS){
		//fprint(stderr, "Failed to bind book. Maybe wrong directory.\n");
		return(1);
	}

	for(i=0 ; i<subcount ; i++){
		error_code = eb_subbook_directory2(
			&book,
			sublist[i],
			buff);
		if (error_code != EB_SUCCESS){
			warning(_("Failed to get subbook directory."));
			return(1);
		}

		error_code = eb_subbook_title2(
			&book,
			sublist[i],
			buff);
		if (error_code != EB_SUCCESS){
			warning(_("Failed to get title."));
			return(1);
		}

		error_code = eb_set_subbook(&book, sublist[i]); 
		if (error_code != EB_SUCCESS){
			fprintf(stderr, "failed to set subbook %s, %d: %s\n",
				path, sublist[i],
				eb_error_message(error_code));
			return(1);
		}

		eb_multi_search_list(&book, multi_list, &multi_count);
		if(eb_have_word_search(&book) ||
		   eb_have_endword_search(&book) ||
		   eb_have_exactword_search(&book) ||
		   eb_have_keyword_search(&book) ||
		   (multi_count != 0))
//			(eb_have_menu(binfo->book)
//			eb_have_copyright(binfo->book)
		{

			text[0] = buff;
			binfo = load_book(path, sublist[i], NULL, 0);
			if(binfo == NULL){
				warning(_("Failed to load book."));
				return(1);
			}
			row = gtk_clist_append(GTK_CLIST(clist_dict), text);
			gtk_clist_set_row_data(GTK_CLIST(clist_dict), row, binfo);
		}

	}
	eb_finalize_book(&book);

	return(0);
}

gint max_depth = 0;

static void search_dictionary_recursive(gchar *dirname, gint depth)
{
	DIR *dir;
	struct dirent *ent;
	struct stat sbuf;
	gchar fullpath[512];
	
	if((dir = opendir(dirname)) == NULL){
		fprintf(stderr, "Failed to open directory %s\n", dirname);
		return;
	}

	while((ent = readdir(dir)) != NULL){
		if(ent->d_ino == 0)
			continue;
		if(strcmp(dirname,"/")==0){
			sprintf(fullpath,"/%s",ent->d_name);
		} else {
			sprintf(fullpath,"%s/%s",dirname,ent->d_name);
		}
		stat(fullpath,&sbuf);
		
		switch(sbuf.st_mode &S_IFMT){
		case S_IFREG:
			if((strcasecmp(ent->d_name, "catalog") == 0) ||
			   (strcasecmp(ent->d_name, "catalogs") == 0)){
				enumerate_subbook(dirname);
			}
			break;
		case S_IFDIR:
			if(strcmp(ent->d_name,".") == 0){
				break;
			}
			else if(strcmp(ent->d_name,"..") == 0){
				break;
			} else {
				if(depth < max_depth)
					search_dictionary_recursive(fullpath, depth+1);
			}
			break;
		default:
			break;
		}
	}
	closedir(dir);

}

static void search_disk(GtkWidget *widget,gpointer *data)
{
	gchar *dirname;

	dirname = gtk_entry_get_text(GTK_ENTRY(entry_directory_name));
	dirname = strdup(dirname);
	remove_space(dirname);

	if((strlen(dirname) != 1) &&(dirname[strlen(dirname) - 1] == '/'))
		dirname[strlen(dirname) - 1] = '\0';

	if(strlen(dirname) == 0){
		warning(_("Please enter directory name"));
		return;
	}


	max_depth = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spin_search_depth));

	search_dictionary_recursive(dirname, 0);
	free(dirname);

}



static void ctree_group_select_row(GtkWidget *widget,
			       gint row, 
			       gint column, 
			       GdkEventButton *bevent,
			       gpointer user_data)
{

	DICT_MEMBER *member;
	gchar buff[512];
	GtkCTreeRow *l_row;

	current_node = gtk_ctree_node_nth(GTK_CTREE(ctree_group), row);

	l_row = GTK_CTREE_ROW(current_node);
	g_assert(l_row != NULL);

	if(l_row->is_leaf){
//		gtk_clist_set_reorderable(GTK_CLIST(ctree_group), TRUE);

		member = gtk_ctree_node_get_row_data(GTK_CTREE(ctree_group), current_node);

		gtk_entry_set_text(GTK_ENTRY(entry_book_name), member->name);
		gtk_label_set_text(GTK_LABEL(label_book_path), member->binfo->book_path);
		sprintf(buff, "%d", member->binfo->subbook_no);
		gtk_label_set_text(GTK_LABEL(label_subbook_no), buff);
		if(member->binfo->appendix_path){
			gtk_entry_set_text(GTK_ENTRY(entry_appendix_path), member->binfo->appendix_path);
			gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin_appendix_subbook_no), member->binfo->appendix_subbook_no);
		} else {
			gtk_entry_set_text(GTK_ENTRY(entry_appendix_path), "");
			gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin_appendix_subbook_no), 0);
		}
	} else {
//		gtk_clist_set_reorderable(GTK_CLIST(ctree_group), FALSE);
	}

}



void preference_dictgroup()
{
	GtkWidget *button;
	GtkWidget *hbox;
	GtkWidget *hbox2;
	GtkWidget *vbox;
	GtkWidget *vbox2;
	GtkWidget *label;
	GtkWidget *frame;
	GtkWidget *scroll;
	GtkWidget *table;
	GtkObject *adj;
	GtkObject *adj_appendix;

	GtkAttachOptions xoption, yoption;




	group_dlg = gtk_dialog_new();
	gtk_window_set_position(GTK_WINDOW(group_dlg), GTK_WIN_POS_CENTER_ALWAYS);

	gtk_signal_connect (GTK_OBJECT (group_dlg), "delete_event",
			    GTK_SIGNAL_FUNC (delete_event), NULL);

	gtk_grab_add(group_dlg);
	gtk_widget_realize(group_dlg);

	button = gtk_button_new_with_label(_("Ok"));
	GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
	gtk_box_pack_start (GTK_BOX (GTK_DIALOG (group_dlg)->action_area), button,
			    TRUE, TRUE, 0);

	gtk_signal_connect (GTK_OBJECT (button), "clicked",
			    GTK_SIGNAL_FUNC (ok_group), (gpointer)group_dlg);
	gtk_widget_grab_default (button);


	hbox = gtk_hbox_new(FALSE,0);
	gtk_container_border_width(GTK_CONTAINER(hbox), 5);

	gtk_box_pack_start (GTK_BOX(GTK_DIALOG(group_dlg)->vbox)
			    , hbox,TRUE, TRUE, 0);


	// $B:8H>J,(B

	vbox = gtk_vbox_new(FALSE,0);
	gtk_container_border_width(GTK_CONTAINER(vbox), 5);
	gtk_box_pack_start (GTK_BOX(hbox)
			    , vbox,TRUE, TRUE, 0);

	frame = gtk_frame_new(_("Dictionary group"));
	gtk_box_pack_start (GTK_BOX(vbox), frame,TRUE, TRUE, 0);

	vbox2 = gtk_vbox_new(FALSE,2);
	gtk_container_border_width(GTK_CONTAINER(vbox2), 2);
	gtk_container_add (GTK_CONTAINER (frame), vbox2);


	scroll = gtk_scrolled_window_new (NULL, NULL);
	gtk_box_pack_start (GTK_BOX(vbox2)
			    , scroll,TRUE, TRUE, 0);
	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll),
					GTK_POLICY_AUTOMATIC,
					GTK_POLICY_AUTOMATIC);



	ctree_group = gtk_ctree_new(1, 0);
//	gtk_clist_set_reorderable(GTK_CLIST(ctree_group), TRUE);
	gtk_widget_set_usize(ctree_group,250, 200);
	gtk_container_add (GTK_CONTAINER (scroll), ctree_group);
	gtk_signal_connect (GTK_OBJECT (ctree_group), "select_row",
			    (GtkSignalFunc) ctree_group_select_row, NULL);


	show_group_tree();

	hbox2 = gtk_hbox_new(FALSE, 0);
	gtk_box_pack_start (GTK_BOX(vbox2)
			    , hbox2,FALSE, FALSE, 0);

	label = gtk_label_new(_("Group name"));
	gtk_box_pack_start (GTK_BOX(hbox2)
			    , label,FALSE, FALSE, 2);

	entry_group_name = gtk_entry_new();
	gtk_box_pack_start (GTK_BOX(hbox2)
			    , entry_group_name,TRUE, TRUE, 5);
	gtk_signal_connect (GTK_OBJECT (entry_group_name), "activate",
			    GTK_SIGNAL_FUNC (add_group), (gpointer)NULL);

	button = gtk_button_new_with_label(_("Add"));
	gtk_box_pack_start (GTK_BOX(hbox2)
			    , button,FALSE,FALSE, 0);
	gtk_signal_connect (GTK_OBJECT (button), "clicked",
			    GTK_SIGNAL_FUNC (add_group), (gpointer)button);

	hbox2 = gtk_hbox_new(FALSE,5);
	gtk_box_pack_start (GTK_BOX(vbox2)
			    , hbox2,FALSE, FALSE, 0);

	button = gtk_button_new_with_label(_("Remove"));
	gtk_box_pack_start (GTK_BOX(hbox2)
			    , button,FALSE,FALSE, 0);
	gtk_signal_connect (GTK_OBJECT (button), "clicked",
			    GTK_SIGNAL_FUNC (remove_item), (gpointer)button);

	button = gtk_button_new_with_label(_("Up"));
	gtk_box_pack_start (GTK_BOX(hbox2)
			    , button,FALSE,FALSE, 0);
	gtk_signal_connect (GTK_OBJECT (button), "clicked",
			    GTK_SIGNAL_FUNC (up_item), (gpointer)button);

	button = gtk_button_new_with_label(_("Down"));
	gtk_box_pack_start (GTK_BOX(hbox2)
			    , button,FALSE,FALSE, 0);
	gtk_signal_connect (GTK_OBJECT (button), "clicked",
			    GTK_SIGNAL_FUNC (down_item), (gpointer)button);



	// $B1&H>J,(B

	vbox = gtk_vbox_new(FALSE,0);
	gtk_box_pack_start (GTK_BOX(hbox)
			    , vbox, TRUE, TRUE, 0);

	vbox = gtk_vbox_new(FALSE,0);
	gtk_container_border_width(GTK_CONTAINER(vbox), 5);
	gtk_box_pack_start (GTK_BOX(hbox)
			    , vbox, TRUE, TRUE, 0);

	frame = gtk_frame_new(_("Available dictionaries"));
	gtk_box_pack_start (GTK_BOX(vbox), frame,TRUE, TRUE, 0);

	vbox2 = gtk_vbox_new(FALSE,0);
	gtk_container_border_width(GTK_CONTAINER(vbox2), 2);
	gtk_container_add(GTK_CONTAINER(frame), vbox2);


	scroll = gtk_scrolled_window_new (NULL, NULL);
	gtk_box_pack_start (GTK_BOX(vbox2)
			    , scroll,TRUE, TRUE, 2);
	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll),
					GTK_POLICY_AUTOMATIC,
					GTK_POLICY_AUTOMATIC);

	clist_dict = gtk_clist_new(1);
	gtk_widget_set_usize(clist_dict,250,200);
	gtk_signal_connect (GTK_OBJECT (clist_dict), "select_row",
			    (GtkSignalFunc) dict_select_row, NULL);
	gtk_container_add (GTK_CONTAINER (scroll), clist_dict);


	hbox2 = gtk_hbox_new(FALSE,5);
	gtk_box_pack_start (GTK_BOX(vbox2)
			    , hbox2,FALSE, FALSE, 0);

	label = gtk_label_new(_("Directory"));
	gtk_box_pack_start (GTK_BOX(hbox2)
			    , label,FALSE, FALSE, 2);

	entry_directory_name = gtk_entry_new();
	gtk_box_pack_start (GTK_BOX(hbox2)
			    , entry_directory_name, FALSE, FALSE, 0);
	gtk_signal_connect (GTK_OBJECT (entry_directory_name), "activate",
			    GTK_SIGNAL_FUNC (search_disk), (gpointer)NULL);

	adj = gtk_adjustment_new( 1, //value
				  0, // lower
				  20, //upper
                                  1, // step increment
                                  10,// page_increment,
                                  (gfloat)0.0);
	spin_search_depth = gtk_spin_button_new(GTK_ADJUSTMENT(adj), 1.0, 0);
	gtk_box_pack_start (GTK_BOX(hbox2)
			    , spin_search_depth,FALSE, FALSE, 0);
	gtk_tooltips_set_tip(tooltip, spin_search_depth, 
			     _("Specify search depth. 0 means to search only specified directory."),"Private");



	button = gtk_button_new_with_label(_("Search Disk"));
	gtk_box_pack_start (GTK_BOX(hbox2)
			    , button,FALSE,FALSE, 0);
	gtk_signal_connect (GTK_OBJECT (button), "clicked",
			    GTK_SIGNAL_FUNC (search_disk), (gpointer)button);



	frame = gtk_frame_new(_("Selected dictionary"));
	gtk_box_pack_start (GTK_BOX(vbox)
			    , frame,TRUE,FALSE, 0);

	vbox2 = gtk_vbox_new(FALSE,0);
	gtk_container_add (GTK_CONTAINER (frame), vbox2);




	xoption = GTK_EXPAND | GTK_SHRINK | GTK_FILL;
	yoption = GTK_EXPAND | GTK_SHRINK | GTK_FILL;
//	xoption = 0;
//	yoption = 0;

	table = gtk_table_new(2, 5, FALSE);
	gtk_box_pack_start (GTK_BOX(vbox2)
			    , table, FALSE, FALSE, 0);

	label = gtk_label_new(_("Book name : "));
	gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
	gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, 
			 0, 0, 5, 5);

	entry_book_name = gtk_entry_new();
	gtk_table_attach(GTK_TABLE(table), entry_book_name, 1, 2, 0, 1, 
			 xoption, yoption, 5, 5);
	gtk_signal_connect (GTK_OBJECT (entry_book_name), "activate",
			    GTK_SIGNAL_FUNC (add_dict), (gpointer)NULL);


	label = gtk_label_new(_("Book path : "));
	gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
	gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, 
			 0, 0, 5, 5);

	hbox2 = gtk_hbox_new(FALSE,5);
	gtk_table_attach(GTK_TABLE(table), hbox2, 1, 2, 1, 2, 
			 xoption, yoption, 5, 5);

	label_book_path = gtk_label_new("");
	gtk_box_pack_start(GTK_BOX(hbox2)
			    , label_book_path,FALSE, FALSE, 0);

	gtk_label_set_justify(GTK_LABEL(label_book_path), GTK_JUSTIFY_LEFT);


	label = gtk_label_new(_("Subbook no. : "));
	gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
	gtk_table_attach(GTK_TABLE(table), label, 0, 1, 2, 3, 
			 0, 0, 5, 5);

	hbox2 = gtk_hbox_new(FALSE,5);
	gtk_table_attach(GTK_TABLE(table), hbox2, 1, 2, 2, 3, 
			 xoption, yoption, 5, 5);

	label_subbook_no = gtk_label_new("");
	gtk_box_pack_start (GTK_BOX(hbox2)
			    , label_subbook_no,FALSE, FALSE, 0);

	label = gtk_label_new(_("Appendix path : "));
	gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
	gtk_table_attach(GTK_TABLE(table), label, 0, 1, 3, 4, 
			 0, 0, 5, 5);

	entry_appendix_path = gtk_entry_new();
	gtk_table_attach(GTK_TABLE(table), entry_appendix_path, 1, 2, 3, 4, 
			 xoption, yoption, 5, 5);


	label = gtk_label_new(_("Appendix Subbook no. : "));
	gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
	gtk_table_attach(GTK_TABLE(table), label, 0, 1, 4, 5, 
			 0, 0, 5, 5);

	adj_appendix = gtk_adjustment_new( 0, //value
					   0, // lower
					   20, //upper
					   1, // step increment
					   10,// page_increment,
					   (gfloat)0.0);

	hbox2 = gtk_hbox_new(FALSE,5);
	gtk_table_attach(GTK_TABLE(table), hbox2, 1, 2, 4, 5, 
			 xoption, yoption, 5, 5);

	spin_appendix_subbook_no = gtk_spin_button_new(GTK_ADJUSTMENT(adj_appendix), 1.0, 0);
	gtk_box_pack_start (GTK_BOX(hbox2)
			    , spin_appendix_subbook_no,FALSE, FALSE, 0);

//	entry_appendix_subbook_no = gtk_entry_new();
//	gtk_table_attach(GTK_TABLE(table), entry_appendix_subbook_no, 1, 2, 4, 5, 


	hbox2 = gtk_hbox_new(FALSE,5);
	gtk_container_border_width(GTK_CONTAINER(hbox2), 5);
	gtk_box_pack_start (GTK_BOX(vbox2)
			    , hbox2,FALSE, FALSE, 0);


	button = gtk_button_new_with_label(_("Add"));
	gtk_box_pack_start (GTK_BOX(hbox2)
			    , button,FALSE,FALSE, 0);
	gtk_signal_connect (GTK_OBJECT (button), "clicked",
			    GTK_SIGNAL_FUNC (add_dict), (gpointer)button);


	button = gtk_button_new_with_label(_("Change"));
	gtk_box_pack_start (GTK_BOX(hbox2)
			    , button,FALSE,FALSE, 0);
	gtk_signal_connect (GTK_OBJECT (button), "clicked",
			    GTK_SIGNAL_FUNC (change_dict), (gpointer)button);

	gtk_widget_show_all(group_dlg);

}


void print_dict_group()
{
	GList *group_item;
	GList *member_item;
	DICT_GROUP *group;
	DICT_MEMBER *member;

	g_print("\n*** dictionary group information ***\n");

        group_item = g_list_first(group_list);
	while(group_item != NULL){
		g_print("* GROUP *\n");
		group = (DICT_GROUP *)(group_item->data);
		if(group == NULL) {
			g_print("error : data is NULL\n");
			continue;
		}		
		g_print("name = %s\n", group->name);
		g_print("active = %d\n", group->active);
		member_item = group->member;
		while(member_item != NULL){
			g_print("* MEMBER *\n");
			member = (DICT_MEMBER *)(member_item->data);
			if(member == NULL) {
				g_print("error : data is NULL\n");
				continue;
			}
			printf("title = %s\n", member->name);
			printf("path = %s\n", member->binfo->book_path);
			printf("subbook = %d\n", member->binfo->subbook_no);
			printf("active = %d\n", member->active);
			member_item = g_list_next(member_item);
		}
		printf("\n");

		group_item = g_list_next(group_item);
	}

	g_print("\n*** end ***\n");
}


void load_dictgroup()
{
	char filename[512];

	char *book_name;
	char *book_path;
	char *appendix_path;
	int subbook_no;
	int appendix_subbook_no;
	int active;
	DICT_GROUP *group;
	DICT_MEMBER *member;
	BOOK_INFO *binfo;

	xmlDoc *doc;
	xmlNode *xroot;
	xmlNode *xdictgroup;
	xmlNode *xgroup;
	xmlNode *xdict;
	xmlNode *xnode;

	sprintf(filename, "%s/dictgroup.xml", package_dir);

	if(find_file(filename) == FALSE){
		return;
	}



	doc = xml_parse_file(filename);
	if(doc == NULL){
		fprintf(stderr, "%s not found. Is this the first try ?\n", filename);
		return;
	}


	xroot = doc->root;

	// dictgroup
	xdictgroup = xml_get_child(xroot);
	if(strcmp(xml_get_name(xdictgroup), "dictgroup") != 0){
		goto FAILED;
	}

	xgroup = xml_get_child(xdictgroup);
	while(xgroup){
		if(strcmp(xml_get_name(xgroup), "group") != 0){
			goto FAILED;
		}


		group = (DICT_GROUP *)calloc(sizeof(DICT_GROUP), 1);
		group->name = strdup(xml_get_attr(xgroup, "name"));
		group->active = atoi(xml_get_attr(xgroup, "active"));

		group_list = g_list_append(group_list, group);


		xdict = xml_get_child(xgroup);
		while(xdict){

			// dict
			if(strcmp(xml_get_name(xdict), "dict") != 0){
				goto FAILED;
			}

			xnode = xml_get_child(xdict);

			book_name = NULL;
			book_path = NULL;
			appendix_path = NULL;
			subbook_no = 0;
			appendix_subbook_no = 0;
			active = 0;

			while(xnode){
				gchar *name;
				name = xml_get_name(xnode);
				if(strcmp(name, "name") == 0){
					book_name = xml_get_content(xnode);
				} else if(strcmp(name, "path") == 0){
					book_path = xml_get_content(xnode);
				} else if(strcmp(name, "subbook") == 0){
					subbook_no = atoi(xml_get_content(xnode));
				} else if(strcmp(name, "appendix_path") == 0){
					appendix_path = xml_get_content(xnode);
				} else if(strcmp(name, "appendix_subbook") == 0){
					appendix_subbook_no = atoi(xml_get_content(xnode));
				} else if(strcmp(name, "active") == 0){
					active = atoi(xml_get_content(xnode));
				} else {
					goto FAILED;
				}
				xnode = xml_get_next(xnode);
			}

			if(!book_name && !book_path){
				xdict = xml_get_next(xdict);
				continue;
			}

			binfo = load_book(book_path, subbook_no, appendix_path, appendix_subbook_no);

			if(binfo != NULL){
				member = (DICT_MEMBER *)calloc(sizeof(DICT_MEMBER), 1);
				member->binfo = binfo;
				member->active = active;
				member->name = strdup(book_name);
				
				group->member = g_list_append(group->member, member);
			}

			xdict = xml_get_next(xdict);
		}
		xgroup = xml_get_next(xgroup);
	}

	xml_destroy_document(doc);

	check_search_method();

	//print_dict_group();

	return;

 FAILED:
	fprintf(stderr, "dictgroup.xml corrupt\n");
	xml_destroy_document(doc);
	return;

}


void save_dictgroup()
{
	char filename[512];
	DICT_GROUP *group;
	DICT_MEMBER *member;
	GList *group_item;
	GList *member_item;

	xmlDoc *doc;
	xmlNode *xdictgroup;
	xmlNode *xgroup;
	xmlNode *xdict;

	gchar buff[512];

	sprintf(filename, "%s/dictgroup.xml", package_dir);

	doc = xml_doc_new();
	doc->encoding = strdup("euc-jp");
	doc->version = strdup("1.0");

	xdictgroup = xml_add_child(doc->root, "dictgroup", NULL);

	group_item = g_list_first(group_list);
	while(group_item)
	{
		group = (DICT_GROUP *)(group_item->data);

		xgroup = xml_add_child(xdictgroup, "group", NULL);
		xml_set_attr(xgroup, "name", group->name);
		sprintf(buff, "%d", group->active);	
		xml_set_attr(xgroup, "active", buff);

		member_item = ((DICT_GROUP *)(group_item->data))->member;
		while(member_item != NULL){
			member = (DICT_MEMBER *)(member_item->data);
			xdict = xml_add_child(xgroup, "dict", NULL);

			xml_add_child(xdict, "name", member->name);
			xml_add_child(xdict, "path", member->binfo->book_path);
			sprintf(buff, "%d", member->binfo->subbook_no);
			xml_add_child(xdict, "subbook", buff);
			if(member->binfo->appendix_path){
				xml_add_child(xdict, "appendix_path", member->binfo->appendix_path);
				sprintf(buff, "%d", member->binfo->appendix_subbook_no);
				xml_add_child(xdict, "appendix_subbook", buff);
			}
			sprintf(buff, "%d",member->active);
			xml_add_child(xdict, "active", buff);
			member_item = g_list_next(member_item);
		}
		group_item = g_list_next(group_item);
	}

	xml_save_file(filename, doc);

	xml_destroy_document(doc);
}




syntax highlighted by Code2HTML, v. 0.9.1