/*  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.
*/

#define _GLOBAL
#include <signal.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <pthread.h>

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

#ifdef HAVE_GETOPT_LONG
#include <getopt.h>
#endif

#include "defs.h"
#include "global.h"

#include <gdk/gdkkeysyms.h>
#include <X11/Xlib.h>
#include <gdk/gdkx.h>

#include "eb.h"
#include "dictheading.h"
#include "dicttext.h"
#include "dictgroup.h"
#include "weblist.h"
#include "pixmap.h"
#include "selection.h"
#include "preference.h"
#include "dialog.h"

#define DEFAULT_WINDOW_WIDTH    670
#define DEFAULT_WINDOW_HEIGHT   440


static gboolean style_set=FALSE;

static pthread_t server_tid=(pthread_t)-1;
static guint signal_remote_command = 0;
static gint conn;
static gchar sock_name[512];

extern GtkWidget *dict_scroll;
extern GtkWidget *note_tree;

void exit_program( GtkWidget *widget,
		   gpointer   data )
{

	if(pthread_self() == server_tid)
		pthread_exit(0);

	ebook_end();

	gdk_window_get_root_origin(window->window, &window_x, &window_y);
	window_width = window->allocation.width;
	window_height = window->allocation.height;

	tree_width = note_tree->allocation.width;
	tree_height = note_tree->allocation.height;

	save_preference();

	gtk_main_quit ();

	if(server_tid != (pthread_t)-1)
		pthread_cancel(server_tid);

	close(conn);
	unlink(sock_name);
//	pthread_kill(server_tid, SIGKILL);
	pthread_join(server_tid, NULL);

	exit(0);
}

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

static void sig_handler(int sig){
	gint status;

	//g_print("(%d) signal %d received\n", getpid(), sig);
	switch(sig){
	case SIGCHLD:
		wait(&status);
		if(WEXITSTATUS(status) == 100){
			warning(_("Failed to execute command. Please check setting."));
		}
		break;
	case SIGTERM:
	case SIGINT:
		exit_program(NULL, NULL);
		break;
	default:
		break;
	}
}

static void style_set_event( GtkWidget *widget,
		   GdkEvent  *event,
		   gpointer   data )
{
	style_set = TRUE;
}

static void draw_event( GtkWidget *widget,
		   GdkEvent  *event,
		   gpointer   data )
{
	gint save_row;
	gchar *text=NULL;

	if(style_set == FALSE)
		return;

	save_row = current_row;
	clear_tree(tree_root);
	current_row = save_row;
	show_result_tree();

	if(current_position.page >= 0){
		text = ebook_get_text(current_book_info,
				      current_position.page,
				      current_position.offset);
		show_text(current_book_info, text);
		free(text);
	} else {
		show_about();
	}

	style_set = FALSE;
}

gboolean perform_shortcut(GdkEventKey *event);

static gint window_key_event(GtkWidget *widget, GdkEventKey *event){
//	g_print("window_key_event\n");


	if(perform_shortcut(event) == TRUE){
		gtk_signal_emit_stop_by_name(GTK_OBJECT(window), "key_press_event");
	}

	if(ebook_search_method() != SEARCH_METHOD_MULTI)
		gtk_window_set_focus(GTK_WINDOW(window), word_entry);

	return(FALSE);
}

gint g_argc;
gchar *g_argv[16];

static void remote_command_old( GtkWidget *widget,
		   gpointer   data )
{
	gboolean selection=FALSE;
	gboolean popup=FALSE;
	gboolean iconify=FALSE;
	gboolean raise=FALSE;
	gboolean save_popup;
	gint i;
	gint c;
	gchar word[512];
	Window xwindow;

	int option_index = 0;
	static struct option long_options[] = {
		{"selection", 0, 0, 's'},
		{"popup", 0, 0, 'p'},
		{"raise", 0, 0, 'r'},
		{"iconify", 0, 0, 'i'},
		{0, 0, 0, 0}
	};

/*
	g_print("g_argc = %d\n", g_argc);

	for(i=0;i<g_argc;i++){
		printf("g_argv[%d] = %s\n", i, g_argv[i]);
	}
*/

	optarg = NULL;
	optind = 0;

	while(1){
#ifndef HAVE_GETOPT_LONG
		c = getopt(g_argc, g_argv, "sprig:");
#else 
		c = getopt_long(g_argc, g_argv, "sprig:",
				long_options, &option_index);
#endif
		if(c == -1)
			break;

		switch( c ){
		case 's' :
//			printf("Option %c(%d).\n", c , optind);
			selection = TRUE;
			break;
		case 'p' :
//			printf("Option %c(%d).\n", c , optind);
			popup = TRUE;
			break;
		case 'r' :
//			printf("Option %c(%d).\n", c , optind);
			raise = TRUE;
			break;
		case 'i' :
//			printf("Option %c(%d).\n", c , optind);
			iconify = TRUE;
			break;
		case 'g' :
//			printf("Option %c with arg %s(%d).\n", c, optarg, optind);
			break;
		case '?' :
			break;
		default :
//			printf("Unknown option '%c'\n", optopt);
			break;
		}
		optarg = NULL;
	}

	word[0] = '\0';

	if(optind < g_argc){
		while (optind < g_argc){
			strcat(word, g_argv[optind++]);
			strcat(word, " ");
		}
	}

	if(selection){
		g_print("Searching selection\n");
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button_popup), popup);
		bshow_popup = popup;
		copy_clipboard(NULL);
//		if(!bshow_popup)
			gtk_window_activate_focus(GTK_WINDOW(window));
			gtk_window_activate_default(GTK_WINDOW(window));
		return;
	} else if (iconify) {
		g_print("Iconify\n");
		// GTK2.0
//		gdk_window_iconify(window->window);
		xwindow = GDK_WINDOW_XWINDOW(window->window);
		XIconifyWindow(GDK_DISPLAY (), xwindow, DefaultScreen (GDK_DISPLAY ()));
	}

	if (raise) {
		g_print("Raise\n");
//		gdk_window_hide(window->window);
		gtk_widget_grab_focus(window);
		gdk_window_raise(window->window);
//		gdk_window_show(window->window);
//		gtk_window_activate_focus(GTK_WINDOW(window));
/*
		xwindow = GDK_WINDOW_XWINDOW(window->window);
		XRaiseWindow(GDK_DISPLAY (), xwindow);
*/

	}

	if(strlen(word) != 0){
		g_print("Searching %s\n", word);
		gtk_entry_set_text(GTK_ENTRY(word_entry), word);
		start_search();
	}
}
extern GtkWidget *popup;

static void remote_command( GtkWidget *widget,
		   gpointer   data )
{
	gboolean bpopup=FALSE;
	gint i;
	gchar word[512];

	if(strcmp(g_argv[1], "--search") == 0){
		word[0] = '\0';

		for(i=2; i < g_argc ; i ++){
			strcat(word, g_argv[i]);
			strcat(word, " ");
		}

		if(strlen(word) != 0){
			g_print("Searching %s\n", word);
			gtk_entry_set_text(GTK_ENTRY(word_entry), word);
			start_search();
		}
	} else if((strcmp(g_argv[1], "--selection") == 0) || 
		  (strcmp(g_argv[1], "--popup") == 0)) {

		if(strcmp(g_argv[1], "--popup") == 0)
			bpopup = TRUE;

		g_print("Searching selection\n");
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button_popup), bpopup);
		bshow_popup = bpopup;
		copy_clipboard(NULL);
		return;
	} else if(strcmp(g_argv[1], "--close-popup") == 0){
		if(popup != NULL)
			gtk_signal_emit_by_name(GTK_OBJECT (popup), 
//					"delete_event");
						"close_popup");
			gtk_signal_emit_by_name(GTK_OBJECT (popup), 
						"redraw");
	}
}

static void *server_thread(void *arg)
{
	gint count=0;
	gchar buff[256];
	int len, read_len;
	gchar *p;
	gint i;
	gint state;

	struct sockaddr_un address;
	int sock;
	size_t addrLength;

	signal(SIGCHLD, SIG_DFL);
//	signal(SIGINT, SIG_DFL);
	signal(SIGTERM, SIG_DFL);
	signal(SIGPIPE, SIG_DFL);

	pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &state);
	pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &state);

	if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
		perror("socket");
		_exit(1);
	}

	/* Remove any preexisting socket (or other file) */

	address.sun_family = AF_UNIX;	/* Unix domain socket */
//	strcpy(address.sun_path, "./sample-socket");
	sprintf(sock_name, "%s/.remote-sock", package_dir);
	strcpy(address.sun_path, sock_name);
	unlink(sock_name);

	/* The total length of the address includes the sun_family 
	   element */

#ifndef HAVE_GETOPT_LONG
        addrLength = sizeof(address.sun_len) + sizeof(address.sun_family) + strlen(address.sun_path) + 1;
        address.sun_len = addrLength;
#else
        addrLength = sizeof(address.sun_family) + strlen(address.sun_path);
#endif

	if (bind(sock, (struct sockaddr *) &address, addrLength)){
		perror("bind");
		_exit(1);
	}

	if (listen(sock, 5)){
		perror("listen");
		_exit(1);
	}


	sprintf(buff, "remote command %d", count);

	while ((conn = accept(sock, (struct sockaddr *) &address, 
			      &addrLength)) >= 0) {
		printf("---- getting data\n");
		read_len = read(conn, buff, 1);
		if(read_len != 1){
			g_print("Failed to read socket\n");
			close(conn);
			continue;
		}

		len = (unsigned char)buff[0];
		if(len == 0){
			g_print("Data too short\n");
			close(conn);
			continue;
		}

		g_print("Receiving %d bytes of data...", len);

		read_len = read(conn, buff, len);
		if(read_len != len){
			g_print("%d should be %d\n", read_len , len);
			perror("read");
			g_print("Failed to read socket\n");
			close(conn);
			continue;
		}

		g_print("done\n");
		close(conn);

		p = buff;
		g_argc = *p;
		p ++;


		for(i=0; i<g_argc; i++){
			g_argv[i] = p;
			p = strchr(p, '\0');
			p++;
		}

		gdk_threads_enter();
		gtk_signal_emit (GTK_OBJECT (window), signal_remote_command);
		gdk_threads_leave();
	}

	if (conn < 0) {
		perror("accept");
		_exit(1);
	}

}

void execute_remote_command(gint argc, gchar **argv){
	gchar buff[256];
	gint len;
	gint i;

	g_print("execute_remote_command\n");

	g_argc = argc;

	for(i=0; i<argc ; i++)
		g_argv[i] = argv[i];

	gdk_threads_enter();
	gtk_signal_emit (GTK_OBJECT (window), signal_remote_command);
	gdk_threads_leave();

}

int main( int   argc,
	  char *argv[] )
{
	GtkWidget *dict_window;
	GtkWidget *hidden_window;
	GtkWidget *vbox;
	gint i;
	DIR *dir;
	gchar *home_dir;
	gchar buff[256];
	gint rc;
	pthread_attr_t thread_attr ;


	signal(SIGCHLD, sig_handler);
	signal(SIGINT, sig_handler);
	signal(SIGTERM, sig_handler);
	signal(SIGPIPE, sig_handler);

	
	gtk_set_locale();
	setlocale(LC_ALL,"");
	bindtextdomain(PACKAGE,LOCALEDIR);
	textdomain(PACKAGE);

	g_thread_init(NULL);

	gtk_init (&argc, &argv);
	gdk_imlib_init();


	// 外部変数の初期化
	bauto_lookup = FALSE;
	bbeep_on_nohit = TRUE;
	bignore_locks = TRUE;
	tree_root = NULL;
	entry_focus_in = FALSE;
	search_result = NULL;
	current_position.page = -1;
	current_position.offset = -1;
	current_book_info = NULL;
	line_space = 0.3;
	h_space = 0;
	v_space = 2;
	h_border = 5;
	v_border = 6;
	menu_word_search = FALSE;
	menu_endword_search = FALSE;
	menu_exactword_search = FALSE;
	menu_keyword_search = FALSE;
	menu_menu = FALSE;
	menu_copyright = FALSE;
	menu_multi_search = FALSE;

	max_search = 100;
	max_remember_words = 10;
	dict_label_bytes = 10;
	auto_interval = 1000;
	auto_minchar = 3;
	auto_maxchar = 64;
	bshow_menu_bar = 1;
	bshow_status_bar = 1;
	bshow_dict_bar = 1;
	bshow_tree_tab = 1;
	bending_correction = 1;
	bending_only_nohit = 1;
	bshow_popup = 1;
	bshow_popup_title = 1;
	popup_width = 300;
	popup_height = 200;
	window_x = 0;
	window_y = 0;
	window_width = DEFAULT_WINDOW_WIDTH;
	window_height = DEFAULT_WINDOW_HEIGHT;
	tree_width = 185;
	tree_height = 344;

	mpeg_template = strdup("plaympeg %f");
	wave_template = strdup("playwave %f");
	browser_template = strdup("gnome-moz-remote %f");

	fontset_normal = strdup("-misc-fixed-medium-r-normal-*-14-*-*-*-*-*-*-*");
	fontset_bold = strdup("-misc-fixed-bold-r-normal-*-14-*-*-*-*-*-*-*");
	fontset_italic = strdup("-misc-fixed-medium-i-normal-*-14-*-*-*-*-*-*-*");
	fontset_superscript = strdup("-misc-fixed-medium-r-normal-*-10-*-*-*-*-*-*-*");



	// ディレクトリ名を外部変数にセットしておく
	home_dir = getenv("HOME");

	sprintf(buff, "/.%s", PACKAGE);
	package_dir = calloc(strlen(home_dir)+strlen(buff)+1, 1);
	sprintf(package_dir,"%s%s", home_dir, buff);

	sprintf(buff, "/.%s/tmp", PACKAGE);
	tmp_dir = calloc(strlen(home_dir)+strlen(buff)+1, 1);
	sprintf(tmp_dir,"%s%s", home_dir, buff);
	
	if((dir = opendir(package_dir)) == NULL){
		if(mkdir(package_dir,
			 S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) != 0){
			fprintf(stderr, "Failed to create directory : %s\n", package_dir);
			exit(1);
		}
	} else {
		closedir(dir);
	}

	// テンポラリディレクトリを作成
	if((dir = opendir(tmp_dir)) == NULL){
		if(mkdir(tmp_dir,
			 S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) != 0){
			fprintf(stderr, "Failed to create directory : %s\n", tmp_dir);
			exit(1);
		}
	} else {
		closedir(dir);
		sprintf(buff, "rm -fr %s/*", tmp_dir);
		system(buff);
	}

	ebook_start();
	load_preference();
	load_ending();
	load_ending_ja();
	load_dictgroup();
	load_shortcut();

	alloc_colors();

	tooltip = gtk_tooltips_new();
	//gtk_tooltips_set_colors(tooltip, &colors[COLOR_YELLOW], &colors[COLOR_BLACK]);

#ifdef ENABLE_WEBSEARCH
	load_weblist();
#endif

	signal_remote_command =
		gtk_object_class_user_signal_new (gtk_type_class (GTK_TYPE_WIDGET),
						  "remote_command",
						  GTK_RUN_LAST | GTK_RUN_ACTION,
						  gtk_marshal_NONE__POINTER,
						  GTK_TYPE_NONE, 0);

	gtk_object_class_user_signal_new (gtk_type_class (GTK_TYPE_WIDGET),
					  "close_popup",
					  GTK_RUN_LAST | GTK_RUN_ACTION,
					  gtk_marshal_NONE__POINTER,
					  GTK_TYPE_NONE, 0);

	pthread_attr_init (&thread_attr) ;
	pthread_attr_setstacksize (&thread_attr, 512*1024) ;
	rc = pthread_create(&server_tid, &thread_attr, server_thread, (void *)NULL);
	if(rc != 0){
		perror("pthread_create");
		exit(1);
	}

	pthread_attr_destroy(&thread_attr);
	
//	window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
	window = gtk_widget_new (GTK_TYPE_WINDOW,
				"type", GTK_WINDOW_TOPLEVEL,
				"x", window_x,
				"y", window_y,
				NULL);

	//  style = gtk_widget_get_style(window);
	sprintf(buff, "EBView %s", VERSION);
	gtk_window_set_title (GTK_WINDOW (window), buff);
	gtk_window_set_wmclass(GTK_WINDOW(window), "Main", "EBView");
	gtk_signal_connect (GTK_OBJECT (window), "delete_event",
			    GTK_SIGNAL_FUNC (delete_event), NULL);

	gtk_signal_connect (GTK_OBJECT (window), "style_set",
			    GTK_SIGNAL_FUNC (style_set_event), NULL);

	gtk_signal_connect (GTK_OBJECT (window), "draw",
			    GTK_SIGNAL_FUNC (draw_event), NULL);

	gtk_signal_connect( GTK_OBJECT(window),"key_press_event",
			    (GtkSignalFunc)window_key_event, NULL);

	gtk_signal_connect (GTK_OBJECT (window), "remote_command",
			    GTK_SIGNAL_FUNC (remote_command), NULL);


//	gtk_container_set_border_width (GTK_CONTAINER (window), 5);
	
	gtk_widget_realize(window);

	vbox = gtk_vbox_new(FALSE, 0);
	gtk_container_add (GTK_CONTAINER (window), vbox);


	load_pixmaps();

	load_font();

	// dictionary window

	dict_window = create_dict_window();
	gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(dict_window), TRUE, TRUE, 0);
	
	gtk_widget_show(vbox);
	gtk_widget_set_usize(window, window_width, window_height);
	gtk_window_set_policy(GTK_WINDOW(window),
			      1,  // allow_shrink
			      1,  // allow_grow
			      1); // auto_shrink

	gtk_widget_set_usize(note_tree, tree_width, tree_height);

	gtk_widget_show (window);

	gdk_window_set_icon (window->window, NULL, ebook_pixmap, ebook_mask);

	hidden_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
	hidden_entry = gtk_entry_new();
	
	gtk_signal_connect (GTK_OBJECT(hidden_entry), "selection_received",
			    GTK_SIGNAL_FUNC (selection_received), NULL);
	gtk_container_add (GTK_CONTAINER (hidden_window), hidden_entry);


	show_about();

	gtk_selection_owner_set(window, GDK_SELECTION_PRIMARY,GDK_CURRENT_TIME);

	if(!bshow_menu_bar)
		hide_menu_bar();
	if(!bshow_dict_bar)
		hide_dict_bar();
	if(!bshow_status_bar)
		hide_status_bar();

	if(argc != 1)
		execute_remote_command(argc, argv);

	gdk_threads_enter();
	gtk_main ();
	gdk_threads_leave();
	
	ebook_end();

	_exit(0);

//	return(0);
}



syntax highlighted by Code2HTML, v. 0.9.1