#!/usr/bin/python
#encoding:utf8

__author__ = 'marlena'
from plumper.sumo.plwnpwnsumo_file import MappingFileOperator
from npsemrel.carrot.db import db
from collections import defaultdict
import collections
import argparse
import sys
import Queue


class Serdel(MappingFileOperator):
	def __init__(self, dbconnection):
		MappingFileOperator.__init__(self)
		self._plwn_sumo_rels = None
		self.dbconnection = dbconnection
		self.pos_list = [1, 2, 4]
		'''
        +-----+----------+
        | ID  | shortcut |
        +-----+----------+
        |  11 | hiper    |
        |  60 | bzn      |
        | 145 | war      |
        | 230 | sumo     |
        +-----+----------+
        '''
		self.rel_id_not_change = [60]
		self.rel_id_change = [11, 145, 230]


	def __linefunc(self, synset_id, sumo_str, sumo_rel):
		self._plwn_sumo_rels[synset_id].add((sumo_str, sumo_rel))


	def get_pos_str(self, pos):
		if pos == 1:
			#verb
			return 'v'
		if pos == 2:
			#subst
			return 'n'
		if pos == 3:
			#adv
			return 'adv'
		if pos == 4:
			#adj
			return 'a'
		if pos == 5:
			#PWN verb
			return 'PWN verb'
		if pos == 6:
			#PWN subst
			return 'PWN subst'
		if pos == 7:
			#PWN adv
			return 'PWN adv'
		if pos == 8:
			#PWN adj
			return 'PWN adj'

		return 'unknown'


	def get_list_of_synsets_without_sumo(self, is_for_all=True, not_mapped_synsets=None):
		synsets_without_sumo_dict = defaultdict(list)

		if is_for_all:
			where_part = ''
			for i in range(len(self.pos_list)):
				if i == 0:
					where_part = 'pos=' + str(self.pos_list[i])
				else:
					where_part = where_part + ' OR pos=' + str(self.pos_list[i])
		else:
			where_part = ''
			for i, item in enumerate(not_mapped_synsets):
				if i == 0:
					where_part = 'SYN.ID=' + str(item)
				else:
					where_part = where_part + ' OR SYN.ID=' + str(item)

		query = ' SELECT DISTINCT SYN.ID, SYN.unitsstr, LEX.domain, LEX.pos ' \
				' FROM synset SYN ' \
				' JOIN unitandsynset UAS ON (SYN.ID = UAS.SYN_ID) ' \
				' JOIN lexicalunit LEX ON (UAS.LEX_ID = LEX.ID) ' \
				' WHERE ' + where_part + ';'
		cursor = self.dbconnection.cursor()
		cursor.execute(query)

		for row in cursor.fetchall():
			synset_id = str(row[0])
			if not self._plwn_sumo_rels.has_key(synset_id):
				if not synsets_without_sumo_dict.has_key(synset_id):
					pos_str = self.get_pos_str(row[3])
					domain = str(row[2])
					unitsstr = row[1]
					splline1 = unitsstr.split('|')[0].split(')')[0].split('(')
					domain_str = splline1[2] + '-' + domain
					splline2 = splline1[1].replace('*','').split(' ')
					synset_str = ''
					for line in splline2:
						if line.isdigit():
							synset_str = synset_str[:-1]
							synset_str = synset_str + '.' + line
							break
						else:
							synset_str = synset_str + line + ' '
					synsets_without_sumo_dict[synset_id] = [synset_str, domain_str, pos_str]

		return synsets_without_sumo_dict


	def get_concept_list_for_synset(self, synset_id):
		where_part = ''
		for i in range(len(self.rel_id_not_change)):
			if i == 0:
				where_part = 'REL_ID=' + str(self.rel_id_not_change[i])
			else:
				where_part = where_part + ' OR REL_ID=' + str(self.rel_id_not_change[i])
		for i in range(len(self.rel_id_change)):
			where_part = where_part + ' OR REL_ID=' + str(self.rel_id_change[i])

		sumo_concept = set()

		synsets_id_queue = Queue.Queue()
		synsets_id_dict = {}

		synsets_id_queue.put(synset_id)
		synsets_id_dict[synset_id] = 0

		level_dict = {}
		level_dict[synset_id] = 0

		while not synsets_id_queue.empty():
			synset_id = synsets_id_queue.get()

			if self._plwn_sumo_rels.has_key(synset_id):
				for key in level_dict.keys():
					if level_dict[key] == level_dict[synset_id] and self._plwn_sumo_rels.has_key(synset_id):
						for synset in self._plwn_sumo_rels[key]:
							if synsets_id_dict[key] in self.rel_id_not_change:
								sumo_concept.add(synset)
							elif synsets_id_dict[key] in self.rel_id_change:
								sumo = synset[0]
								rel = 'subsumed'
								sumo_concept.add((sumo, rel))

				return sumo_concept

			query = ' SELECT PARENT_ID, REL_ID ' \
					' FROM synsetrelation ' \
					' WHERE CHILD_ID=' + synset_id + ' AND (' + where_part + ');'
			cursor = self.dbconnection.cursor()
			cursor.execute(query)

			for row in cursor.fetchall():
				if not synsets_id_dict.has_key(str(row[0])):
					synsets_id_dict[str(row[0])] = row[1]
					synsets_id_queue.put(str(row[0]))
					level_dict[str(row[0])] = level_dict[synset_id] + 1

		return sumo_concept


	def get_parents_synsets(self, synset_id):
		where_part = ''
		for i in range(len(self.rel_id_not_change)):
			if i == 0:
				where_part = 'REL_ID=' + str(self.rel_id_not_change[i])
			else:
				where_part = where_part + ' OR REL_ID=' + str(self.rel_id_not_change[i])
		for i in range(len(self.rel_id_change)):
			where_part = where_part + ' OR REL_ID=' + str(self.rel_id_change[i])


		parents_synsets = set()
		synsets_id_queue = Queue.Queue()

		synsets_id_queue.put(synset_id)
		parents_synsets.add(synset_id)

		while not synsets_id_queue.empty():
			synset_id = synsets_id_queue.get()

			query = ' SELECT PARENT_ID ' \
					' FROM synsetrelation ' \
					' WHERE CHILD_ID=' + synset_id + ' AND (' + where_part + ');'
			cursor = self.dbconnection.cursor()
			cursor.execute(query)

			for row in cursor.fetchall():
				parent_id = str(row[0])
				if not parent_id in parents_synsets:
					parents_synsets.add(parent_id)
					synsets_id_queue.put(parent_id)

		return parents_synsets


	def serdluj_z_tym(self, mapping_result_file, out_fileobj=sys.stdout,
                      is_for_all=True, not_mapped_synsets=None):
		self._plwn_sumo_rels = collections.defaultdict(set)

		self.read_mapping_file(mapping_result_file,
								(u'synset_id_plwn', u'pojecie_sumo', -1),
								self.__linefunc)

		synsets_without_sumo_dict = defaultdict(list)
		if is_for_all:
			synsets_without_sumo_dict = self.get_list_of_synsets_without_sumo()
		elif not_mapped_synsets:
			synsets_without_sumo_dict = self.get_list_of_synsets_without_sumo(is_for_all, not_mapped_synsets)


		#Zapisanie do pliku synsetow zrzutowanych bezposrednio na SUMO
		self._header.append('serdel_step')
		record_size = len(self._header)


		for i in range(len(self._linebuffer)):
			last_rel = self._linebuffer[i][-1]
			self._linebuffer[i].append(last_rel)

		self.print_contents(out_fileobj)


		#Zapisanie do pliku synsetow zrzutowanych posrednio na SUMO
		for key in synsets_without_sumo_dict.keys():
			sumo_concept = set()
			sumo_concept = self.get_concept_list_for_synset(key)
			if sumo_concept:
				for sumo in sumo_concept:
					parent_sumo = sumo[0]
					parent_sumo_rel = sumo[1]
					
					record = [None] * record_size

					#0: synset_str_plwn
					record[0] = synsets_without_sumo_dict[key][0]
					#1: dziedzina_plwn
					record[1] = synsets_without_sumo_dict[key][1]
					#2: synset_id_plwn
					record[2] = key

					#5: pwn_synset_pos
					record[5] = synsets_without_sumo_dict[key][2]

					#8: pojecie_sumo
					record[8] = parent_sumo

					#3: rel_miedzyjezykowa
					#4: synset_str_pwn
					#6: dziedzina_pwn
					#7: synset_id_pwn
					#9: rel_sumo_pwn
					#10: rel_sumo_pwn_skrot
					#11: plwn_sumo_rel
					#12:..., ..., N-1:...
					for i in range(3, 5) + range(6, 8) + range(9, record_size-1):
						record[i] = 'brak'

					#N: serdel_step
					record[-1] = parent_sumo_rel
	
					self._print(record, out_fileobj)


def main():
	argparser = argparse.ArgumentParser(description=__doc__)
	argparser.add_argument('mapping_result_file', help="csv file with " + 
														"plWN -> SUMO " + 
														"output")
	argparser.add_argument('db_config')

	args = argparser.parse_args()

	dbcon = db.DB()
	dbconnection = dbcon.connect(args.db_config)
	if not dbconnection:
		print >> sys.stderr, 'Cannot connect to DB!'
		exit(1)

	s = Serdel(dbconnection)
	s.serdluj_z_tym(args.mapping_result_file)


if __name__ == '__main__':
	main()