/*
 * 文節の境界を検出する。
 *
 * metawordの選択にはビタビアルゴリズムを使う
 *
 * anthy_eval_border() で指定された領域を文節に分割する
 *
 * Funded by IPA未踏ソフトウェア創造事業 2001 10/29
 * Copyright (C) 2000-2003 TABATA Yusuke, UGAWA Tomoharu
 */
#include <stdio.h>
#include <stdlib.h>

#include <anthy/alloc.h>
#include <anthy/splitter.h>
#include "wordborder.h"

static int
border_check(struct meta_word* mw,
	     int from,
	     int border)
{
  if (mw->from < border) {
    /* 先頭の文節の中から始まるmwは文節区切りにぴったりあっていないとダメ */
    if (mw->from == from && mw->from + mw->len == border) {
      return 1;
    } else {
      return 0;
    }
  } else {
    /* 後ろの文節は無条件に使用可能 */
    return 1;
  }
}

/*
 * 再帰的にmetawordが使用可能かチェックする
 */
static void
metaword_constraint_check(struct splitter_context *sc,
			  struct meta_word *mw,
			  int from, 
			  int border)
{
  if (!mw) return;
  if (mw->can_use != unchecked) return;

  switch(anthy_metaword_type_tab[mw->type].check){
  case MW_CHECK_SINGLE:
    mw->can_use = border_check(mw, from, border) ? ok : ng;
    break;
  case MW_CHECK_BORDER:
    {
      struct meta_word* mw1 = mw->mw1;
      struct meta_word* mw2 = mw->mw2;

      if (mw1&&mw2&&mw1->from + mw1->len == border) {
	/* ちょうど境目にマークが入ってる */
	mw->can_use = ng;
	break;
      }
      if (mw1)
	metaword_constraint_check(sc, mw1, from, border);
      if (mw2)
	metaword_constraint_check(sc, mw2, mw2->from, border);
      
      if ((!mw1 || mw1->can_use == ok) && (!mw2 || mw2->can_use == ok)) {
	mw->can_use = ok;
      } else {
	mw->can_use = ng;
      }
    }
    break;
  case MW_CHECK_WRAP:
    metaword_constraint_check(sc, mw->mw1, from, border);
    mw->can_use = mw->mw1->can_use;
    break;
  case MW_CHECK_NUMBER:
    {
      struct meta_word* itr = mw;
      mw->can_use = ok;
      
      /* 個々の文節の一つでも文節区切りをまたがっていれば、この複合語は使えない */
      for (; itr && itr->type == MW_NUMBER; itr = itr->mw2) {
	struct meta_word* mw1 = itr->mw1;
	if (!border_check(mw1, from, border)) {
	  mw->can_use = ng;
	  break;
	}
      }
    }
    break;
  case MW_CHECK_COMPOUND:
    {
      struct meta_word* itr = mw;
      mw->can_use = ok;
      
      /* 個々の文節の一つでも文節区切りをまたがっていれば、この複合語は使えない */
      for (; itr && (itr->type == MW_COMPOUND_HEAD || itr->type == MW_COMPOUND); itr = itr->mw2) {
	struct meta_word* mw1 = itr->mw1;
	if (!border_check(mw1, from, border)) {
	  mw->can_use = ng;
	  break;
	}
      }
    }
    break;
  case MW_CHECK_OCHAIRE:
    {
      struct meta_word* mw1;
      if (border_check(mw, from, border)) {
	for (mw1 = mw; mw1; mw1 = mw1->mw1) {
	  mw1->can_use = ok;
	}
      } else {
	for (mw1 = mw; mw1; mw1 = mw1->mw1) {
	  mw1->can_use = ng;
	}	
      }
    }
    break;
  case MW_CHECK_NONE:
    break;
  default:
    printf("try to check unknown type of metaword (%d).\n", mw->type);
  }
}

/*
 * 全てのmetawordについて使用できるかどうかをチェックする
 */
static void
metaword_constraint_check_all(struct splitter_context *sc,
			      int from, int to,
			      int border)
{
  int i;
  struct word_split_info_cache *info;
  info = sc->word_split_info;

  /* まずuncheckedにする */
  for (i = from; i < to; i ++) {
    struct meta_word *mw;
    for (mw = info->cnode[i].mw;
	 mw; mw = mw->next) {
      mw->can_use = unchecked;
    }
  }

  /* 次に合成されたmetawordについてチェック */
  for (i = from; i < to; i ++) {
    struct meta_word *mw;
    for (mw = info->cnode[i].mw; mw; mw = mw->next) {
      metaword_constraint_check(sc, mw, from, border);
    }
  }
}

/*
 * ここから文節境界をマークする
 */
void
anthy_eval_border(struct splitter_context *sc, int from, int from2, int to)
{
  struct meta_word *mw;
  int nr;

  /* 文節候補のうち使えるもののみ選択 */
  metaword_constraint_check_all(sc, from, to, from2);

  /* fromとfrom2の間をカバーするmeta_wordがあるかどうかを探す。
   * あれば、fromから解析を行い、なければfrom2から解析をする。
   */
  nr = 0;
  for (mw = sc->word_split_info->cnode[from].mw; mw; mw = mw->next) {
    if (mw->can_use == ok) {
      nr ++;
      break;
    }
  }
  if (nr == 0) {
    from = from2;
  }

  /* 文節の境界を設定する */
  anthy_mark_borders(sc, from, to);
}


syntax highlighted by Code2HTML, v. 0.9.1