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

/*
 *  Copyright (C) 2004 Hiroyuki Ikezoe
 *  Copyright (C) 2004 Hidetaka Iwai
 *
 *  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.
 */

#include "kz-migemo.h"
#if USE_MIGEMO

struct _KzMigemo
{
	GPid pid;
	
	gint input;
	gint output;
	gint error;
};

#include "kazehakase.h"
#include "glib-utils.h"

#define MIGEMO_MAX_LENGTH 64
#define MIGEMO_DEFAULT_COMMAND "migemo -t perl -d /usr/share/migemo/migemo-dict"

/* PCRE causes segfault if a big regex is passed. X< */
#define	MIGEMO_MAX_REGEX_LENGTH 4096

KzMigemo *
kz_migemo_new (void)
{
	KzMigemo *migemo;
	migemo = g_new0(KzMigemo, 1);
	return migemo;
}

void
kz_migemo_free (KzMigemo *migemo)
{
	if (migemo)
	{
		if (migemo->pid)
			g_spawn_close_pid(migemo->pid);
		g_free(migemo);
	}
}

static gboolean
kz_migemo_run_command(KzMigemo *migemo)
{
	gboolean ret;
	GSpawnFlags flags;
	gint argc;
	gchar **argv = NULL;
	gchar *migemo_command;

	migemo_command = KZ_CONF_GET_STR("Global", "migemo_command");
	if (!migemo_command)
		migemo_command = g_strdup(MIGEMO_DEFAULT_COMMAND);

	g_shell_parse_argv(migemo_command,
			   &argc,
			   &argv,
			   NULL);

	flags = G_SPAWN_SEARCH_PATH;
	ret = g_spawn_async_with_pipes(NULL,
				       argv,
				       NULL,
				       flags,
				       NULL,
				       NULL,
				       &migemo->pid,
				       &migemo->input,
				       &migemo->output,
				       &migemo->error,
				       NULL);
	g_strfreev(argv);
	g_free(migemo_command);

	return ret;
}

gchar *
kz_migemo_get_regex(KzMigemo *migemo, const gchar *text)
{
	GIOChannel *in;
	GIOChannel *out;
	gchar *write_buf = NULL, *read_buf = NULL;
	gchar *euc_text = NULL;
	gchar *regex;
	gsize bytes;
	GError *e = NULL;

	g_return_val_if_fail(migemo, NULL);
	g_return_val_if_fail(text, NULL);

	if (!migemo->pid && !kz_migemo_run_command(migemo))
		return NULL;

	if (strlen(text) > MIGEMO_MAX_LENGTH)
		return NULL;

	euc_text = g_convert(text, strlen(text),
			     "EUC-JP", "UTF-8",
			     NULL, NULL, &e);
	if (e)
	{
		g_error_free(e);
		return NULL;
	}
	in  = g_io_channel_unix_new(migemo->input);
	out = g_io_channel_unix_new(migemo->output);
	
	g_io_channel_set_encoding(in, NULL, NULL);
	g_io_channel_set_encoding(out, NULL, NULL);
	
	write_buf = g_strconcat (euc_text, "\n", NULL);
	g_free(euc_text);

	g_io_channel_write_chars(in,
				 write_buf,
				 strlen(write_buf),
				 &bytes,
				 NULL);
	g_io_channel_flush(in, NULL);
	g_free(write_buf);
	
	g_io_channel_read_line(out,
			       &read_buf,
			       &bytes,
			       NULL,
			       &e);
	g_io_channel_unref(in);
	g_io_channel_unref(out);

	if (e)
	{
		g_warning("%s", e->message);
		g_error_free(e);
		e = NULL;
	}

	if (!read_buf) return NULL;
	regex = g_convert(read_buf, bytes,
			  "UTF-8", "EUC-JP",
			  NULL, NULL, NULL);
	g_free(read_buf);

	if (regex && strlen(regex) >= MIGEMO_MAX_REGEX_LENGTH)
	{
		g_free(regex);
		regex = g_strdup(text);
	}

	return regex;
}

gchar *
kz_migemo_get_matched_text(KzMigemo *migemo, const gchar *body,
			   const gchar *text, const gboolean last)
{
	gchar *matched_text = NULL;
	gchar *regex_string;
	GRegex *regex;
	GMatchInfo *match_info;
	GError *e = NULL;

	g_return_val_if_fail(migemo, NULL);
	g_return_val_if_fail(body, NULL);
	g_return_val_if_fail(text, NULL);
	g_return_val_if_fail(g_utf8_validate(body, -1, NULL), NULL);

	regex_string = kz_migemo_get_regex(migemo, text);

	if (!regex_string) return NULL;

	regex = g_regex_new(regex_string,
			    G_REGEX_CASELESS |
			    G_REGEX_MULTILINE |
			    G_REGEX_EXTENDED,
			    0, &e);
	g_free(regex_string);

	if (e)
	{
		g_error_free(e);
		return NULL;
	}

	if (g_regex_match(regex, body, 0, &match_info))
	{
		while (g_match_info_next(match_info, NULL))
		{
			if (matched_text)
				g_free(matched_text);
			matched_text = g_match_info_fetch(match_info, 0);
			if (!last) break;
		}
	}

	g_match_info_free(match_info);
	g_regex_unref(regex);
	return matched_text;
}

#endif /* USE_MIGEMO */
