%module anthy
%include typemaps.i

%{
#include "include/anthy.h"
%}

%init %{
anthy_init();
%}

%define OUTPUT_TYPEMAP(type, klass)
%typemap(in,numinputs=0) type *OUTPUT(VALUE temp)
{
  temp = rb_funcall(klass, rb_intern("new"), 0);
  Data_Get_Struct(temp, $*ltype, $1);
}

%typemap(argout) type *OUTPUT
{
  if ($result < 0)
    $result = Qnil;
  else
    $result = temp$argnum;
}
%enddef

OUTPUT_TYPEMAP(struct anthy_conv_stat, cConvStat.klass);
OUTPUT_TYPEMAP(struct anthy_segment_stat, cSegmentStat.klass);
OUTPUT_TYPEMAP(struct anthy_prediction_stat, cPredictionStat.klass);

#undef OUTPUT_TYPEMAP

%rename(ConvStat) anthy_conv_stat;
%rename(SegmentStat) anthy_segment_stat;
%rename(PredictionStat) anthy_prediction_stat;

%rename(COMPILED_ENCODING) ANTHY_COMPILED_ENCODING;
%rename(EUC_JP_ENCODING) ANTHY_EUC_JP_ENCODING;
%rename(UTF8_ENCODING) ANTHY_UTF8_ENCODING;

%rename(init) anthy_init;
%rename(quit) anthy_quit;
%rename(conf_override) anthy_conf_override;
%rename(set_personality) anthy_set_personality;

%ignore anthy_create_context;
%ignore anthy_reset_context;
%ignore anthy_release_context;

%ignore anthy_set_string;
%ignore anthy_resize_segment;
%ignore anthy_get_stat;
%ignore anthy_get_segment_stat;
%ignore anthy_get_segment;
%ignore anthy_commit_segment;

%ignore anthy_set_prediction_string;
%ignore anthy_get_prediction_stat;
%ignore anthy_get_prediction;

%ignore anthy_print_context;
%ignore anthy_context_set_encoding;

%{
#define anthy_context_set_string anthy_set_string
#define anthy_context_resize_segment anthy_resize_segment
#define anthy_context_get_stat anthy_get_stat
#define anthy_context_get_segment_stat anthy_get_segment_stat
/* #define anthy_context_get_segment anthy_get_segment */
/* #define anthy_context_commit_segment anthy_commit_segment */
#define anthy_context_print anthy_print_context

#define anthy_context_set_prediction_string anthy_set_prediction_string
#define anthy_context_get_prediction_stat anthy_get_prediction_stat
/* #define anthy_context_get_prediction anthy_get_prediction */
%}

%rename(Context) anthy_context;

%rename(get_version_string) anthy_get_version_string;
/* SWIG says "Segmentation fault" */
/* %alias anthy_get_version_string "version_string"; */
%inline %{
static char *
version_string(void)
{
  return anthy_get_version_string();
}
%}

/* logger */
%ignore anthy_set_logger;

%header %{
static VALUE logger = Qnil;
%}

%init %{
rb_gc_register_address(&logger);
%}

%{
#if 0
} /* for c-mode indentation */
#endif

typedef struct logger_info
{
  VALUE level;
  VALUE message;
} logger_info_t;

static VALUE
invoke_logger(VALUE data)
{
  logger_info_t *info = (logger_info_t *)data;
  return rb_funcall(logger, rb_intern("call"), 2, info->level, info->message);
}

static void
rb_logger(int lv, const char *str)
{
  int state = 0;
  logger_info_t info;

  info.level = INT2NUM(lv);
  info.message = rb_str_new2(str);
  rb_protect(invoke_logger, (VALUE)&info, &state);
  if (state && !NIL_P(ruby_errinfo)) {
    VALUE klass, message, backtrace;
    int i, len;

    klass = rb_funcall(rb_funcall(ruby_errinfo, rb_intern("class"), 0),
                       rb_intern("to_s"), 0);
    message = rb_funcall(ruby_errinfo, rb_intern("message"), 0);
    backtrace = rb_funcall(ruby_errinfo, rb_intern("backtrace"), 0);
    rb_warning("%s: %s\n", StringValueCStr(klass), StringValueCStr(message));

    len = RARRAY(backtrace)->len;
    for (i = 0; i < len; i++) {
      rb_warning("%s\n", StringValueCStr(RARRAY(backtrace)->ptr[i]));
    }
  }
}

#if 0
{ /* for c-mode indentation */
#endif
%}

%inline %{
#if 0
} /* for c-mode indentation */
#endif

static void
set_logger(int level)
{
  if (rb_block_given_p()) {
    logger = Qnil;
    anthy_set_logger(NULL, level);
  } else {
    logger = rb_block_proc();
    anthy_set_logger(rb_logger, level);
  }
}

#if 0
{ /* for c-mode indentation */
#endif
%}

%include include/anthy.h


%freefunc anthy_context "anthy_release_context";

struct anthy_context
{
  %extend
  {
    anthy_context(void)
    {
      return anthy_create_context();
    };

    void reset(void)
    {
      anthy_reset_context(self);
    };

    %alias set_string "string=";
    int set_string(char *);

    void resize_segment(int, int);

    %alias get_stat "stat";
    int get_stat(struct anthy_conv_stat *OUTPUT);

    %alias get_segment_stat "segment_stat";
    int get_segment_stat(int, struct anthy_segment_stat *OUTPUT);

    %alias get_segment "segment";
    VALUE get_segment(int nth_seg, int nth_cand)
    {
      int len;
      char *buffer;
      len = anthy_get_segment(self, nth_seg, nth_cand, NULL, 0);
      buffer = alloca(len + 1);
      len = anthy_get_segment(self, nth_seg, nth_cand, buffer, len + 1);
      if (len < 0) {
        return Qnil;
      } else {
        return rb_str_new2(buffer);
      }
    };

    VALUE commit_segment(int s, int c)
    {
      return (anthy_commit_segment(self, s, c) < 0) ? Qfalse : Qtrue;
    }

    %alias set_prediction_string "prediction_string=";
    int set_prediction_string(const char *);

    %alias get_prediction_stat "prediction_stat";
    int get_prediction_stat(struct anthy_prediction_stat *OUTPUT);

    %alias get_prediction "prediction";
    int get_prediction(int nth_pre)
    {
      int len;
      char *buffer;
      len = anthy_get_prediction(self, nth_pre, NULL, 0);
      buffer = alloca(len + 1);
      len = anthy_get_prediction(self, nth_pre, buffer, len + 1);
      if (len < 0) {
        return Qnil;
      } else {
        return rb_str_new2(buffer);
      }
    };


    void print();

    %alias set_encoding "encoding=";
    void set_encoding(int encoding);
  }
};


syntax highlighted by Code2HTML, v. 0.9.1