/* Copyright (c) 2000-2003                  */
/*   Yamashita Lab., Ritsumeikan University */
/*   All rights reserved                    */

#include	<stdio.h>
#include	<stdlib.h>
#include	<string.h>
#include	"synthesis.h"
#include	"accent.h"

int TmpMsg(char *,...);
int LogMsg(char *,...);
int ErrMsg(char *,...);
void restart(int);
void print_aphrase_kanji(APHRASE *);
void print_aphrase_yomi(APHRASE *);
void print_morph_yomi(MORPH *);



/* 最初に一度だけ */
void init_aphrase()
{
	ahead = atail = NULL;
}

/* 入力文ごとに */
/* 使っているアクセント句のセルの開放 */
void refresh_aphrase()
{
	APHRASE *aphrase, *next;

	aphrase = ahead;
	while( aphrase )  {
		next = aphrase->next;
		free( aphrase );
		aphrase = next;
	}
	ahead = atail = NULL;
}

/* モーラ mora が特殊拍であれば非０を返す */
int is_TOKUSHUHAKU( MORA *mora )
{
	if( mora == NULL )  return(0);		/* 「」など。*/

	if( strcmp("ン",mora->yomi)==0 )  return(1);
	if( strcmp("ー",mora->yomi)==0 )  return(1);
	if( strcmp("ッ",mora->yomi)==0 )  return(1);
	return(0);
}

/* 形態素 m のアクセント型が平板型か尾高型であれば非０を返す */
int no_nucleus( MORPH *morph )
{
	int 	at, len;

	at = morph->accentType;
	if( at == 0 )  return(1);

	len = morph->nmora;
	if( at == len  )  return(1);
	if( at < len-1 )  return(0);

/* 尾高型かどうかは音節単位で判断する。
   「制限」は 3 型だが、最終音節「ゲン」に核があるため、尾高型とする。
   つまり、at == len-1 で最終モーラが特殊泊であれば尾高型。*/
	if( is_TOKUSHUHAKU(morph->mrtail) )  return(1);

	return(0);
}

/* 品詞情報に基づいて何番目のアクセント結合情報を使うかを返す */
int select_aform_pos( MORPH *morph, int hinshiID )
{
	int i;
	char pre_posID;

	if( morph->n_accent <= 0 )  return(-1);

	/* アクセント句の先頭形態素の品詞 */
	switch( hinshiID )  {
	case H_DOUSHI:
		pre_posID = 'V';	/* 動詞 */
		break;
	case H_KEIYOUSHI:
		pre_posID = 'A';	/* 形容詞 */
		break;
	default:
		pre_posID = 'N';	/* 名詞 */
	}

	for( i=0; i<morph->n_accent; ++i )  {
		if( morph->accent[i].prepos == pre_posID )  return(i);
	}
	for( i=0; i<morph->n_accent; ++i )  {
		if( morph->accent[i].prepos == '*' )  return(i);
	}
	/* マッチする品詞がなければ、1番目のデータを使う */
	return(0);
}

/* アクセント句 a に形態素 morph が後続した時の全体のアクセント型を決める */
int accentKetsugou( MORPH *morph, APHRASE *a )
{
	int 	p1, p2, af1, at1, len1, af2, at2, cm2, cm22, len2, at;

	if( morph->nmora == 0 )  return 0;	/* 」 など */

	/* 先行アクセント句が接頭辞だけからなる時のために */
	/* 結合様式を後続形態素の品詞で決める */
	at1 = a->accentType;
	p1 = select_aform_pos( a->mptail, morph->hinshiID );
	if( p1 < 0 )  {
		af1 = -1;
	} else {
		af1 = a->mptail->accent[p1].form;
	}
	len1 = a->nmora;

	/* 後続形態素の結合様式をアクセント句末の形態素の品詞で決める */
	at2 = morph->accentType;
	p2 = select_aform_pos( morph, a->mphead->hinshiID );
	if( p2 < 0 )  {
		af2 = AF_C4;	/* 平板化型  (cm2, cm22 は不要) */
	} else {
		af2 = morph->accent[p2].form;
		cm2 = morph->accent[p2].ctype;	/* アクセント結合価 */
		if( cm2 < 0 )  cm2 = at2;	/* 未定義であればアクセント型の値を使う */
		cm22 = morph->accent[p2].ctype2;  /* F6, F9 では、結合価が２つある。*/
	}
	len2 = morph->nmora;

/* 一つ前が接頭語の時 */
	if( IS_PRE_KETSUGOU(af1) )  {
		switch( af1 )  {
		case AF_P1:	/* 一体化型 */
			at = ( no_nucleus(morph) ) ? 0 : (len1+at2);
			break;
		case AF_P2:	/* 自立語結合型 */
			at = ( no_nucleus(morph) ) ? (len1+1) : (len1+at2);
			break;
		case AF_P3:	/* 分離型 */
			/* 分離型は独立したアクセント型にする */
			/* ここが実行されることはないはず。 */
			at = at1;
			break;
		case AF_P4:	/* 混合型 */
			at = ( no_nucleus(morph) ) ? (len1+1) : (at1);
			break;
		case AF_P5: /* 動詞／形容詞接続型 */
			at = len1+len2-1;
			/* 後ろから二つ目のモーラが特殊泊なら一つ前へ */
			if( is_TOKUSHUHAKU(morph->mrtail->prev) )  {
				--at;
			}
			break;
		case AF_P6:
			at = 0;
			break;
		case AF_P7:
			at = ( no_nucleus(morph) ) ? 0 : (at1);
			break;
		case AF_P8:
			at = ( no_nucleus(morph) ) ? (len1+1) : 0;
			break;
		case AF_P9:
			at = ( no_nucleus(morph) ) ? (len1+1) : (at1);
			break;
		case AF_P10:
			at = ( no_nucleus(morph) ) ? (len1+1) : (at1);
			break;
		case AF_P11:
			at = ( no_nucleus(morph) ) ? (len1) : (len1+at2);
			break;
		case AF_P12:
			at = ( no_nucleus(morph) ) ? (len1) : (at1);
			break;
		case AF_P13:
			at = at1;
			break;
		case AF_P14:
			at = ( no_nucleus(morph) ) ? (at1) : (len1 + at2);
			break;
		case AF_P15:
			at = ( no_nucleus(morph) ) ? (at1) : 1;
			break;
		default: /* 頻度が多いので P2 をデフォールトに */
			/* ここが実行されることはないはずであるが、念のため。 */
			at = ( no_nucleus(morph) ) ? (len1+1) : (len1+at2);
			break;
		}
#ifdef KETSUGO_DEBUG
		TmpMsg( "%s %d 接頭 %o\n", morph->kanji, at, af2 );
#endif
			
/* 付属語が後続する時 */
	} else if( IS_FUZOKU_KETSUGOU(af2) )  {
		switch( af2 )  {
		case AF_F1:	/* 従属型 */
			at = at1;
			break;
		case AF_F2: /* 不完全支配型 */
			at = ( at1 == 0 ) ? (len1+cm2) : at1;
			break;
		case AF_F3:	/* 融合型 */
			at = ( at1 == 0 ) ? at1 : (len1+cm2);
			break;
		case AF_F4:	/* 支配型1 */
			at = (len1+cm2);
			break;
		case AF_F5:	/* 支配型2 */
			at = 0;
			break;
		case AF_F6:
			if( cm22 < 0 )  {
				ErrMsg( "'%s' is F6 type. But it does not have two accent conjugation metrics\n", morph->kanji );
				cm22 = cm2;
			}
			at = ( at1 == 0 ) ? (len1+cm2) : (len1+cm22);
			break;
		case AF_F7:
			at = ( at1 == 0 ) ? 0 : (len1+cm2);
			break;
		case AF_F8:
			at = (len1+cm2);
			break;
		case AF_F9:
			if( cm22 < 0 )  {
				ErrMsg( "'%s' is F6 type. But it does not have two accent conjugation metrics\n", morph->kanji );
				cm22 = cm2;
			}
			at = ( at1 == 0 ) ? (len1+cm2) : (len1+cm22);
			break;
		default: /* 頻度が多いので F1 をデフォールトに */
			/* ここが実行されることはないはずであるが、念のため。 */
			at = at1;
			break;
		}
#ifdef KETSUGO_DEBUG
		TmpMsg( "%s %d 付属 %o\n", morph->kanji, at, af2 );
#endif

/* 接尾語や短い(２モーラ以下の)語が後続する時、名詞連鎖の時 */
	} else if( IS_POST_KETSUGOU(af2) )  {
		switch( af2 )  {
		case AF_C1:	/* 自立語結合 保存型 */
			at = len1+at2;
			break;
		case AF_C2:	/* 自立語結合 生起型 */
			at = len1+1;
			break;
		case AF_C3:	/* 接辞結合 標準型 */
			/* アクセント句の最終モーラを調べる */
			/* 特殊拍なら一つ前に */
			at = (is_TOKUSHUHAKU(a->mptail->mrtail)) ? (len1-1) : len1;
			break;
		case AF_C4:	/* 接辞結合 平板化型 */
			at = 0;
			break;
		case AF_C5:
			at = at1;
			break;
		case AF_C6:
			at = 1;
			break;
		case AF_C7:
			at = len1+cm2;
			break;
		case AF_C8:
			at = len1+at2;
			break;
		case AF_C9:
			at = 0;
			break;
		case AF_C10:
			at = len1+at2;	/* or at = at1; */
			break;
		case AF_C11:
			at = len1+cm2;	/* or at = at1; */
			break;
		case AF_C12:
			at = len1+cm2;	/* or at = len1; */
			break;
		default: /* 頻度が多いので C4 をデフォールトに */
			/* ここが実行されることはないはずであるが、念のため。 */
			at = 0;
			break;
		}
#ifdef KETSUGO_DEBUG
		TmpMsg( "%s %d 接尾 %o\n", morph->kanji, at, af2 );
#endif

/* その他の結合 */
	} else {
		at = ( no_nucleus(morph) ) ? (len1+1) : (len1+at2);
#ifdef KETSUGO_DEBUG
		TmpMsg( "%s %d その他 %o\n", morph->kanji, at, af2 );
#endif
	}
	return( at );
}

/* 形態素 morph をアクセント句 a に追加する */
void add_to_aphrase( MORPH *morph, APHRASE *a )
{
	if( a->mphead == NULL )  {
		/* 一つめの子供 */
		a->mphead = a->mptail = morph;
		a->accentType = morph->accentType;
	} else {
		/* 最後尾の子供に */
		a->accentType = accentKetsugou( morph, a );
		a->mptail = morph;
	}
	a->nmora += morph->nmora;
	morph->parent = a;
}

APHRASE *new_aphrase()
{
	APHRASE	*aphrase;

	aphrase = (APHRASE *) malloc( sizeof(APHRASE) );
	if( ! aphrase )  {
		ErrMsg( "* malloc error for 'aphrase'\n" );
		restart(1);
	}
/* 作ったアクセント句セルをチェーンの中に入れる */
	if( ahead == NULL )  {
		/* 一つめのセル */
		ahead = atail = aphrase;
		aphrase->prev = aphrase->next = NULL;
	} else {
		/* tail の後ろに追加 */
		atail->next = aphrase;
		aphrase->prev = atail;
		aphrase->next = NULL;
		atail = aphrase;
	}
	aphrase->parent = NULL;

	aphrase->nmora = 0;
	aphrase->accentType = -1;
	aphrase->position = -1;
	aphrase->silence = NON;
	aphrase->interrogative = NO;
	aphrase->mphead = aphrase->mptail = NULL;

	return aphrase;
}

/* アクセント句が決まった後で、モーラごとのアクセント情報として、
       mora.position: アクセント句中でのモーラ位置
       mora.acdist: アクセント句中でのアクセント核からの相対位置
   を決める。*/
void make_accent_on_mora()
{
	APHRASE	*aphrase;
	MORA	*mora, *last=NULL;
	int 	i, accent;
	
	for( aphrase=ahead; aphrase; aphrase=aphrase->next )  {
		if( aphrase->nmora == 0 )  continue;	/* 「」など。*/

		accent = aphrase->accentType;
		mora = aphrase->mphead->mrhead;
		for( i=0; i<aphrase->nmora; ++i, mora=mora->next )  {
			mora->position = i+1;
			mora->acdist = (i+1) - accent;
			last = mora;
		}
		/* 念のため */
		if( aphrase->mptail->mrtail != last )  {
			ErrMsg( "* ERROR: make_accent_on_mora \n" );
			restart(1);
		}
	}
}

void make_aphrase()
{
	int 	pre_hinshi, hinshi, pre_ketsugou, ketsugou;
	MORPH	*morph;
	APHRASE	*aphrase=NULL;
	SILENCE pre_silence;

	pre_hinshi = pre_ketsugou = 0;
	pre_silence = NON;
	for( morph=mphead; morph; morph=morph->next )  {
		hinshi = morph->hinshiID;
		ketsugou = morph->accent[0].form;

		if( strcmp(morph->kanji,"？")==0 ) {
			/* '？' の前は別のアクセント句に */
			aphrase = new_aphrase();
			/* 前のアクセント句を疑問文に */
			if( aphrase->prev )  aphrase->prev->interrogative = YES;

		} else if( morph->silence != NON) {
			/* 無音は一つのアクセント句 */
			aphrase = new_aphrase();

		} else if(pre_silence != NON) {
			/* 無音の後は別のアクセント句に */
			aphrase = new_aphrase();

		} else if( IS_KUTOUTEN(pre_hinshi) || IS_KUTOUTEN(hinshi) ) {
			/* 句読点は単独のアクセント句に */
			aphrase = new_aphrase();

		} else if( hinshi == H_KAKKO_HIRAKU ||
				pre_hinshi == H_KAKKO_HIRAKU )  {
			/* 記号-括弧開 (「など) は単独のアクセント句に */
			aphrase = new_aphrase();

		} else if( hinshi == H_KAKKO_TOJIRU ||
				pre_hinshi == H_KAKKO_TOJIRU )  {
			/* 記号-括弧閉 (」など) は単独のアクセント句に */
			aphrase = new_aphrase();

		} else if( hinshi == H_DOUSHI_HIJIRITSU )  {
			/* 動詞-非自立 (いる、など) は前にくっつける */

		} else if( hinshi == H_KEIYOUSHI_HIJIRITSU )  {
			/* 形容詞-非自立 は前にくっつける */

		} else if( IS_SETSUBIJI(pre_hinshi) && IS_MEISHI(hinshi) )  {
			/* 接尾辞の後の名詞は一つのアクセント句に */

		} else if( IS_FUZOKUGO(pre_hinshi) && IS_JIRITSUGO(hinshi) )  {
			/* 付属語の後の自立語は別のアクセント句に */
			aphrase = new_aphrase();

		} else if( IS_FUZOKUGO(hinshi) )  {
			/* 付属語は前にくっつける */

		} else if( pre_hinshi == H_MEISHI_FUTSUU_FUKUSHI )  {
			/* 名詞-普通名詞-副詞可能 (すべて、など) は単独のアクセント句に */
			aphrase = new_aphrase();

		} else if( pre_hinshi == H_FUKUSHI || hinshi == H_FUKUSHI )  {
			/* 副詞は単独のアクセント句に */
			aphrase = new_aphrase();

		} else if( pre_hinshi == H_SETSUZOKUSHI || hinshi == H_SETSUZOKUSHI )  {
			/* 接続詞は単独のアクセント句に */
			aphrase = new_aphrase();

		} else if( pre_hinshi == H_RENTAISHI )  {
			/* 連体詞は単独のアクセント句に */
			aphrase = new_aphrase();

		} else if( pre_hinshi == H_DOUSHI && IS_MEISHI(hinshi) )  {
			/* 動詞の後に名詞がきたら別のアクセント句に */
			aphrase = new_aphrase();

		} else if( pre_hinshi == H_DOUSHI && 
				   ( hinshi == H_KEIYOUSHI || hinshi == H_KEIJOUSHI ) )  {
			/* 動詞の後に形容詞、形状詞がきたら別のアクセント句に */
			aphrase = new_aphrase();

		} else if( (pre_hinshi == H_KEIYOUSHI || pre_hinshi == H_KEIJOUSHI ) 
				   && IS_MEISHI(hinshi)	) {
			/* 形容詞、形状詞の後に名詞がきたら別のアクセント句に */
			aphrase = new_aphrase();

		} else if( IS_MEISHI(pre_hinshi) && IS_MEISHI(hinshi) )  {
			/* 名詞の連続はくっつける */

		} else if( pre_ketsugou == AF_P3 )  {
			/* 分離型 (各、反、前、など) は単独のアクセント句に */
			aphrase = new_aphrase();

		}
		aphrase->silence = morph->silence;
		add_to_aphrase( morph, aphrase );
		pre_hinshi = hinshi;
		pre_ketsugou = ketsugou;
		pre_silence = morph->silence;
	}

	make_accent_on_mora();
}

void print_aphrase()
{
	int 	n;
	APHRASE	*a;

	LogMsg( "* aphrase data\n" );
	LogMsg( "(orth\tpron\t[accent]\tmora\tposition\tDEC/INT)\n" );
	n = 0;
	for( a=ahead; a; a=a->next )  {
		print_aphrase_kanji( a );
		LogMsg( "\t" );
		print_aphrase_yomi( a );
		LogMsg( "\t[%d]\t%d\t%d\t", a->accentType, a->nmora, a->position );
		if( a->interrogative == YES ) {
		  LogMsg( "INT" );
		} else {
		  LogMsg( "DEC" );
		}
		LogMsg( "\n" );
		++n;
	}
	LogMsg( "- n_aphrase: %d\n", n );
}

void print_aphrase_kanji( APHRASE *a )
{
	MORPH	*morph;

	for( morph=a->mphead; morph && morph->parent==a; morph=morph->next )  {
			LogMsg( "%s", morph->kanji );
	}
}

void print_aphrase_yomi( APHRASE *a )
{
	MORPH	*morph;

	for( morph=a->mphead; morph && morph->parent==a; morph=morph->next )  {
		print_morph_yomi( morph );
	}
}

