/*
 * Copyright (C) 2004, 2005 Jean-Yves Lefort
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of Jean-Yves Lefort nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"
#include <string.h>
#include <glib/gi18n-lib.h>
#include <gmodule.h>
#include <talkfilters.h>
#include "translate.h"

#define TAG_FROM_FILTER_NAME(filter_name)	(g_strconcat("en-x-", (filter_name), NULL))
#define FILTER_NAME_FROM_TAG(tag)		((tag) + 5)

#define TRANSLATE_TALKFILTERS_TYPE_SERVICE		(translate_talkfilters_service_get_type())
#define TRANSLATE_TALKFILTERS_SERVICE(obj)		(G_TYPE_CHECK_INSTANCE_CAST((obj), TRANSLATE_TALKFILTERS_TYPE_SERVICE, TranslateTalkfiltersService))
#define TRANSLATE_TALKFILTERS_SERVICE_CLASS(klass)	(G_TYPE_CHECK_CLASS_CAST((klass), TRANSLATE_TALKFILTERS_TYPE_SERVICE, TranslateTalkfiltersServiceClass))
#define TRANSLATE_TALKFILTERS_IS_SERVICE(obj)		(G_TYPE_CHECK_INSTANCE_TYPE((obj), TRANSLATE_TALKFILTERS_TYPE_SERVICE))
#define TRANSLATE_TALKFILTERS_IS_SERVICE_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE((klass), TRANSLATE_TALKFILTERS_TYPE_SERVICE))
#define TRANSLATE_TALKFILTERS_SERVICE_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS((obj), TRANSLATE_TALKFILTERS_TYPE_SERVICE, TranslateTalkfiltersServiceClass))

typedef struct _TranslateTalkfiltersService TranslateTalkfiltersService;
typedef struct _TranslateTalkfiltersServiceClass TranslateTalkfiltersServiceClass;

struct _TranslateTalkfiltersService
{
  TranslateService			parent;
};

struct _TranslateTalkfiltersServiceClass
{
  TranslateServiceClass			parent;
};

static GType translate_talkfilters_service_get_type (void);
static void translate_talkfilters_service_register_type (GType *type);
static void translate_talkfilters_service_class_init (TranslateTalkfiltersServiceClass *class);

static gboolean translate_talkfilters_service_get_pairs (TranslateService *service,
							 GSList **pairs,
							 TranslateProgressFunc progress_func,
							 gpointer user_data,
							 GError **err);
static char *translate_talkfilters_service_translate_text (TranslateService *service,
							   const char *text,
							   const char *from,
							   const char *to,
							   TranslateProgressFunc progress_func,
							   gpointer user_data,
							   GError **err);

static GType
translate_talkfilters_service_get_type (void)
{
  static GType type;
  static GOnce once = G_ONCE_INIT;

  g_once(&once, (GThreadFunc) translate_talkfilters_service_register_type, &type);

  return type;
}

static void
translate_talkfilters_service_register_type (GType *type)
{
  static const GTypeInfo info = {
    sizeof(TranslateTalkfiltersServiceClass),
    NULL,
    NULL,
    (GClassInitFunc) translate_talkfilters_service_class_init,
    NULL,
    NULL,
    sizeof(TranslateTalkfiltersService),
    0,
    NULL
  };
  
  *type = g_type_register_static(TRANSLATE_TYPE_SERVICE,
				 "TranslateTalkfiltersService",
				 &info,
				 0);
}

static void
translate_talkfilters_service_class_init (TranslateTalkfiltersServiceClass *class)
{
  TranslateServiceClass *service_class = TRANSLATE_SERVICE_CLASS(class);
  
  service_class->get_pairs = translate_talkfilters_service_get_pairs;
  service_class->translate_text = translate_talkfilters_service_translate_text;
}

static gboolean
translate_talkfilters_service_get_pairs (TranslateService *service,
					 GSList **pairs,
					 TranslateProgressFunc progress_func,
					 gpointer user_data,
					 GError **err)
{
  int n_filters;
  const gtf_filter_t *f;
  int i;

  *pairs = NULL;

  n_filters = gtf_filter_count();
  for (f = gtf_filter_list(), i = 0; i < n_filters; f++, i++)
    {
      char *to_tag;

      to_tag = TAG_FROM_FILTER_NAME(f->name);
      *pairs = g_slist_append(*pairs, translate_pair_new(TRANSLATE_PAIR_TEXT, "en", to_tag));
      g_free(to_tag);
    }

  return TRUE;
}

static char *
translate_talkfilters_service_translate_text (TranslateService *service,
					      const char *text,
					      const char *from,
					      const char *to,
					      TranslateProgressFunc progress_func,
					      gpointer user_data,
					      GError **err)
{
  const gtf_filter_t *filter;
  char *translated;
  unsigned long len;
  /* the talkfilters documentation states that filters are not reentrant */
  G_LOCK_DEFINE_STATIC(filters);

  filter = gtf_filter_lookup(FILTER_NAME_FROM_TAG(to));
  g_return_val_if_fail(filter != NULL, NULL);

  len = strlen(text) + 1;
  translated = g_new(char, len);

  G_LOCK(filters);
  while (filter->filter(text, translated, len) == 1)
    translated = g_renew(char, translated, len += 1024);
  G_UNLOCK(filters);

  return translated;
}

G_MODULE_EXPORT gboolean
translate_module_init (GError **err)
{
  int n_filters;
  const gtf_filter_t *f;
  int i;
  TranslateService *service;

  /* register languages */
  
  n_filters = gtf_filter_count();
  for (f = gtf_filter_list(), i = 0; i < n_filters; f++, i++)
    {
      char *tag;
      char *name;

      tag = TAG_FROM_FILTER_NAME(f->name);
      name = g_strdup_printf(_("English (%s)"), f->desc);
      translate_add_language(tag, name);
      g_free(tag);
      g_free(name);
    }

  /* add service */

  service = g_object_new(TRANSLATE_TALKFILTERS_TYPE_SERVICE,
			 "name", "talkfilters",
			 "nick", "GNU Talk Filters",
			 NULL);
  translate_add_service(service);
  g_object_unref(service);

  return TRUE;
}
