# -*- coding: utf-8 -*-
"""This is really designed to get phones from UNISYN.  It was used
on the IViE corpus, where only text transcriptions are available.
"""

import os
from gmisclib import die
from gmisclib import dictops

import process_phones as PP
import phones as PH
import generate_misc as GM

MIN_PHONES_PER_UTTERANCE = 3


def prep_phones(pa, pmap, phonology, datasource='?'):
	"""This maps from the string of phonemes that the
	human or dictionary produces into a string of
	C, V, S and transition phonemes that the ASR systems wants.
	It inserts opportunities for liason where possible.
	@param is_manual_transcription: are pauses transcribed?  Otherwise, the
		system assumes that they may appear at word boundaries.
	@type is_manual_transcription: bool
	@param pa: The transcribed phoneme sequence
	@type pa: C{list(str)}
	@param pmap: A mapping from input phonemes to output phonemes.
	@type pmap: C{dict(str:str)}
	"""
	#: the output list of phonemes gets accumulated here.
	phones = []
	#: Have we just seen an end-of-word marker?
	iwp = False
	last = PH.phone_c('#')
	# GenericVowel = PP.get_most_frequent_vowel(pa, pmap, phonology)
	# GenericConsonant = PP.get_most_frequent_consonant(pa, pmap, phonology)
	# print "PA=", pa
	for p in pa:
		try:
			pm = pmap[p.lbl]
		except KeyError:
			pm = None
		# print "#pp: last=%s p=%s pm=%s len(phones)=%d phones[-1]=%s" % (last, p, pm, len(phones), phones[-1])
		if p.lbl in ['<BOS>', '<EOS>']:
			iwp = False
			pass
		elif p.lbl == '<B1>':
			iwp = False
			if last is not None and last.is_all_sil():
				phones.append(PH.phone_c(PH.opt('shortsil')))
			else:
				phones.append(PH.phone_c(PH.opt(PH.alt('sil', 'shortsil'), p=0.2)))
			last = PH.phone_c('#')
		elif p.lbl == '<B2>':
			iwp = False
			if last is not None and last.is_all_sil():
				phones.append(PH.phone_c(PH.opt('shortsil')))
			else:
				phones.append(PH.phone_c('shortsil'))
			last = PH.phone_c('#')
		elif p.lbl == '<B3>':
			if last is None or not last.is_all_sil():
				last = PH.phone_c('#')
				iwp = False
				phones.append(PH.phone_c('sil'))
		elif p.lbl == '<W>':
			# print "#pp: <W> %s" % p.lbl
			# Word or punctuation boundaries.
			iwp = True
		elif pm is not None and pm:
			# print "#pp: normal %s %s" % (str(p.lbl), pm)
			# All normal phonemes.
			if iwp and last is not None:
				if PP.isV(phonology, last.likely()[-1]) and PP.isV(phonology, p.likely()[0]):
					# # Possible liason, or maybe a pause
					# phones.append(PH.phone_c(PH.opt(PH.alt(GenericConsonant, 'sil'), p=0.2)))
					# A possible pause:
					# phones.append(PH.phone_c(PH.opt('sil', p=0.1)))
					phones.append(PH.phone_c(PH.opt(PH.alt('sil', 'shortsil'), p=0.1)))
				elif PP.isC(phonology, last.likely()[-1]) and PP.isC(phonology, p.likely()[0]):
					# # Possible consonant deletion or Epenthetic vowel insertion or pause
					# phones[-1].lbl = PH.alt(phones[-1].lbl,
									# PH.seq(phones[-1].lbl, GenericVowel),
									# PH.seq(phones[-1].lbl, 'sil'),
									# PH.opt('sil', p=0.2)
									# )
					# A possible pause:
					# phones.append(PH.phone_c(PH.opt('sil', p=0.1)))
					phones.append(PH.phone_c(PH.opt(PH.alt('sil', 'shortsil'), p=0.1)))
				elif PP.isC(phonology, last.likely()[-1]):
					# # There is a possibility of consonant deletion and/or a pause
					# phones[-1].lbl = PH.seq(PH.opt(phones[-1].lbl), PH.opt('sil', p=0.1))
					# A possible pause:
					# phones.append(PH.phone_c(PH.opt('sil', p=0.1)))
					phones.append(PH.phone_c(PH.opt(PH.alt('sil', 'shortsil'), p=0.1)))
				elif not last.is_all_sil():
					# phones.append(PH.phone_c(PH.opt('sil', p=0.1)))
					phones.append(PH.phone_c(PH.opt(PH.alt('sil', 'shortsil'), p=0.1)))
				
			iwp = False
			phones.append(PH.phone_c(pm))
			last = p
		elif pm == '':
			# Legal non-phonemes like tone markers.
			pass
		else:
			raise GM.BadPhonesError("Unrecognized phone: %s from %s" % (p, datasource))
	if len(phones) < 3: 
		raise GM.BadPhonesError("Too few phones: %d" % len(phones), pa, datasource)
	# You should always have a <B3> at the end of a sentence, so
	# it should always end in a silence.
	assert phones[-1].is_some_sil()
	return phones




def prepare_phones(info, pmap, phonology, get_transcription):
	d = os.path.join(info['dbdir'], info['d'], info['f'])
	o = []
	phonelist, priority, phonefile = get_transcription(info)
	if len(phonelist) < MIN_PHONES_PER_UTTERANCE:
		die.warn("Too few phones (%d) in %s from %s" % (len(phonelist), phonefile, d))
		return o

	edge_silence = 'fragments' not in d

	try:
		tmp = prep_phones(phonelist, pmap, phonology, datasource=phonefile)
	except GM.BadPhonesError, x:
		die.warn("%s in %s from %s" % (x, phonefile, d))
		return []
	else:
		if len(tmp) >= MIN_PHONES_PER_UTTERANCE:
			o.append(tmp)
		else:
			die.warn("After preparation, there were too few phones (%d): %s" % (len(tmp), d))
	# print 'Before pppp', tmp
	if edge_silence:
		PP.add_edge_silence(tmp)
	else:
		PP.junkify_edge_phones(tmp)
	# print 'After pppp', tmp
	assert len(o) in [0,1]
	return o

