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

struct {
	int 	id;
	char	*name;
} aformTable[] = {
	{ AF_NULL, "-" },
	{ AF_F1, "F1" },
	{ AF_F2, "F2" },
	{ AF_F3, "F3" },
	{ AF_F4, "F4" },
	{ AF_F5, "F5" },
	{ AF_F6, "F6" },
	{ AF_F7, "F7" },
	{ AF_F8, "F8" },
	{ AF_F9, "F9" },
	{ AF_C1, "C1" },
	{ AF_C2, "C2" },
	{ AF_C3, "C3" },
	{ AF_C4, "C4" },
	{ AF_C5, "C5" },
	{ AF_C6, "C6" },
	{ AF_C7, "C7" },
	{ AF_C8, "C8" },
	{ AF_C9, "C9" },
	{ AF_C10, "C10" },
	{ AF_C11, "C11" },
	{ AF_C12, "C12" },
	{ AF_P1, "P1" },
	{ AF_P2, "P2" },
	{ AF_P3, "P3" },
	{ AF_P4, "P4" },
	{ AF_P5, "P5" },
	{ AF_P6, "P6" },
	{ AF_P7, "P7" },
	{ AF_P8, "P8" },
	{ AF_P9, "P9" },
	{ AF_P10, "P10" },
	{ AF_P11, "P11" },
	{ AF_P12, "P12" },
	{ AF_P13, "P13" },
	{ AF_P14, "P14" },
	{ AF_P15, "P15" },
	{ AF_OTHER, "?" },
};

#define	NUM_AFORM	(sizeof(aformTable)/sizeof(aformTable[0]))

/* アクセント型の決定 */
int getAccent( char *acc, int kata, int kei )
{
	int 	aType, i;

	i = 0;
	while( acc[i] )  {
		if( acc[i] == ',' )  {
			acc[i] = '\0';			/* 1,0 などを 1 に */
			break;
		}
		++i;
	}

	aType = ( acc[0]=='\0' ) ? 0 : atoi( acc );

	if( aType == 0 )  return( aType );

/* 一段活用で未然形、連用形のときには、アクセント型が左へ一つ動く */
/* 暖める: アタタメ|ル(4型)  暖め + た: アタタ|メ + タ(3型) */
	if( kata==KATA_ICHIDAN && (kei==KEI_MIZEN || kei==KEI_RENYOU) )  {
		--aType;
	}
	return( aType );
}

/* アクセント結合型のID */
int getAccentFormID( char *aform )
{
	int 	i;
	for( i=0; i<NUM_AFORM; ++i )  {
		if( strcmp(aform,aformTable[i].name)==0 )  return aformTable[i].id;
	}
	return -1;
}

/* 結合型IDを様式名称 (F1 など) に変換する。*/
char * aformName( int acID )
{
	int 	i;
	if( acID == -1 )  return "-";		/* silB, silE など */
	for( i=0; i<NUM_AFORM; ++i )  {
		if( acID == aformTable[i].id )  return aformTable[i].name;
	}
	ErrMsg( "Unknown Accent Ketsugou ID ... '%d'\n", acID );
/*	restart( 1 );	*/
	return NULL;
}

int isNumber( char c )
{
	if( c == '-' )  return (1);
	if( c >= '0' && c <= '9' )  return(1);
	return( 0 );
}

int isNumberStr( char *str )
{
	while( *str )  {
		if( ! isNumber( *str ) )  return( 0 );
		++str;
	}
	return( 1 );
}

/* 文字列 p からデリミタ(あるいはNULL)までの文字を token に入れ、
次の場所を返す */
static char *get_token( char *p, char *token, char del )
{
	if( *p == '\0' || p == NULL )  return NULL;

/*	while( *p != del && *p != '\0' )  {	*/

	while( 1 )  {
		if( *p == '\0' )  break;
		if( *p == del )  {
			if( del != ',' )  {
				break;
			} else {
			/*  形容詞%F6@0,-2 などの処理 */
				if( ! isNumber( *(p+1) )  )  break;
			}
		}

		*(token++) = *(p++);
	}
	*token = '\0';
	if( *p != '\0' )  ++p;
	return p;
}


#define MAX_TOKENSTR 2048
static char tokenStr[MAX_TOKENSTR];
static char *tokenPos;

/* トークンを含む文字列をセットする。*/
static void setTokenStr( char *str )
{
	if( strlen(str)+1 > MAX_TOKENSTR )  {
		ErrMsg( "Too long string in setTokenStr()\n" );
		return;
	}
	strcpy( tokenStr, str );
	tokenPos = tokenStr;
}

static int isDelimiter( char c )
{
	if( c == '%' || c == '@' || c == ',' || c == '\0' )  {
		return( 1 );
	} else {
		return( 0 );
	}
}

/* トークンがあれば１、なくなれば０を返す。*/
static int getToken( char *token )
{
	if( *tokenPos == '\0' )  return( 0 );

	if( isDelimiter( *tokenPos ) )  {
		*(token++) = *(tokenPos++);
		*token = '\0';
		return( 1 );
	}

	for( ;; )  {
		*(token++) = *(tokenPos++);
		if( isDelimiter( *tokenPos ) )  {
			*token = '\0';
			return( 1 );
		}
	}
}	

/* アクセント接続情報
	動詞%F5,名詞%F1,形容詞%F6@0,-2
などから、必要な情報を取り出す。*/

void parse_aConType( char *acon_str, MORPH *morph )
{
	char token[128];
	enum {POS,ACON,NUM,NON} pre_token_type;
	char pre_del_type;
	int i, ctype_pos, afID;

	setTokenStr( acon_str );

	i = -1;		/* アクセント結合情報の数 */
	ctype_pos = 1;
	pre_token_type = NON;
	pre_del_type = ' ';

	while( getToken( token ) )  {
		if( strcmp(token,"名詞")==0 || strcmp(token,"動詞")==0
				|| strcmp(token,"形容詞")==0 )  {
			++i;
			if( strcmp(token,"名詞")==0 )  {
				morph->accent[i].prepos = 'N';
			} else if( strcmp(token,"動詞")==0 )  {
				morph->accent[i].prepos = 'V';
			} else if( strcmp(token,"形容詞")==0 )  {
				morph->accent[i].prepos = 'A';
			}
			pre_token_type = POS;
			morph->accent[i].ctype  = -999;
			morph->accent[i].ctype2 = -999;

		} else if( strcmp(token,"%")==0 )  {
			if( pre_token_type != POS )  {
				ErrMsg( "* irregal aConType ...\n%s\n", acon_str );
			}
			pre_del_type = '%';

		} else if( strcmp(token,"@")==0 )  {
			if( pre_token_type != ACON )  {
				ErrMsg( "* irregal aConType ...\n%s\n", acon_str );
			}
			pre_del_type = '@';

		} else if( strcmp(token,",")==0 )  {
			pre_del_type = ',';

		} else if( (afID = getAccentFormID(token)) >= 0 )  {
			if( pre_token_type == NON )  ++i;
			if( pre_token_type != POS )  {
				morph->accent[i].prepos = '*';
				morph->accent[i].ctype  = -999;
				morph->accent[i].ctype2 = -999;
			}
			morph->accent[i].form = afID;
			ctype_pos = 1;
			pre_token_type = ACON;

		} else if( isNumberStr(token) )  {
			if( ctype_pos == 1 )  {
				if( pre_token_type != ACON )  {
					ErrMsg( "* irregal aConType ...\n%s\n", acon_str );
				}
				morph->accent[i].ctype = atoi( token );
				ctype_pos = 2;
			} else {
				if( pre_token_type != NUM )  {
					ErrMsg( "* irregal aConType ...\n%s\n", acon_str );
				}
				morph->accent[i].ctype2 = atoi( token );
			}
			pre_token_type = NUM;
			
		} else {
			ErrMsg( "* Unknown token ... '%s' in %s\n", token, acon_str );
		}
	}
	morph->n_accent = i+1;
}

void init_accent_info( MORPH *morph )
{
	/* to set default */
	morph->accentType = -1;
	morph->n_accent = 0;
}

/* 以下は、古い辞書のバージョン (unidic-0.1.x) に対応するため、残してある。*/

/* 茶筌の付加情報
	accent=0:accent_con=名詞%F1,動詞%F2@0,形容詞%F2@0
から、アクセント型などの情報を取り出す。 */

void parse_accent_info( char *val, MORPH *morph )
{
	char	*v, token[256];

	init_accent_info( morph );

	v = val;
	morph->accentType = 0;	/* アクセント型データがなければ 0 型に */
/*	TmpMsg( "val: %s\n", val );	*/
	while( (val=get_token(val,token,'=')) != NULL )  {
		if( strcmp("accent",token)==0 )  {
			val = get_token(val,token,':');
			morph->accentType = getAccent( token, 
				morph->katsuyogataID, morph->katsuyokeiID );

		} else if( strcmp("accent_con",token)==0 )  {
			val = get_token(val,token,':');
			parse_aConType( token, morph );

		} else {
			ErrMsg( "Unknown info ... '%s' in '%s'\n", token, v );
/*			restart( 1 );	*/
		}
	}
}

