#include <fishtalk.h>

/* phonemes per letter */
#define MAX_PPL 5

#define FT_PHONEME(X) phon_##X,
static signed char* phons[] = {NULL, NULL, NULL, FT_PHONEMES};
#undef FT_PHONEME

#define FT_PHONEME(X) , #X
static const char* phon_str[] = {"(none)", "(space)", "" FT_PHONEMES};
#undef FT_PHONEME

#define FT_PHONEME(X) , P_##X
enum PHONS {
	P_NONE = 0,
	P_DOT,
	P_IGNORE FT_PHONEMES
};
#undef FT_PHONEME

static int p_match(const char* buffer, const char* target, long buffer_length) {
	int i;

	if(buffer_length < strlen(target)) return 0;

	for(i = 0; target[i] != 0; i++) {
		if(target[i] == '_') continue;

		if(tolower(buffer[i]) != tolower(target[i])) return 0;
	}

	return 1;
}

#define M(X) p_match(buffer + i, (X), length - i)
#define DEF(X) static int X(unsigned char* ph, int i, const char* buffer, long length, int first, int last, char b_c)

DEF(p_gen_4) {
	if(M("tion")) {
		ph[i * MAX_PPL + 0] = P_SH;
		ph[i * MAX_PPL + 1] = P_AH;
		ph[i * MAX_PPL + 2] = P_N;
		return 3;
	} else if(M("sion")) {
		ph[i * MAX_PPL + 0] = P_ZH;
		ph[i * MAX_PPL + 1] = P_AH;
		ph[i * MAX_PPL + 2] = P_N;
		return 3;
	}

	return -1;
}

DEF(p_silent_e) {
	if(M("a_e")) {
		ph[i * MAX_PPL + 0] = P_EY;

		return 0;
	} else if(M("i_e")) {
		ph[i * MAX_PPL + 0] = P_AY;

		return 0;
	} else if(M("o_e")) {
		ph[i * MAX_PPL + 0] = P_OW;

		return 0;
	} else if(M("u_e")) {
		ph[i * MAX_PPL + 0] = P_Y;
		ph[i * MAX_PPL + 1] = P_UW;

		return 0;
	}

	return -1;
}

DEF(p_special_2) {
	if(M("ly") && last) {
		ph[i * MAX_PPL + 0] = P_L;
		ph[i * MAX_PPL + 1] = P_IY;

		return 1;
	} else if(M("le") && last) {
		ph[i * MAX_PPL + 0] = P_L;
		ph[i * MAX_PPL + 1] = P_EH;

		return 1;
	}

	return -1;
}

DEF(p_gen_2) {
	if(M("ll")) {
		ph[i * MAX_PPL + 0] = P_L;

		return 1;
	} else if(M("sh")) {
		ph[i * MAX_PPL + 0] = P_SH;

		return 1;
	} else if(M("ch")) {
		ph[i * MAX_PPL + 0] = P_CH;

		return 1;
	} else if(M("th")) {
		ph[i * MAX_PPL + 0] = P_TH;
		i++;

		return 1;
	} else if(M("ph")) {
		ph[i * MAX_PPL + 0] = P_F;

		return 1;
	} else if(M("ng")) {
		ph[i * MAX_PPL + 0] = P_NG;

		return 1;
	} else if(M("wr")) {
		ph[i * MAX_PPL + 0] = P_R;

		return 1;
	} else if(M("kn") || M("gn")) {
		ph[i * MAX_PPL + 0] = P_N;

		return 1;
	} else if(M("ck")) {
		ph[i * MAX_PPL + 0] = P_K;

		return 1;
	} else if(M("wa")) {
		ph[i * MAX_PPL + 0] = P_W;
		ph[i * MAX_PPL + 1] = P_AE;

		return 1;
	} else if(M("te")) {
		ph[i * MAX_PPL + 0] = P_T;
		ph[i * MAX_PPL + 1] = P_EH;

		return 1;
	} else if(M("tt")) {
		ph[i * MAX_PPL + 0] = P_T;

		return 1;
	}

	return -1;
}

DEF(p_vowel_2) {
	if(M("ee") || M("ea")) {
		ph[i * MAX_PPL + 0] = P_EY;

		return 1;
	} else if(M("oo")) {
		ph[i * MAX_PPL + 0] = P_UW; /* FIXME: could be P_UH */

		return 1;
	} else if(M("ou")) {
		ph[i * MAX_PPL + 0] = P_AW;

		return 1;
	} else if(M("ow")) {
		ph[i * MAX_PPL + 0] = P_OW;

		return 1;
	} else if(M("oi") || M("oy")) {
		ph[i * MAX_PPL + 0] = P_OY;

		return 1;
	} else if(M("ar")) {
		ph[i * MAX_PPL + 0] = P_AA;
		ph[i * MAX_PPL + 1] = P_R;

		return 1;
	} else if(M("er") || M("ir") || M("ur")) {
		ph[i * MAX_PPL + 0] = P_ER;

		return 1;
	} else if(M("or")) {
		ph[i * MAX_PPL + 0] = P_AO;
		ph[i * MAX_PPL + 1] = P_R;

		return 1;
	}

	return -1;
}

DEF(p_soft) {
	if(M("c")) {
		if(b_c == 'e' || b_c == 'i' || b_c == 'y') {
			ph[i * MAX_PPL + 0] = P_S;
		} else {
			ph[i * MAX_PPL + 0] = P_K;
		}

		return 0;
	} else if(M("g")) {
		if(b_c == 'e' || b_c == 'i' || b_c == 'y') {
			ph[i * MAX_PPL + 0] = P_JH;
		} else {
			ph[i * MAX_PPL + 0] = P_G;
		}

		return 0;
	}

	return -1;
}

DEF(p_special_1) {
	if(M("e") && last) {
		return 0;
	} else if(M("y") && first) {
		ph[i * MAX_PPL + 0] = P_Y;

		return 0;
	} else if(M("y") && last) {
		ph[i * MAX_PPL + 0] = P_IY;

		return 0;
	} else if(M("n") && last) {
		ph[i * MAX_PPL + 0] = P_N;

		return 0;
	} else if(M("k") && last) {
		ph[i * MAX_PPL + 0] = P_K;

		return 0;
	}

	return -1;
}

DEF(p_gen_1) {
	if(M("s")) {
		ph[i * MAX_PPL + 0] = P_S;

		return 0;
	} else if(M("f")) {
		ph[i * MAX_PPL + 0] = P_F;

		return 0;
	} else if(M("t")) {
		ph[i * MAX_PPL + 0] = P_T;

		return 0;
	} else if(M("p")) {
		ph[i * MAX_PPL + 0] = P_P;

		return 0;
	} else if(M("l")) {
		ph[i * MAX_PPL + 0] = P_L;

		return 0;
	} else if(M("m")) {
		ph[i * MAX_PPL + 0] = P_M;

		return 0;
	} else if(M("n")) {
		ph[i * MAX_PPL + 0] = P_N;

		return 0;
	} else if(M("d")) {
		ph[i * MAX_PPL + 0] = P_D;

		return 0;
	} else if(M("h")) {
		ph[i * MAX_PPL + 0] = P_HH;

		return 0;
	}

	return -1;
}

DEF(p_vowel_1) {
	if(M("a")) {
		ph[i * MAX_PPL + 0] = P_AE;

		return 0;
	} else if(M("e")) {
		ph[i * MAX_PPL + 0] = P_EH;

		return 0;
	} else if(M("i")) {
		ph[i * MAX_PPL + 0] = P_IH;

		return 0;
	} else if(M("o")) {
		ph[i * MAX_PPL + 0] = P_AA;

		return 0;
	} else if(M("u")) {
		ph[i * MAX_PPL + 0] = P_AH;

		return 0;
	}

	return -1;
}

#undef DEF
#undef M

void ft_phon_main(FT_HANDLE handle, const char* buffer, long length) {
	unsigned char* ph = malloc(length * MAX_PPL);
	int	       i;

	memset(ph, 0, length * MAX_PPL);

	for(i = 0; i < length; i++) {
		int  first = 0;
		int  last  = 0;
		char b_c   = (i > 0) ? buffer[i - 1] : 0;
		int  n;

		b_c = tolower(b_c);

		if(i == 0 || FT_IS_SKIPPABLE(buffer[i - 1])) first = 1;
		if(i == (length - 1) || FT_IS_SKIPPABLE(buffer[i + 1])) last = 1;

		if(ph[i * MAX_PPL]) continue;

		if(FT_IS_SKIPPABLE(buffer[i])) {
			ph[i * MAX_PPL + 0] = P_DOT;
		} else if((n = p_gen_4(ph, i, buffer, length, first, last, b_c)) != -1) {
		} else if((n = p_silent_e(ph, i, buffer, length, first, last, b_c)) != -1) {
		} else if((n = p_special_2(ph, i, buffer, length, first, last, b_c)) != -1) {
		} else if((n = p_gen_2(ph, i, buffer, length, first, last, b_c)) != -1) {
		} else if((n = p_vowel_2(ph, i, buffer, length, first, last, b_c)) != -1) {
		} else if((n = p_soft(ph, i, buffer, length, first, last, b_c)) != -1) {
		} else if((n = p_special_1(ph, i, buffer, length, first, last, b_c)) != -1) {
		} else if((n = p_gen_1(ph, i, buffer, length, first, last, b_c)) != -1) {
		} else if((n = p_vowel_1(ph, i, buffer, length, first, last, b_c)) != -1) {
		}

		if(n != -1) i += n;
	}

	fprintf(stderr, "phoneme of \"");
	fwrite(buffer, length, 1, stderr);
	fprintf(stderr, "\":");
	for(i = 0; i < length * MAX_PPL; i++) {
		if(!ph[i]) continue;

		fprintf(stderr, " %s", phon_str[ph[i]]);
	}
	fprintf(stderr, "\n");

	free(ph);
}
