#!/usr/bin/env python

"""Reads the *.fiat file produced by q_classifier.py that
contains the decisions of the individual classifiers in the forest.
Returns the majority decision."""

import math
from gmisclib import fiatio
from gmisclib import nice_hash
from gmisclib import avio
from gmisclib import dictops

DEFAULTS = {}

def index(individuals):
	"""Takes a list of decisions on an individual utterance
	from an individual classifier (as from *.fiat from
	q_classifier.py) and indexes them by the utterance.
	"""
	uid_index = {}
	for decision in individuals:
		uid = decision['uid']
		dictops.add_dol(uid_index, uid, decision)
	return uid_index


_h = nice_hash.nice_hash( lambda x: x )

def vote(individuals):
	# How many in total?
	totalsc = float(len(individuals))

	# Collect data in groups of utterance id.
	idx = index(individuals)


	# First, we see what the set of classes is:
	domain = {}
	for (uid, decisions) in idx.iteritems():
		for decision in decisions:
			domain[decision['compclass']] = 0
			domain[decision['trueclass']] = 0
	# Domain.keys() is now a list of all classes that appear
	# in the input file.


	o = []
	for (uid, decisions) in idx.iteritems():
		# Scores will contain the number of times that the
		# input file showed a given class to be the computed
		# result of the first-level classifier.
		scores = domain.copy()
		trueclass = None
		for decision in decisions:
			compclass = decision['compclass']
			scores[compclass] += 1
			if trueclass is None:
				trueclass = decision['trueclass']
			else:
				assert trueclass == decision['trueclass']
		assert trueclass is not None

		# Now, we compute the class that a majority of the
		# first-level classifiers vote for:
		total = 0
		bestscore = 0
		compclass = None
		for (k, sc) in scores.items():
			total += sc
			if sc > bestscore:
				bestscore = sc
				majorityclass = k
		assert majorityclass is not None
		correctvote = scores[trueclass]

		tmp = DEFAULTS.copy()
		for (k, sc) in scores.items():
			tmp['V_%s' % k] = float(sc)/float(total)
		tmp['compclass'] = majorityclass
		tmp['trueclass'] = trueclass
		tmp['cclassid'] = _h.add(majorityclass)
		tmp['tclassid'] = _h.add(trueclass)
		tmp['vote'] = bestscore
		tmp['totalvote'] = total
		tmp['uid'] = uid
		tmp['correctvote'] = correctvote
		o.append( tmp )
	return o


if __name__ == '__main__':
	import sys
	arglist = sys.argv[1:]
	outputfile = None
	DEFAULTS = {}
	while arglist and arglist[0].startswith('-'):
		arg = arglist.pop(0)
		if arg == '--':
			break
		elif arg == 'default':
			DEFAULTS[arglist[0]] = arglist[1]
			arglist = arglist[2:]
		elif arg == '-o':
			outputfile = arglist.pop(0)
		else:
			die.die('Unrecognized argument: %s' % arg)
	fname = arglist.pop(0)
	h, d, comments = fiatio.read(open(fname, 'r'))
	correct = 0
	total = 0
	indicorrect = 0
	inditotal = 0
	votes = vote(d)
	chance = {}
	for decision in votes:
		if decision['compclass'] == decision['trueclass']:
			correct += 1
		total += 1
		indicorrect += decision['correctvote']
		inditotal += decision['totalvote']
		if decision['trueclass'] not in chance:
			chance[decision['trueclass']] = 1
		else:
			chance[decision['trueclass']] += 1

	Pcorrect = float(correct)/float(total)
	Picorrect = float(indicorrect)/float(inditotal)
	Pchance = 0.0
	for c in chance.values():
		Pchance += (float(c)/float(total))**2
	K = (Pcorrect-Pchance)/(1.0-Pchance)
	Ki = (Picorrect-Pchance)/(1.0-Pchance)
	out = {'K': K, 'Kindividual': Ki, 'Pcorrect': Pcorrect,
		'Individual': Picorrect, 'chance': Pchance,
		'total': total}

	print avio.concoct(out)
	if outputfile is not None:
		fd = open(outputfile, 'w')
		fiatio.write(fd, votes, hdr=h,
				comments=comments + ['Processed by q_classiboost'])
