# -*- coding: utf-8 -*-
"""
Functions needed to build window-based co-occurance data. 

Author: Bartosz Broda, bartosz.broda@gmail.com
"""
import nltk.tokenize as tokenize
import nltk.data

import  architect2.contexts as contexts 

def gen_unordered_triples(contextgen, filter_center_condition = lambda t : False, 
						filter_context_condition = lambda t : False):
	"""
	Generates all unordered triples out of a context generator (contextgen). There is a possibility
	of filtering of triples by using a filter (center_condition). Tokens in context can be filtered in similar
	way (context_condition)

	Triples returned are tuples of the form:
	(center_token, u'UNORDERED', token_in_context)
	or alternative definition:
	(head, relation, modifier), where relation is UNORDERED
	
	>>> tokens = ['A', 'b', 'C', 'd']
	>>> center_cond = lambda t : t == 'b'
	>>> right_cond = lambda t : t == 'C'
	>>> gen = gen_unordered_triples(contexts.window.window_contexts_generator(tokens, 3,2), center_cond, right_cond)
	>>> gen.next()
	('A', u'UNORDERED', 'b')
	>>> gen.next() 
	('C', u'UNORDERED', 'A')
	>>> gen.next()
	('C', u'UNORDERED', 'b')
	>>> gen.next()
	('C', u'UNORDERED', 'd')
	>>> gen.next() 
	('d', u'UNORDERED', 'A')
	>>> gen.next()
	('d', u'UNORDERED', 'b')
	>>> gen.next()
	Traceback (most recent call last):
	...
	StopIteration
	"""
	for (left, center, right) in contextgen:
		if filter_center_condition(center):
			continue
		for elem in left:
			if not filter_context_condition(elem):
				yield (center, u'UNORDERED', elem)
		for elem in right:
			if not filter_context_condition(elem):
				yield (center, u'UNORDERED', elem)

def gen_ordered_triples(contextgen, filter_center_condition = lambda t : False, 
					filter_context_condition = lambda t : False):
	"""
	Generates all unordered triples out of a context generator (contextgen). There is a possibility
	of filtering of triples by using a filter (center_condition). Tokens in context can be filtered in similar
	way (context_condition)

	Triples returned are tuples of the form:
	(center_token, DISTANCE, token_in_context), 
	where distance is a string telling how far token_in_context is from center_token
	or alternative definition:
	(head, relation, modifier), where relation is named after the distance
	
	>>> tokens = ['a', 'b', 'c', 'd']
	>>> center_cond = lambda t : t == 'b'
	>>> right_cond = lambda t : t == 'c'
	>>> gen = gen_ordered_triples(contexts.window.window_contexts_generator(tokens, 3,2), center_cond, right_cond)
	>>> gen.next()
	('a', '1', 'b')
	>>> gen.next()
	('c', '-2', 'a')
	>>> gen.next()
	('c', '-1', 'b')
	>>> gen.next()
	('c', '1', 'd')
	>>> gen.next()
	('d', '-3', 'a')
	>>> gen.next()
	('d', '-2', 'b')
	>>> gen.next()
	Traceback (most recent call last):
	...
	StopIteration
	"""
	for (left, center, right) in contextgen:
		if filter_center_condition(center):
			continue
		for i, elem in enumerate(left):
			if not filter_context_condition(elem):
				yield (center, str(-(len(left)-i)), elem)
		for i, elem in enumerate(right):
			if not filter_context_condition(elem):
				yield (center, str(i+1), elem)
				

def gen_sentence_context_triples(text, triples_gen, 
								context_gen = contexts.window.window_contexts_generator, 
								tokenizer = tokenize.WordPunctTokenizer().tokenize):
	"""
	Generates triples using embedded triples_generator and context generator, out of _sentences_ in given text.
	
	Arguments:
	- text - a text to process
	- triples_gen - a function that takes a context_gen and returns a generator of triples; 
	  for example it can be: lambda x : gen_ordered_triples(x, filter, filter) with some
	  filter from filters.    
	- context_gen - a generator of contexts out of token lists, f.e., 
	  contexts.gen_contexts
	- tokenizer - a function that will tokenize text in sentence
	
	>>> from architect2 import filters
	>>> filter = filters.eng_textmining()
	>>> text = 'Anarchism is a political philosophy. That sentence was taken from Wikipedia.'
	>>> trigen = lambda x : gen_ordered_triples(x, filter, filter)
	>>> generator = gen_sentence_context_triples(text, trigen) 
	>>> generator.next()
	('Anarchism', '3', 'political')
	>>> generator.next()
	('political', '-3', 'Anarchism')
	>>> generator.next()
	('political', '1', 'philosophy')
	>>> generator.next() 
	('philosophy', '-1', 'political')
	>>> generator.next() 
	('sentence', '2', 'taken')
	>>> generator.next()
	('taken', '-2', 'sentence')
	>>> generator.next()
	('taken', '2', 'Wikipedia')
	>>> generator.next()
	('Wikipedia', '-2', 'taken')
	>>> generator.next()
	Traceback (most recent call last):
	...
	StopIteration
	"""

	# resources are cached by default in nlt
	punkt = nltk.data.load('tokenizers/punkt/english.pickle')

	for sentence in punkt.tokenize(text):# pylint: disable-msg=E1103, E0011 
		tokens = tokenizer(sentence.strip())
		generator = triples_gen( context_gen(tokens) )
		for t in generator:
			yield t
			
if __name__ == '__main__':
	import doctest
	doctest.testmod()
