# -*- coding: utf-8 -*-
import os

from gmisclib import die
from gmisclib import dictops

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

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 = [PH.phone_c('sil')]
	#: are we in the middle of a garbled section?
	garble = False
	#: counters are just used for trouble detection.
	counters = dictops.dict_of_accums()
	# GenericVowel = PP.get_most_frequent_vowel(pa, pmap, phonology)
	# GenericConsonant = PP.get_most_frequent_consonant(pa, pmap, phonology)
	for p in pa:
		try:
			pm = pmap[p.lbl]
		except KeyError:
			pm = None
		if p.lbl in ['#', '##', 'sil', 'shortsil']:
			counters.add('sil', 1)
			phones.append(PH.silence(s=p.s, e=p.e))
			# phones.append(PH.phone_c(PH.alt('sil', 'shortsil'), s=p.s, e=p.e))
		elif p.startswith('#w') or p.startswith('#p'):
			# Word or punctuation boundaries.
			garble = False
		elif p.startswith('#['):
			# Beginning of garble/correction
			garble = True
		elif p.startswith('#]') or p.startswith(']#'):
			# end of garble/correction
			garble = False
		elif p.startswith('#'):
			# Other non-phoneme markers.
			garble = False
		elif p.lbl == 'junk':
			phones.append(PH.phone_c(p.lbl, s=p.s, e=p.e))
		elif pm:
			# print "#pp: normal %s %s" % (str(p.lbl), pm)
			# All normal phonemes.
			if garble:
				pm = GM.JunkPhone
			counters.add(phones[-1].lbl, 1)
			phones.append(PH.phone_c(pm, s=p.s, e=p.e))
			counters.add(pm, 1)
			counters.add('*', 1)
		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" % counters.get('*',0), pa, datasource)
	if counters.get('garble',0) > (counters.get('*',0)+5)//10:
		raise GM.BadPhonesError("Too many garbles: %d in a string of %d phones"
					% (counters.get('garble',0), counters.get('*',0)),
					pa, datasource)
	return phones




def add_edge_silence(phones, start, end):
	if start > phones[0].s+0.01:
		return "phone[0] %s starts before utterance at %s" % (phones[0], start)
	if phones[0].s > start+0.01 and not phones[0].is_all_sil():
		phones.insert(0, PH.silence(dur=phones[0].s-start, e=phones[0].s))
	if end < phones[-1].e-0.01:
		return "phone[-1] %s ends after utterance at %s" % (phones[-1], end)
	if phones[-1].e < end-0.01 and not phones[-1].is_all_sil():
		phones.append(PH.silence(dur=end-phones[-1].e, s=phones[-1].e))
	return ''


def prepare_phones(info, pmap, phonology, candidate_files):
	d = os.path.join(info['dbdir'], info['d'], info['f'])
	die.info("Candidate files: %s" % candidate_files)
	o = []
	if candidate_files:
		start, end = GP.get_start_end(info)
		for phonefile in candidate_files:
			phonelist = GP.get_manual_transcription(phonefile)
			die.info("Found human segmentation in %s for %s" % (phonefile, d))
			if len(phonelist) < MIN_PHONES_PER_UTTERANCE:
				die.warn("Too few phones (%d) in %s" % (len(phonelist), d))
				continue
			try:
				tmp = prep_phones(phonelist, pmap, phonology, datasource=phonefile)
			except GM.BadPhonesError, x:
				die.warn("%s in %s from %s" % (x, phonefile, d))
				continue
			e = add_edge_silence(tmp, start, end)
			if e:
				die.warn("%s/%s: %s" % (info['d'], info['f'], e))
				continue
			PP.fill_NaNs_in_phone_sequence(tmp, start, end)
			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))

	return o
