/*
 * 候補の交換のヒストリを管理する。
 *
 * anthy_swap_cand_ent() で学習する
 * anthy_proc_swap_candidate() で学習結果を用いる
 *
 *  「田端が」という候補をトップに出して「田畑が」で確定された場合は
 *  自立語部:「田端」->「田畑」
 *    の二つのエントリを追加する
 *
 */
#include <stdlib.h>

#include <record.h>
#include "segment.h"
/* for OCHAIRE_SCORE */
#include <splitter.h>
#include <sorter.h>

#define MAX_INDEP_PAIR_ENTRY 100

/* 候補の自立語部を学習する */
static void
learn_swap_cand_indep(struct cand_ent *o, struct cand_ent *n)
{
  xstr os, ns;
  int res;
  int o_idx = o->core_elm_index;
  int n_idx = n->core_elm_index;

  /* 自立語部を含む文節しか学習しない */
  if (o_idx < 0 || n_idx < 0) {
    return ;
  }
  if (o->elm[o_idx].str.len != n->elm[n_idx].str.len) {
    return ;
  }
  if (o->elm[o_idx].nth == -1 || n->elm[n_idx].nth == -1) {
    return ;
  }
  res = anthy_get_nth_dic_ent_str(o->elm[o_idx].se, &o->elm[o_idx].str,
				  o->elm[o_idx].nth, &os);
  if (res) {
    return ;
  }
  res = anthy_get_nth_dic_ent_str(n->elm[n_idx].se, &n->elm[n_idx].str,
				  n->elm[n_idx].nth, &ns);
  if (res) {
    free(os.str);
    return ;
  }
  if (anthy_select_section("INDEPPAIR", 1) == 0) {
    if (anthy_select_column(&os, 1) == 0) {
      anthy_set_nth_xstr(0, &ns);
    }
  }
  free(os.str);
  free(ns.str);
}

/*
 * 候補o を出したらn がコミットされたので
 * o -> n をrecordにセットする
 */
void
anthy_swap_cand_ent(struct cand_ent *o, struct cand_ent *n)
{
  if (o == n) {
    /* 同じ候補 */
    return ;
  }
  if (n->flag & CEF_USEDICT) {
    /* 用例辞書から出てきた候補 */
    return ;
  }
  /* 自立語部 */
  learn_swap_cand_indep(o, n);
}


/*
 * 変換時に生成した候補を並べた状態で最優先の候補を決める
 * ループの除去なども行う
 */
static xstr *
prepare_swap_candidate(xstr *target)
{
  xstr *xs, *n;
  if (anthy_select_column(target, 0) == -1) {
    return NULL;
  }
  xs = anthy_get_nth_xstr(0);
  if (!xs) {
    return NULL;
  }
  /* 第一候補 -> xs となるのを発見 */
  anthy_mark_column_used();
  if (anthy_select_column(xs, 0) != 0){
    /* xs -> ⊥ */
    return xs;
  }
  /* xs -> n */
  n = anthy_get_nth_xstr(0);
  if (!n) {
    return NULL;
  }

  if (!anthy_xstrcmp(target, n)) {
    /* 第一候補 -> xs -> n で n = 第一候補のループ */
    anthy_select_column(target, 0);
    anthy_release_column();
    anthy_select_column(xs, 0);
    anthy_release_column();
    /* 第一候補 -> xs を消して、交換の必要は無し */
    return NULL;
  }
  /* 第一候補 -> xs -> n で n != 第一候補なので
   * 第一候補 -> nを設定
   */
  if (anthy_select_column(target, 0) == 0){
    anthy_set_nth_xstr(0, n);
  }
  return n;
}

/*
 * 自立語のみ
 */
static void
proc_swap_candidate_indep(struct seg_ent *se)
{
  xstr *xs;
  xstr key;
  int i;
  int core_idx = se->cands[0]->core_elm_index;
  int res;
  struct cand_elm *core_elm;

  if (core_idx < 0) {
    return ;
  }

  core_elm = &se->cands[0]->elm[core_idx];
  if (core_elm->nth < 0) {
    return ;
  }

  res = anthy_get_nth_dic_ent_str(core_elm->se,
				  &core_elm->str,
				  core_elm->nth,
				  &key);
  if (res) {
    return ;
  }
  anthy_select_section("INDEPPAIR", 1);

  xs = prepare_swap_candidate(&key);
  free(key.str);
  if (!xs) {
    return ;
  }

  /* 第一候補 -> xs なので xsの候補を探す */
  for (i = 1; i < se->nr_cands; i++) {
    if (se->cands[i]->nr_words == se->cands[0]->nr_words &&
	se->cands[i]->core_elm_index == se->cands[0]->core_elm_index) {
      xstr cand;
      res = anthy_get_nth_dic_ent_str(se->cands[i]->elm[core_idx].se,
				      &se->cands[i]->elm[core_idx].str,
				      se->cands[i]->elm[core_idx].nth,
				      &cand);
      if (res == 0 &&
	  !anthy_xstrcmp(&cand, xs)) {
	free(cand.str);
	/* みつけたのでその候補のスコアをアップ */
	se->cands[i]->score = se->cands[0]->score + 1;
	return ;
      }
      free(cand.str);
    }
  }
}

/*
 * 変換時に生成した候補を並べた状態で最優先の候補を決める
 */
void
anthy_proc_swap_candidate(struct seg_ent *seg)
{

  if (seg->cands[0]->score >= OCHAIRE_SCORE) {
    /* cands[0] は特別な点数を持っている */
    return ;
  }
  if (seg->cands[0]->flag & CEF_USEDICT) {
    return ;
  }
  /**/
  proc_swap_candidate_indep(seg);
}

/* 候補交換の古いエントリを消す */
void
anthy_cand_swap_ageup(void)
{
  if (anthy_select_section("INDEPPAIR", 0) == 0) {
    anthy_truncate_section(MAX_INDEP_PAIR_ENTRY);
  }
}
