#! python

"""This was used for LabPhon 12, 2010."""

import os
import sys
import math
import random

import numpy

import gpkimgclass

from gmisclib import die
from gmisclib import mcmc
from gmisclib import avio
from gmisclib import stats
from gmisclib import tsops
from gmisclib import fiatio
from gmisclib import gpkmisc
from gmisclib import dictops
from gmisclib import g2_select
from gmisclib import g_localfit
# from gmisclib import mcmc_idxr
# from gmisclib import spread_jobs
from gmisclib import g_datetime as GD
from gmisclib import Numeric_gpk as NG
from gmisclib import wavesurfer_lab as WL
from gmisclib import weighted_percentile as WP
from gmisclib import blue_data_attributes as BD

from gpk_voicing import voice_misc

# from newstem2 import indexclass as IC

# from sloppy_oscillator import delay4 as O
from RM_ts_lib import zero as Z


SEGMENTATION = 'recVx_HTKfv.lab'

PSample = 0.03
TYPDUR = 0.10


class DubiousData(ValueError):
	def __init__(self, *s):
		ValueError.__init__(self, *s)


class utterance_c(object):
	def __init__(self, dbdir, info, segmentation):
		self.info = info
		self.dbdir = dbdir
		self.read_data(dbdir, info, segmentation)

	def read_data(self, dbdir, info, segmentation):
		self.segmentation = segmentation
		self.path = os.path.join(dbdir, info['d'], info['f'])
		die.info('Loading %s' % self.path)
		ld = gpkimgclass.read(os.path.join(self.path, 'loud.dat'))
		ird = gpkimgclass.read(os.path.join(self.path, 'irr.dat'))
		pdd = gpkimgclass.read(os.path.join(self.path, 'pdur.dat'))
		self.taxis, loud, irr, pdur = tsops.common([ld, ird, pdd])
		self.pdur = pdur[:,pdd.types['pseudoduration']]
		
		loud = loud[:,ld.types['loudness']]
		loud -= Z.loud_zero(loud)
		if not numpy.sum(numpy.maximum(0.0, loud)) > 30.0*numpy.sum(numpy.maximum(0.0, -loud)):
			raise DubiousData, "Loudness is not dominantly positive."
		avloud = numpy.sum(loud**2)/numpy.sum(loud)
		self.lnorm = loud/avloud
		irr = irr[:,ird.types['aperiodicity']]
		irr_avg = numpy.sum(irr*loud)/numpy.sum(loud)
		self.fric = self.lnorm * (irr - irr_avg) * 2.0
		# The extra factor of 2.0 is so that the variance(fric) is similar to var(lnorm)
		

	@staticmethod
	def print_hdr():
		print "# All data from a C,V,C,V,C sequence."
		print "# COL 1: voicing estimator: total voicing over the latter half-C,V,half-C syllable."
		print "# COL 2: narrow speech rate estimator from latter half-C,V,half-C"
		print "# COL 3-6 duration, loudness, voicing estimator, speechrate for first half-C,V,half-C"
		print "# COL 7: speech rate estimator over the entire C,V,C,V,C sequence"
		print "# COL 8-16: group,gender,tempo,minmax,property,subjectID, language, d, f"


	def printit(self):
		h, lbls = WL.read(os.path.join(self.path, self.segmentation))
		if len(lbls) <= 5:
			die.warn('lbls too short: %d for %s / %s' % (len(lbls), self.path, self.segmentation))
			return
		for i in range(3, len(lbls)-1):
			if random.random() > PSample:
				continue
			if(lbls[i][2]=='V' and lbls[i-1][2]=='C' and lbls[i+1][2]=='C'
				and lbls[i-2][2]=='V' and lbls[i-3][2]=='C'):
				o = []
				try:
					tmp = self.compute_statistics(lbls[i-1][0],
											lbls[i][0],
											lbls[i][1],
											lbls[i+1][1])
				except IndexError, x:
					die.warn('OutOfRange: %s in %s' % (x, self.path))
					continue

				o.append(tmp[self.idx['voice1']])
				o.append(tmp[self.idx['speechrate']])
				try:
					o.extend(self.compute_statistics(lbls[i-3][0],
											lbls[i-2][0],
											lbls[i-2][1],
											lbls[i-1][1])
							)
				except IndexError, x:
					die.warn('OutOfRange: %s in %s' % (x, self.path))
					continue
				try:
					o.append(self.speechrate(lbls[i-3][0], lbls[i+1][1]))
				except IndexError, x:
					die.warn('OutOfRange: %s in %s' % (x, self.path))
					continue
				try:
					o.append(self.info['group'])
					o.append(self.info['gender'])
					o.append(self.info['tempo'])
					o.append(self.info['minmax'])
					o.append(self.info['property'])
					o.append(self.info['subjectID'])
					o.append(self.info['language'])
					o.append(self.info['d'])
					o.append(self.info['f'])
				except KeyError, x:
					die.info('key: %s' % x)
					continue
				print ','.join(["%s" % q for q in o])


	def speechrate(self, start, end):
		dur = (end-start)
		si = int(round(self.taxis.index(start)))
		ei = int(round(self.taxis.index(end)))
		speechrate = math.log(numpy.sum(1.0/self.pdur[si:ei+1]) / dur)
		return speechrate

	def compute_statistics(self, c1s, vs, ve, c2e):
		sylsi = int(round(self.taxis.index(0.5*(vs+c1s))))
		sylei = int(round(self.taxis.index(0.5*(ve+c2e))))

		dur = (0.5*(ve+c2e)-0.5*(vs+c1s))/TYPDUR

		lbar = numpy.average(self.lnorm[sylsi:sylei])

		v1 = numpy.mean(self.fric[sylsi:sylei+1])
		speechrate = self.speechrate(0.5*(vs+c1s), 0.5*(ve+c2e))
		return [math.log(dur), lbar, v1, speechrate]
	
	idx = {'duration':0, 'lbar':1, 'voice1':2, 'speechrate': 3}

	ridx = dictops.rev1to1(idx)

def inspector(info):
	return (info['gender'], info['textfile'], info['subjectID'], info['language'])



def select_data_files(dblist, selector):
	assert len(dblist) > 0
	dur = []
	syl = []
	tmp = []
	for dbpath in dblist:
		dbd, dbf = os.path.split(dbpath)
		h, d, c = fiatio.read(open(os.path.join(dbd, dbf), 'r'))
		for info in g2_select.filterlist(selector, d):
			info['__dbdir'] = dbd
			ns = int(info['son_nas_vowel_exp'])
			syl.append(ns)
			info['__nsyls'] = ns
			d = GD.timedelta2float(GD.ISO2datetime(info['RecordEndTime'])
						- GD.ISO2datetime(info['RecordStartTime']))
			info['__duration'] = d
			dur.append(d)
			tmp.append(info)
	assert len(tmp) > 0
	dl, dh = WP.wp(dur, None, [0.1, 0.9])
	snl, snh = WP.wp(syl, None, [0.1, 0.9])
	print '# Range of durations counts accepted:', dl, dh
	print '# Range of syllable counts accepted:', snl, snh
	infolist = []
	for info in tmp:
		if(dl <= info['__duration'] <= dh and
				snl <= info['__nsyls'] <= snh):
			infolist.append(info)

	return infolist




def read_in_utterances(dblist, selector, segmentation):
	for info in select_data_files(dblist, selector):
		if 'ASR' in info['textfile']:
			continue
		if 'group' not in info:
			print 'info=', info
			die.warn("Dropping: no group: %s/%s" % (info['d'], info['f']))
			continue
		try:
			tmp = utterance_c(info['__dbdir'], info, segmentation)
		except Z.ZeroProblem, x:
			die.warn("Dropping %s/%s because of ZeroProblem.%s" % (info['d'], info['f'], str(x)))
		except DubiousData, x:
			die.warn("Dropping %s/%s because of DubiousData.%s" % (info['d'], info['f'], str(x)))
		except WL.NoSuchFileError, x:
			die.warn("Dropping %s/%s because of NoSuchFile.%s" % (info['d'], info['f'], str(x)))
		tmp.printit()


def allbut(a, *i):
	return [a for (a,j) in enumerate(a) if j not in i]





def name(prefix, npper, i):
	return '%s:%d:%s' % (prefix, 1+(i//npper), utterance_c.ridx[1+(i%npper)])


def process(dblist, selector, seglist):
	utterance_c.print_hdr()
	for s in seglist:
		read_in_utterances(dblist, selector, s)


if __name__ == '__main__':
	dblist = [q for q in sys.argv[1:] if 'ASR' not in q]
	Selector = '"ASR" not in textfile'
	arglist = sys.argv[1:]
	while arglist and arglist[0].startswith('-'):
		arg = arglist.pop(0)
		if arg == '--':
			break
		elif arg == '-s':
			Selector = arglist.pop(0)
		else:
			die.die('Unrecognized argument: %s' % arg)
	process(arglist, Selector, [SEGMENTATION])
