
#include <stdlib.h>
#include <string.h>
#include "../include/libstemmer.h"
#include "../runtime/api.h"
#include "modules.h"
#include "rmalloc.h"

struct sb_stemmer {
  struct SN_env *(*create)(void);
  void (*close)(struct SN_env *);
  int (*stem)(struct SN_env *);

  struct SN_env *env;
};

extern const char **sb_stemmer_list(void) {
  return algorithm_names;
}

static stemmer_encoding_t sb_getenc(const char *charenc) {
  struct stemmer_encoding *encoding;
  if (charenc == NULL) return ENC_UTF_8;
  for (encoding = encodings; encoding->name != 0; encoding++) {
    if (strcmp(encoding->name, charenc) == 0) break;
  }
  if (encoding->name == NULL) return ENC_UNKNOWN;
  return encoding->enc;
}

extern struct sb_stemmer *sb_stemmer_new(const char *algorithm, const char *charenc) {
  stemmer_encoding_t enc;
  struct stemmer_modules *module;
  struct sb_stemmer *stemmer;

  enc = sb_getenc(charenc);
  if (enc == ENC_UNKNOWN) return NULL;

  for (module = modules; module->name != 0; module++) {
    if (strcmp(module->name, algorithm) == 0 && module->enc == enc) break;
  }
  if (module->name == NULL) return NULL;

  stemmer = (struct sb_stemmer *)rm_malloc(sizeof(struct sb_stemmer));
  if (stemmer == NULL) return NULL;

  stemmer->create = module->create;
  stemmer->close = module->close;
  stemmer->stem = module->stem;

  stemmer->env = stemmer->create();
  if (stemmer->env == NULL) {
    sb_stemmer_delete(stemmer);
    return NULL;
  }

  return stemmer;
}

void sb_stemmer_delete(struct sb_stemmer *stemmer) {
  if (stemmer == 0) return;
  if (stemmer->close == 0) return;
  stemmer->close(stemmer->env);
  stemmer->close = 0;
  rm_free(stemmer);
}

const sb_symbol *sb_stemmer_stem(struct sb_stemmer *stemmer, const sb_symbol *word, int size) {
  int ret;
  if (SN_set_current(stemmer->env, size, (const symbol *)(word))) {
    stemmer->env->l = 0;
    return NULL;
  }
  ret = stemmer->stem(stemmer->env);
  if (ret < 0) return NULL;
  stemmer->env->p[stemmer->env->l] = 0;
  return (const sb_symbol *)(stemmer->env->p);
}

int sb_stemmer_length(struct sb_stemmer *stemmer) {
  return stemmer->env->l;
}
