/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */

/*
 *  Copyright (C) 2002 Hiroyuki Ikezoe
 *  Copyright (C) 2003 Takuro Ashie
 *
 *  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, 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.
 */

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

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <gtk/gtk.h>

#include "kazehakase.h"
#include "kz-icons.h"
#include "kz-window.h"
#include "kz-actions-tab.h"
#include "kz-xbel.h"
#include "intl.h"
#include "locale.h"
#include "utils.h"
#include "mozilla.h"

#ifdef USE_GTK_2_2
#include "gtk24backports.h"
#endif

KzProfile      *kz_global_profile = NULL;
KzProfile      *kz_session        = NULL;
KzProfile      *kz_proxy          = NULL;
KzRootBookmark *kz_bookmarks      = NULL;
#if 0
Migemo         *migemo            = NULL;
#endif
static gchar *usage =
N_("Usage: kazehakase [OPTION...] [URI...]\n"
"   -a, --action \"Action Name\"              Execute action\n"
"   -h, --help                              Show this help\n"
"   -v, --version                           Show the version\n"
);


/******************************************************************************
 *                                                                            *
 *                                 UI Level                                   *
 *                                                                            *
 ******************************************************************************/
KzUILevel
kz_ui_level (void)
{
	KzUILevel val;
	gchar level[16];

	g_return_val_if_fail(KZ_IS_PROFILE(kz_global_profile),
			     KZ_UI_LEVEL_BEGINNER);

	level[0] = '\0';
	kz_profile_get_value(kz_global_profile,
			     "Global", "ui_level",
			     level, sizeof(level),
			     KZ_PROFILE_VALUE_TYPE_STRING);

	val = kz_ui_level_from_str(level);
	if (!val)
		return KZ_UI_LEVEL_BEGINNER;

	return val;
}


KzUILevel
kz_ui_level_from_str (const gchar *level)
{
	if (!level || !*level)
		return KZ_UI_LEVEL_INVALID;

	if (!strcmp(level, "custom"))
		return KZ_UI_LEVEL_CUSTOM;
	else if (!strcmp(level, "expert"))
		return KZ_UI_LEVEL_EXPERT;
	else if (!strcmp(level, "medium"))
		return KZ_UI_LEVEL_MEDIUM;
	else if (!strcmp(level, "beginner"))
		return KZ_UI_LEVEL_BEGINNER;

	return KZ_UI_LEVEL_INVALID;
}


const gchar *
kz_ui_level_to_str (KzUILevel level)
{
	switch (level)
	{
	case KZ_UI_LEVEL_CUSTOM:
		return "custom";
	case KZ_UI_LEVEL_EXPERT:
		return "expert";
	case KZ_UI_LEVEL_MEDIUM:
		return "medium";
	case KZ_UI_LEVEL_BEGINNER:
		return "beginner";
	default:
		break;
	}

	return NULL;
}


const gchar *
kz_ui_level_to_suffix (KzUILevel level)
{
	switch (level)
	{
	case KZ_UI_LEVEL_CUSTOM:
		return "\0";
	case KZ_UI_LEVEL_EXPERT:
		return "Ex";
	case KZ_UI_LEVEL_MEDIUM:
		return "Med";
	case KZ_UI_LEVEL_BEGINNER:
		return "Beg";
	default:
		break;
	}

	return NULL;
}


/******************************************************************************
 *                                                                            *
 *                       Kazehakase process checker                           *
 *                                                                            *
 ******************************************************************************/
/*
 *  Based on Text maid 2.3.0
 *  copyright (c) 1998-2003 Kazuki IWAMOTO http://www.maid.org/ iwm@maid.org
 */
enum {
	TARGET_STRING
};

static GtkTargetEntry targets[]={
	{"STRING", 0, TARGET_STRING},
};
static GdkAtom  atom_kz0;  /* for checking process  */
static GdkAtom  atom_kz1;  /* for sending arguments */
static gchar   *arg_text = NULL;
static gint     instance = -1;


static void
cb_selection_get(GtkWidget *widget,
		 GtkSelectionData *data,
		 guint info,
		 guint time,
		 GtkWidget *window)
{
	gchar *text = NULL;
	gint length = 0;

	if (data->selection == atom_kz0)
	{
		text = "Kazehakase Selection";
		length = strlen(text);
		gtk_selection_convert(window, atom_kz1,
				      GDK_SELECTION_TYPE_STRING,
				      GDK_CURRENT_TIME);
	}
	else if (data->selection == atom_kz1 && arg_text != NULL)
	{
		text = arg_text;
		arg_text = NULL;
		length = strlen(text);
	}

	if (text != NULL)
	{
		gtk_selection_data_set_text(data, text, length);
		if (data->selection == atom_kz1)
			g_free(text);
	}
}


static void
activate_action(GList *window_list, const gchar *text)
{
	KzWindow *kz;
	KzTabLabel *kztab;
	GtkWidget *widget;
	EggAction *action;
	gchar *action_name;
	gint action_type;
	enum {
		WINDOW_ACTION,
		TAB_ACTION
	};
	gint window_id = 0, tab_id = -1 /* -1 is current tab */;

	if (!strncmp(text, "KzWindowTabPopup", 16))
	{
		gchar *p1, *p2, *p3;
		action_type = TAB_ACTION;
		
		p1 = (gchar *)(text + 17);

		p2 = strchr(p1, ' ');
		if (!p2)
		{
			window_id = 1;
			action_name = g_strdup(p1);
		}
		else
		{
			window_id = atoi(p2 + 1);
			action_name = g_strndup(p1, p2 - p1);
			p3 = strchr(p2 + 1, ' ');
			if (p3)
				tab_id = atoi(p3 + 1);
		}
		tab_id = !tab_id ? -1 : tab_id;
	}
	else /*if (!strncmp(action, "KzWindow", 8))*/
	{
		gchar *p1, *p2;
		action_type = WINDOW_ACTION;

		p1 = strchr(text, '/');
		if (!p1)
			p1 = (gchar*)text;
		else
			p1++;

		p2 = strchr(p1, ' ');
		if (!p2)
		{
			window_id = 1;
			action_name = g_strdup(p1);
		}
		else
		{
			window_id = atoi(p2 + 1);
			action_name = g_strndup(p1, p2 - p1);
		}
	}
	window_id = !window_id ? 1 : window_id;

	kz = g_list_nth_data(window_list, window_id - 1);	
	/* if not exists indicated window, use first one  */
	if (!kz)
		kz = window_list->data;

	/* activate actions */
	switch (action_type)
	{
	 case TAB_ACTION:
		if (tab_id == -1)
			widget = KZ_WINDOW_CURRENT_PAGE(kz);
		else
			widget = KZ_WINDOW_NTH_PAGE(kz, tab_id - 1);
		if (!widget)
			widget = KZ_WINDOW_CURRENT_PAGE(kz);
		if (!widget)
			break;
		kztab = KZ_TAB_LABEL(gtk_notebook_get_tab_label(GTK_NOTEBOOK(kz->notebook)
								, widget));

		action = egg_action_group_get_action(kz->tabpop_actions,
						     action_name);
		if (action)
			kz_actions_tab_activate_action(kztab, action);
		break;
	 case WINDOW_ACTION:
	 default:
		action = egg_action_group_get_action(kz->actions,
						     action_name);
		if (action)
			egg_action_activate(action);
		break;
	}

	g_free(action_name);
}

static void
cb_selection_received(GtkWidget *widget,
		      GtkSelectionData *data,
		      guint time,
		      gpointer user_data)
{
	if (data->selection == atom_kz0)
	{
		instance = MAX(data->length, 0);
	}
	else if (data->selection == atom_kz1 && data->length > 0) 
	{
		GList *list = kz_window_get_window_list();
		KzWindow *kz;
		gchar **argv;
		gint i;

		if (!list || !list->data || !KZ_IS_WINDOW(list->data)) return;
		kz = list->data;
		gdk_window_raise(GTK_WIDGET(kz)->window);

		/* open URL */
		argv = g_strsplit(data->data, "\n", -1);
		for (i = 0; argv[i]; i++)
		{
			if ((!strcmp(argv[i], "--action") ||
			     !strcmp(argv[i], "-a")) &&
			    *argv[i+1] &&
			    argv[i+1])
			{
				activate_action(list, argv[i+1]);
				i++;
				continue;
			}

			gchar *uri = complement_scheme(argv[i]);
			kz_window_open_new_tab(kz, uri);
			g_free(uri);
		}

		g_strfreev(argv);
	}
}


static GtkWidget *
check_kazehakase_process (int argc, char *argv[])
{
	GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
	gint i, length = 0;

	gtk_widget_realize(window);

	atom_kz0 = gdk_atom_intern("Kazehakase InterProcess communication 0",
				   FALSE);
	atom_kz1 = gdk_atom_intern("Kazehakase InterProcess communication 1",
				   FALSE);

	gtk_selection_add_targets(window, atom_kz0, targets, 1);
	gtk_selection_add_targets(window, atom_kz1, targets, 1);
	g_signal_connect (G_OBJECT(window), "selection-get",
			  G_CALLBACK(cb_selection_get), window);
	g_signal_connect (GTK_OBJECT(window), "selection-received",
			  G_CALLBACK(cb_selection_received), window);

	for (i = 1; i < argc; i++)
	{
		gint len;

		len = strlen(argv[i]) * sizeof(gchar);
		arg_text = g_realloc(arg_text,
				     length + len + sizeof(gchar));
		g_memmove(arg_text + length, argv[i], len);
		length += len;
		arg_text[length++] = '\n';
	}
	if (length > 0)
	{
		arg_text[length - 1] = '\0';
		gtk_selection_owner_set(window, atom_kz1, GDK_CURRENT_TIME);
	}
	gtk_selection_convert(window,atom_kz0,
			      GDK_SELECTION_TYPE_STRING,
			      GDK_CURRENT_TIME);
	while (instance < 0)
		while (gtk_events_pending())
			gtk_main_iteration();
	if (instance > 0)
	{
		/* Kazehakase process is already exists */
		while (arg_text != NULL)
			while (gtk_events_pending())
				gtk_main_iteration();
		gtk_widget_destroy(window);
		return NULL;
	}
	g_free(arg_text);
	arg_text = NULL;
	gtk_selection_owner_set(window, atom_kz0, GDK_CURRENT_TIME);

	return window;
}


/******************************************************************************
 *                                                                            *
 *                                  Main                                      *
 *                                                                            *
 ******************************************************************************/
static void
open_app_info (void)
{
	gchar *sysconf_file, *conf_file, *session_file;
	gchar *bookmark_file, *scrap_file;
	gchar *bookmark_bar_file, *sys_bookmark_bar_file;
	gchar *accel_prefs_file;
	gchar *proxy_file, *sysproxy_file;

	/* load prefs */
	sysconf_file = g_strdup(KZ_SYSCONFDIR "/kzrc");
	conf_file = g_strconcat(g_get_home_dir(), "/.kazehakase/kzrc", NULL);
	kz_global_profile = kz_profile_open(conf_file, sysconf_file);

	/* load sessions */
	session_file = g_strconcat(g_get_home_dir(),
				   "/.kazehakase/sessionrc",
				   NULL);
	kz_session = kz_profile_open(session_file, NULL);

	/* load bookmarks */
	bookmark_file         = g_strconcat(g_get_home_dir(),
					    "/.kazehakase/bookmarks.xml",
					    NULL);
        bookmark_bar_file     = g_strconcat(g_get_home_dir(),
					    "/.kazehakase/bookmarkbar.xml",
					    NULL);
	sys_bookmark_bar_file = g_strconcat(KZ_SYSCONFDIR,
					    "/bookmarkbar.xml",
					    NULL);
	scrap_file            = g_strconcat(g_get_home_dir(),
					    "/.kazehakase/scrap.html",
					    NULL);

	kz_bookmarks = kz_root_bookmark_new(bookmark_file, NULL,
					    scrap_file, NULL);
	kz_root_bookmark_add_bookmark_bar_file(kz_bookmarks,
					       bookmark_bar_file,
					       sys_bookmark_bar_file);


	/* Load other prefs... */
	accel_prefs_file = g_strconcat (g_get_home_dir(),
					"/.kazehakase/keyaccelrc",
					NULL);
	gtk_accel_map_load (accel_prefs_file);

	sysproxy_file = g_strdup(KZ_SYSCONFDIR "/proxyrc");
	proxy_file = g_strconcat (g_get_home_dir(), "/.kazehakase/proxyrc", NULL);
	kz_proxy = kz_profile_open(proxy_file, sysproxy_file);

	kz_icons_init();
	mozilla_init();
	
	g_free(sysconf_file);
	g_free(conf_file);
	g_free(session_file);
	g_free(bookmark_file);
	g_free(scrap_file);
	g_free(bookmark_bar_file);
	g_free(sys_bookmark_bar_file);
	g_free(accel_prefs_file);
	g_free(sysproxy_file);
	g_free(proxy_file);
}


static void
close_app_info (void)
{
	gchar *accel_prefs_file;

	accel_prefs_file = g_strconcat (g_get_home_dir(),
					"/.kazehakase/keyaccelrc",
					NULL);

	gtk_accel_map_save(accel_prefs_file);
	g_free(accel_prefs_file);

	mozilla_exit();

	kz_profile_close(kz_global_profile);
	kz_profile_close(kz_session);
	kz_profile_close(kz_proxy);

	kz_root_bookmark_save_all(kz_bookmarks);
	g_object_unref(G_OBJECT(kz_bookmarks));
#if 0	
	if (migemo)
	{
		migemo_exit();
		migemo = NULL;
	}
#endif	
	kz_global_profile = NULL;
	kz_session        = NULL;
	kz_proxy          = NULL;
	kz_bookmarks      = NULL;
}


int
main (int argc, char *argv[])
{
	KzWindow *kz = NULL;
	GtkWidget *dupl_check_server = NULL;
	gchar *uri = NULL;
	gint i;

	/* initialize */
	setlocale(LC_ALL, "");
	bindtextdomain(PACKAGE, LOCALEDIR);
	bind_textdomain_codeset(PACKAGE, "UTF-8");
	textdomain(PACKAGE);

	gtk_init(&argc, &argv);

	for (i = 1; i < argc; i++)	
	{
		if (!strncmp(argv[i], "--version", 9) ||
		    !strncmp(argv[i], "-v", 2))
		{
			g_print("%s %s\n", PACKAGE, VERSION);
			return 0;
		}
		else if (!strncmp(argv[i], "--help", 6)||
			 !strncmp(argv[i], "-h", 2))
		{
			g_print(_(usage));
			return 0;
		}
	}
	
#ifdef USE_GTK_2_2
	gtk24backports_init();
#endif
	/* find kazehakase process */
	dupl_check_server = check_kazehakase_process(argc, argv);
	if (!dupl_check_server)
	{
		/* FIXME! show message */
		return 0;   /* found kazehakase process */
	}

	/* Load preference */
	open_app_info();

	/* create window */	
	if (argc > 1)
		uri = complement_scheme(argv[1]);
	kz = KZ_WINDOW(kz_window_new(uri));
	if (uri)
		g_free(uri);

	for (i = 2; i < argc; i++)
	{
		uri = complement_scheme(argv[i]);
		kz_window_open_new_tab(kz, uri);
		g_free(uri);
	}
	gtk_widget_show(GTK_WIDGET(kz));

	/* event loop */
	gtk_main();

	/* exit */
	gtk_widget_destroy(dupl_check_server);
	dupl_check_server = NULL;

	close_app_info();

	return 0;
}
