import random
from boto.mturk.connection import MTurkConnection
from boto.mturk.question import QuestionContent,Question,QuestionForm,Overview,AnswerSpecification,SelectionAnswer,FormattedContent
from boto.mturk.qualification import Qualifications,NumberHitsApprovedRequirement,PercentAssignmentsApprovedRequirement,LocaleRequirement
from xml.sax.saxutils import escape
from settings import settings 

#Set up a connection with MTurk 
conn = MTurkConnection(aws_access_key_id=settings['ACCESS_ID'], aws_secret_access_key=settings['SECRET_KEY'], host=settings['HOST'])

#Parameters for the HIT. For convenience, these are defined in settings.py.
title = settings['TITLE']
description = settings['DESCRIPTION']
keywords = settings['KEYWORDS']
duration = settings['DURATION']
price = settings['PRICE']

#Put a title and instructions at the top of the HIT
overview = Overview()
overview.append_field('Title', title)
for line in open(settings['INSTRUCTIONS']).readlines(): overview.append(FormattedContent(line.strip()))

#Impose qualifications on workers for this HIT, defined in settings.py
qualifications = Qualifications()
for q in settings['QUALIFICATIONS'] : qualifications.add(q)

#Utility function for batch iterating 
def batch(iterable, n = 1):
	l = len(iterable)
	for ndx in range(0, l, n): yield iterable[ndx:min(ndx+n, l)]

#Build a individual question, consisting of a phrase, a context, and a set of paraphrases to be judged
def build_question(id, pos, w, sent, pars, kp, kn):
	sent = ' %s '%escape(sent.replace('[[','').replace(']]',''))
	s = sent.replace(' %s '%w, ' <font color="blue"><b>' + w + '</b></font> ', 1)
	qid = '%s ||| %s ||| %s ||| %s ||| %s ||| %s'%(id, pos, w, sent, '|'.join(kp), '|'.join(kn))
	qc = QuestionContent()
	qc.append(FormattedContent(s.strip()))
	a = SelectionAnswer(min=1, max=1000, style='checkbox', selections=[(p,p) for p in pars] + [('None of these paraphrases are good', 'NONE')])
	return Question(identifier=qid, content=qc, answer_spec=AnswerSpecification(a), is_required=True)

#Load the data from input files (tab-separated files in input/). Control file contains two extra fields, designating the known positive controls (paraphrases that should be selected by the worker) and the known negative controls (paraphrases that should not be selected by the worker).
def get_data(filename, is_control=False) : 
	data = []	
	for line in open(filename).readlines():
		if is_control : 
			id, pos, w, pars, sent, known_pos, known_neg = line.strip().split('\t')
		else :	
			id, pos, w, pars, sent = line.strip().split('\t')
			known_pos = 'unk'
			known_neg = 'unk'
		sent = sent.strip()
		data.append((id, pos,escape(w),sent,sorted([escape(p) for p in pars.split('|||')]), 
			sorted([escape(p) for p in known_pos.split('|||')]), 
			sorted([escape(p) for p in known_neg.split('|||')])))
	random.shuffle(data)
	return data

#Load the data to be labeled, and the control data
hit_data = get_data(settings['DATA_FILE']) 
controls_data = get_data(settings['CONTROL_FILE'], is_control=True) 

for count,hit in enumerate(batch(hit_data, settings['PHRASES_PER_HIT'])) : 
	if count > settings['MAX_HITS'] : continue
	questions = []
	#create questions for paraphrases that need labeling
	for id, pos, w, sent, pars, kp, kn in hit : 
		questions.append(build_question(id, pos, w, sent, pars, kp, kn))
	#insert a gold-standard control question
	cid, cpos, cw, csent, cpars, ckp, ckn = random.choice(controls_data)
	questions.append(build_question(cid, cpos, cw, csent, cpars, ckp, ckn))
	#randomize the order
	random.shuffle(questions)

	#Create the question form
	question_form = QuestionForm()
	question_form.append(overview)
	for q in questions: question_form.append(q)
			
	#post the HIT
	conn.create_hit(questions=question_form, 
		qualifications=qualifications, 
		max_assignments=settings['REDUNDANCY'], 
		title=title, 
		description=description, 
		keywords=keywords, 
		duration=duration, 
		reward=price)
