/* 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 LogMsg(char *,...);
int ErrMsg(char *,...);
void restart(int);

/* 最初に一度だけ */
void init_mora()
{
	mrhead = mrtail = NULL;
}

/* 入力文ごとに */
/* 使っているモーラのセルの開放 */
void refresh_mora()
{
	MORA *mora, *next;

	mora = mrhead;
	while( mora )  {
		next = mora->next;
		free( mora->yomi );
		free( mora );
		mora = next;
	}
	mrhead = mrtail = NULL;
}

MORA *new_mora()
{
	MORA *mora;

	mora = (MORA*) malloc( sizeof(MORA) );
	if( ! mora )  {
		ErrMsg( "* malloc error for 'mora'\n" );
		restart(1);
	}

/* 作ったモーラセルをチェーンの中に入れる */
	if( mrhead == NULL )  {
		/* 一つめのセル */
		mrhead = mrtail = mora;
		mora->prev = mora->next = NULL;
	} else {
		/* tail の後ろに追加 */
		mrtail->next = mora;
		mora->prev = mrtail;
		mora->next = NULL;
		mrtail = mora;
	}
	mora->parent = NULL;

	mora->yomi = NULL;
	mora->position = -1;
	mora->acdist = -1;
	mora->chouonka = NO;
	mora->silence = NON;
	mora->phead = mora->ptail = NULL;

	return mora;
}

/* 仮名表記からモーラのデータを作り、モーラ数を返す */
int make_mora_data( MORPH *morph, char *yomi )
{
	int 	hinshi, nmora, len;
	short 	c1, c2;
	MORA	*mora=NULL;
	char	*p;

	hinshi = morph->hinshiID;

/* カタカナで書かれているかどうかチェックしておく */
	p = yomi;
	while( *p )  {
		if( strcmp("、",p)==0 )  break;
		if( strcmp("。",p)==0 )  break;
		if( strcmp("？",p)==0 )  break;

		/* カタカナでなければエラー。 0xA1,0xBC は「ー」*/
		c1 = (*p)&0xFF;
		c2 = (*(p+1))&0xFF;
//		if( !( c1==0xA5 && (c2>=0xA1 && c2<=0xF6) ) &&
//		    !( c1==0xA1 && c2==0xBC ) )  {
		if( !( c1==0x83 && (c2>=0x3f && c2<=0x96) ) &&
		    !( c1==0x81 && c2==0x5b ) )  {
			ErrMsg( "* yomi is NOT katakana ... %s (%x,%x)\n", 
				yomi, c1, c2 );
			return 0;
		}
		p += 2;
	}

	nmora = 0;
	while( *yomi )  {
		mora = new_mora();
		mora->parent = morph;
		if( nmora == 0 )  morph->mrhead = mora;

		p = yomi+2;
		if( strncmp("ァ",p,2)==0 ||
			strncmp("ィ",p,2)==0 ||
			strncmp("ゥ",p,2)==0 ||
			strncmp("ェ",p,2)==0 ||
			strncmp("ォ",p,2)==0 ||
			strncmp("ャ",p,2)==0 ||
			strncmp("ュ",p,2)==0 ||
			strncmp("ョ",p,2)==0 )  {
				len = 4;
		} else {
				len = 2;
		}

		mora->yomi = (char *) malloc( sizeof(char) * (len+1) );
		if( ! mora->yomi )  {
			ErrMsg( "* malloc error for 'mora.yomi'\n" );
			restart(1);
		}
		memcpy( mora->yomi, yomi, len );
		mora->yomi[len] = '\0';

		if( strcmp(mora->yomi,"ー")==0 )  mora->chouonka = YES;
		++nmora;
		yomi += len;
	}
	morph->mrtail = mora;

	return nmora;
}

void make_silence_mora( MORPH *morph )
{
	MORA *mora;

	/* 、の後の 「 や 、の前の 」 では、ポーズを作らない。*/
	if( morph->hinshiID == H_KAKKO_HIRAKU &&   /* 「 など */
		morph->prev->silence != NON )  return;
	if( morph->hinshiID == H_KAKKO_TOJIRU &&	/* 」など */
		morph->next->silence != NON )  return;

	mora = new_mora();

	mora->yomi = (char *) malloc( sizeof(char) * 5 );
	if( ! mora->yomi )  {
		ErrMsg( "* malloc error for 'mora.yomi of SILENCE'\n" );
		restart(1);
	}
	if( morph->silence == PAU )  {
		strcpy( mora->yomi, "pau" );
	} else if( morph->silence == SILB )  {
		strcpy( mora->yomi, "silB" );
	} else if( morph->silence == SILE )  {
		strcpy( mora->yomi, "silE" );
	} else {
		ErrMsg( "* Unknown silence in make_silence_mora\n" );
		strcpy( mora->yomi, "pau" );
/*		restart(1);	*/
	}
	mora->parent = morph;
	morph->mrhead = morph->mrtail = mora;
	mora->silence = morph->silence;
}

void make_mora()
{
	MORPH *morph;

	for( morph=mphead; morph; morph=morph->next )  {
		if( morph->silence == NON )  {
			morph->nmora = make_mora_data( morph, morph->pron );
			if( morph->nmora == 0 ) {
				morph->silence = PAU;
				make_silence_mora( morph );
			}
		} else {
			make_silence_mora( morph );
			morph->nmora = 0;	/* ポーズ、無音のモーラ数は 0 に */
		}
	}
}

void print_mora()
{
	MORA *mora;

	LogMsg( "* mora data\n" );
	for( mora=mrhead; mora; mora=mora->next )  {
		LogMsg( "%s", mora->yomi );
		if( mora->devoiced == YES )  LogMsg( "*" );
/*		if( mora->silence == SILB )  LogMsg( "SB" );
		if( mora->silence == SILE )  LogMsg( "SE" );
		if( mora->silence == PAU )  LogMsg( "P" );
*/
		LogMsg( " " );
	}
	LogMsg( "\n" );
}
