#!/usr/bin/python
# -*- coding: utf-8 -*-


import codecs, sys, pprint
import pyplwn, pymatrices, pycomparator, wnext

bash_red = '\033[31m'
bash_green = '\033[32m'
bash_blue = '\033[36m'
bash_default = '\033[0;0m'
have_bash = True

def colorize(color, text):
	if not have_bash: return text
	else: return color + text + bash_default

class RWFFilter:
	def __init__(self, db, cmp, treshold = 0.08, is_sim_matix = False,flex = u'subst'):
		self.sim_matrix = is_sim_matix
		self.cmp = cmp			
		self.db = db
		self.flex = flex + u':'
		self.retrive_words()
		self.treshold = treshold
		self.lemmas4synset_id = db.Synsets.get_units_lemma_for_synsets_id()
		self.graph = pyplwn.wngraph.WNGraph([db.Relations.get_relation_by_name('hiperonimia'),db.Relations.get_relation_by_name('hiponimia') ], db, False)
		
	def re_score_words(self):
		new_data = {}
		max = len(self.words)
		no = 0
		for word in self.words:
			no += 1
			result = self.count_new_score(word)

			for r in result:
				synset_id = r[0]
				new_score = r[2]

				if word in new_data:
					new_data[word].append( (synset_id, new_score) )
				else:
					new_data[word] = [ (synset_id, new_score) ]
			if no % 100 == 0:
				print "Rescoreing %s / %s " %(no, max)
		return new_data

	def count_new_score(self, word):
		synsets = self.words[word]
		result = []
		for synset_id,score in synsets:
			sim_center = self.min_sim(word, synset_id)
			len1, len2 = self.get_synsets_len12(synset_id)
			
			len1_score = self.avg_score(word, len1)
			len2_score = self.avg_score(word, len2)
			
			if sim_center == sys.maxint:
				sim_center = 0
			
			new_score = sim_center + 0.5 * len1_score + 0.25 * len2_score 
			result.append( (synset_id, score, new_score, sim_center, len1_score, len2_score) )
			
		return result

	def count_score(self, word, center_sysnest_id):
		sim_center = self.min_sim(word, center_sysnest_id)
		len1,len2 = self.get_synsets_len12(center_sysnest_id)
		len1_score = self.avg_score(word, len1)
		len2_score = self.avg_score(word, len2)
		if sim_center != sys.maxint:
			return sim_center + 0.5 * len1_score + 0.25 * len2_score
		return 0.0
			
	
	def message_one(self, result, word):
		best_id = -1
		max = -10000
		print colorize(bash_green, word)
		
		for r_no in xrange( len(result) ):
			r = result[r_no]
			if r[2] > max:
				best_id = r_no
				max = r[2]
				
		for r_no in xrange( len(result) ):
			r = result[r_no]
			synset = "{"
			for s in self.lemmas4synset_id[r[0]]:
				synset += s + ", "
			synset += "}"
			
			message = "\t%s, Old: %s, New: %s (%s,%s,%s)" % (synset, r[1],r[2],r[3],r[4],r[5])
			if r_no == best_id:
				message = colorize(bash_red, message)
			elif r[2] > self.treshold:
				message = colorize(bash_blue, message)
			
			print message
		
	def get_synsets_len12(self, synset_id):
		len1 = set([])
		len2 = set([])
		
		for edge_1 in self.graph.graph.edges(synset_id):
			len1.add(edge_1[1])

			for edge_2 in self.graph.graph.edges(edge_1[1]):
				len2.add(edge_2[1])
		len2.difference_update(len1.union([synset_id]))

		return (len1, len2)
		
	
	def avg_score(self, word, synsets):
		score = 0.0
		no = 0
		for syn_id in synsets:
			min_sim = self.min_sim(word, syn_id)
			if min_sim != sys.maxint:
				no += 1
				score += min_sim
		if no == 0: return 0
									
		return score / no
	
	def retrive_words(self):
		print "Retriving words from database..."		
		query = "SELECT word,synid,score1 FROM extgraph ORDER BY word"
		self.words = {} # word -> synset, score
		self.db.cursor.execute(query)
		for row in self.db.cursor:
			word = row[0].decode('utf-8')
			synset_id = row[1]
			score = row[2]		
			if word in self.words:
				self.words[word].append( (synset_id, score) )
			else:
				self.words[word] = [(synset_id, score)]
			
		print "Retriving words from database... Done."

	def min_sim(self,word, synset):
		minsim = sys.maxint
		if not self.lemmas4synset_id.has_key(synset):
				return minsim
			
		if self.sim_matrix:
			w1 = ( self.flex + word ).encode('utf8')
			w1_ind = self.cmp.GetRowIndex(w1)
			if w1_ind > self.cmp.NumberOfRows():
				return minsim
			row = self.cmp.GetRow(w1_ind) 
			for w in self.lemmas4synset_id[synset]:				
				w2 = (self.flex + w.decode('utf-8')).encode('utf8')
				
				w2_id = self.cmp.GetRowIndex(w2)
				if w2_id < self.cmp.NumberOfRows():
					sim = row.GetElement(w2_id)
					if sim > 0:
						minsim = sim
		else:
			for w in self.lemmas4synset_id[synset]:
				w1 = self.flex + word
				w2 = (self.flex + w.decode('utf-8'))
				sim = self.cmp.Compare(w1.encode('utf'), w2.encode('utf') )
				if sim < minsim and sim > 0:
					minsim = sim
		return minsim

	def find_best_synset(self, word):
		all_synsets_id = self.db.Synsets.get_all_synsets_id()
		score_table = {}# score -> synset_ids
		processed = 0
		for synset_id in all_synsets_id:
			score = self.count_score(word, synset_id)
			if score > 0.0:
				if score in score_table:
					score_table[score].add(synset_id)
				else:
					score_table[score] = set([synset_id])
			processed+=1
			if not self.sim_matrix and processed % 100 == 0:
				print "Processing %s of %s for %s" % ( processed, len(all_synsets_id), word )

		return score_table
	
	def add_rwf_to_db(self):
		new_data = {}
		all = len(self.words)
		no = 0
		for word in sorted(self.words):
			if 'rwf' in word : continue
			score = self.find_best_synset(word)
			best_scores = sorted(score.keys())
			added = 0
			to_add = []
			for val in reversed(best_scores):
				if val < self.treshold:
					added = 100
					break
				weak = 1
				if val < 0.3: weak = 2
				synsets = score[val]
				for synset in synsets:
					added += 1
					to_add.append( (val, synset, weak, val) )	
				if added > 5:
					break
			new_data[word+"-rwf"] = to_add
			
			no+=1
#			if no % 1 == 0:
			print "Processing word %s / %s (%s) " % (no, all, word)
			if no % 20 == 0: 
				print colorize(bash_green, "Adding data to db...") 	
				dbw = wnext.DBWorker(self.db)
				if not dbw.has_lock:
					dbw.aquire_lock()
				dbw.refresh_data(new_data, None, False)
				dbw.release_lock()
				new_data = {}
				print colorize(bash_green, "Done...")
		
				
					
def add_score2_to_db(filter):
	print colorize(bash_green, "Re-scoring synsets...")
	data = filter.re_score_words()
	print colorize(bash_green, "Updating db.")
	query = "LOCK TABLES extgraph WRITE;" 
	filter.db.cursor.execute(query)
	#reporting stuff
	max = float( len(data) )
	no = 0
	last_proc = 0

	for word in data:
		for synset_id, score2 in data[word]:
			query = "UPDATE extgraph SET score2 = %f WHERE word = '%s' AND synid = %d" % ( score2, word, synset_id ) 
			filter.db.cursor.execute(query)
		#report progress
		no += 1
		if progress_report != None:
			proc =  int ( ( float(no) / max ) * 100)
			if last_proc != proc:
				print "%d%%" % proc
				last_proc = proc
	query = "UNLOCK TABLES;" 
	filter.db.cursor.execute(query)
	filter.db.connection.commit()


		
if __name__ == '__main__':
	mdir = '/mnt/data/workdir/macierze/supermatrix2/noun/polaczone/similarity/'
	mname = 'kipi_knigi_rzepa_subst_AdjP_AmISubj_Coord_NGen_rwf'
	#mdir = '/home/boban/pwr/workdir/supermatrix2/polaczone/sim/'
	#mname = 'kipi_knigi_rzepa_subst_AdjP_AmISubj_Coord_NGen_rwf'
	#mdir = '/mnt/pwr/workdir/supermatrix2/polaczone/'
	#mname = 'rzepa_subst_AdjP_AmISubj_Coord_NGen_pq'
	#mdir = '/home/boban/data/workdir/macierze/supermatrix2/noun/polaczone'
	#mname = 'kipi_knigi_rzepa_substAdjP_AmISubj_Coord_NGen_pq'
	#mdir = '/home/boban/data/workdir/macierze/supermatrix2/noun'
	#mname = 'kipi_substAdjP_pq'

	print colorize(bash_green, "Preparing data...")
	
	matrix = pymatrices.LoadSuperMatrix(mdir, mname, False, True)	
	#cmp = pycomparator.FunctionFactory.\
	#   CreateFunction("rwf_tscore(rank_size=10000,min_cdf_p=0.9999,uniform_rank=false)", matrix, mdir)	
	db = pyplwn.database.Database('plwn','plwn','localhost','plwn')
	#db = pyplwn.database.Database(user = "wordnet_dev", passwd = "w0rdn3tDBP@sswd", host = "156.17.129.178", db = "wordnet_developer", port = 3308, encoding = "utf8")
	
	#filter = RWFFilter(db, cmp)
	filter = RWFFilter(db, matrix, 0.1, True)
		
	print colorize(bash_green, "Data prepared.")
	
	filter.add_rwf_to_db()
	#add_score2_to_db(filter)

#	words = [u'abonament', u'absolwentka', u'czekolada', u'oszust', u'pająk', u'pensjonat', u'epizod', u'miesięcznik', u'planeta', u'pokaz'	, u'popis', u'poprawka']
#	scores = []
#	for w in words:
#		print "Finding words for", w
#		scores.append( ( w, filter.find_best_synset(w) ) )
#	
#	file = codecs.open('testslow.txt', 'w', 'utf8')
#
#	for w,score in scores:
#		best_scores = sorted(score.keys())
#		print colorize(bash_blue, w)
#		file.write(w + ":\n")
#		printed = 0
#		for val in reversed(best_scores):
#			synsets = score[val]
#			print "\t",val,";",
#			file.write("\t" + str(val) + "; ")
#			for synset in synsets:
#				synset_str = u"{"
#				for s in filter.lemmas4synset_id[synset]:
#					synset_str += s.decode('utf8') + u", "
#				synset_str += u"}"
#				print synset_str
#				file.write(synset_str + '\n')
#			printed += 1
#			if printed > 8:
#				break
#	file.close()


	
#	for w in words:
#		results = filter.count_new_score(w)
#		filter.message_one(results, w)

	
	
