#!python

"""This takes a HTK directory, as set up by rec.sh and recognizes a bunch of audio
files.     The input is taken from the normal metadata files and the output labels
are likewise written as specified by the metadata.

Usage: rec_all.py rec mfccname fiatfiles
where: rec is the name of a directory here that defines a HTK model (eg rec="rec2fc")
and mfccname is the name of the input mfcc data (e.g.   somedir/mfccname.mfcc)  these
mfcc files are in the directories pointed at by the fiat files.

It reports failure if more than half of its attempts fail.
"""

import os
import sys
import tempfile
import subprocess
from gmisclib import die
from gmisclib import fiatio
from gmisclib import threaded_io
from gmisclib import wavesurfer_lab as WS
from gmisclib import HTK_MLF_io as HTK

import threading

sys.path.insert(0, 'bin')
import convert_ws_lab

def convert_mlf(ifile, ofile):
	assert os.path.isfile(ifile)
	wslabs = convert_ws_lab.convert_mlf(ifile)
	WS.write(open(ofile, 'w'), {'file':ifile}, wslabs)


class io(object):
	def __init__(self):
		self.stdout = tempfile.TemporaryFile(suffix='stdout')
		self.stderr = tempfile.TemporaryFile(suffix='stderr')
		self.rval = None

	def get_stdout(self):
		self.stdout.seek(0, os.SEEK_SET)
		return self.stdout.read()

	def get_stderr(self):
		self.stderr.seek(0, os.SEEK_SET)
		return self.stderr.read()
	
	def close(self):
		self.stdout.close()
		self.stdout = None
		self.stderr.close()
		self.stderr = None


def segment(rec, mfccname, oname, dbdir, info, iob):
	path = os.path.join(dbdir, info['d'], info['f'])
	mfccfname = os.path.join(path, '%s.mfcc' % mfccname)
	print 'Recognizing', path
	assert os.path.isdir(rec)
	assert os.path.isdir('tmpR')
	assert os.path.isdir(path)
	tmfd, tmlf = tempfile.mkstemp(suffix='.mlf')
  	cmd = ['HVite', '-A', '-D', '-T', '1', '-C', os.path.join(rec, 'config'),
		'-i', tmlf,
		'-d', 'tmpR/ph',
		'-H', 'tmpR/ph/macros',
		'-w',  'tmpR/net.slf',
		os.path.join('training', 'dict_final'), 'tmpR/ph/phones', mfccfname
		]
	iob.rval = subprocess.call(cmd, stdout=iob.stdout, stderr=iob.stderr)
	poname = os.path.join(path, oname)
	if iob.rval == 0:
		convert_mlf(tmlf, poname)
	else:
		die.warn("Recognizing %s fails with %d" % (path, iob.rval))
	os.remove(tmlf)
	os.close(tmfd)




def segment_all(rec, mfccname, oname, fiatfiles, n):
	ns = 0
	nt = 0
	tlist = []
	for fname in fiatfiles:
		h, infos, c = fiatio.read(open(fname, 'r'))
		if not infos:
			die.warn("There is no metadata in %s" % fname)
		dbdir = os.path.dirname(fname)
		for info in infos:
			iob = io()
			t = threading.Thread(target=segment,
					args=(rec, mfccname, oname, dbdir, info, iob),
					name=oname
					)
			t.iob = iob
			nt += 1
			t.start()
			tlist.append(t)
			while len(tlist) > n:
				t = threaded_io.to_be_joined(tlist)
				t.join()
				print t.iob.get_stdout()
				print t.iob.get_stderr()
				ns += t.iob.rval==0
				t.iob.close()
	while tlist:
		t = threaded_io.to_be_joined(tlist)
		t.join()
		print t.iob.get_stdout()
		print t.iob.get_stderr()
		t.iob.close()
		ns += t.iob.rval==0

	die.info("%d successes out of %d utterances attempted" % (ns, nt))
	return ns >= (nt+1)//2


if __name__ == '__main__':
	rec = sys.argv[1]
	mfccname = sys.argv[2]
	oname = '%s_%s.lab' % (rec, mfccname)
	fiatfiles = sys.argv[3:]
	rv = segment_all(rec, mfccname, oname, fiatfiles, threaded_io.ncpu())
	sys.exit( (1,0)[rv] )

