"""
Crowdsourcing for NLP Tutorial
NAACL 2015

Script for posting a simple paraphrase judgement HIT to MTurk
"""

import sys
import json
import csv
import random
import cgi
import time
from boto.mturk.connection import MTurkConnection, MTurkRequestError
from boto.mturk.question import QuestionContent,Question,QuestionForm,Overview,AnswerSpecification,SelectionAnswer,FormattedContent,FreeTextAnswer
from boto.mturk.qualification import Qualifications, NumberHitsApprovedRequirement, PercentAssignmentsApprovedRequirement, LocaleRequirement
import string
from xml.sax.saxutils import escape

#Parameters used for posting the HIT
ACCESS_ID= 'YOUR_ACCESS_KEY' #found on Amazon Web Services
SECRET_KEY = 'YOUR_SECRET_KEY' #found on Amazon Web Services
HOST = 'mechanicalturk.sandbox.amazonaws.com'
PHRASES_PER_HIT = 10
PRICE = 0.15
REDUNDANCY = 5
DURATION = 60*60
TITLE = "Choose good paraphrases for a phrase"
DESCRIPTION = ("Choose good paraphrases for words in a sentence.")
INSTRUCTIONS = 'input/instructions.txt'
QUALIFICATIONS = [NumberHitsApprovedRequirement('GreaterThanOrEqualTo', 50), PercentAssignmentsApprovedRequirement('GreaterThanOrEqualTo', 90), LocaleRequirement('EqualTo', 'US')]
DATA_FILE = 'input/paraphrase_input.csv'

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

#Title and instructions to display at the top of the HIT
overview = Overview()
overview.append_field('Title', TITLE)
for line in open(INSTRUCTIONS).readlines(): overview.append(FormattedContent(line.strip()))

#Restrict to workers from US and with good work history
qualifications = Qualifications()
for q in QUALIFICATIONS : qualifications.add(q)

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

#add a set of checkboxes for each sentence/groups of paraphrases to be judged
def build_question(id, pos, w, sent, pars):
	sent = ' %s '%escape(sent.replace('[[','').replace(']]',''))
	s = sent.replace(' %s '%w, ' <font color="blue"><b>' + w + '</b></font> ', 1)
	qid = '%s ||| %s ||| %s ||| %s'%(id, pos, w, sent) #use the question ID to carry around metadata so you can easily access it when you download the HIT
	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)

#Read in the data from the csv
def get_data(filename) : 
	data = []	
	for row in csv.DictReader(open(filename)): 
		data.append((row['id'], row['pos'],escape(row['phrase']),row['sentence'].strip(),sorted([escape(p) for p in row['paraphrases'].split(' XXX ')])))
	random.shuffle(data)
	return data

hit_data = get_data(DATA_FILE) 

sys.stderr.write("Posting...")
for count,hit in enumerate(batch(hit_data, PHRASES_PER_HIT)) : 
	questions = []
	for id, pos, w, sent, pars in hit : 
		questions.append(build_question(id, pos, w, sent, pars))
	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=REDUNDANCY, 
		title=TITLE, 
		description=DESCRIPTION, 
		duration=DURATION, 
		reward=PRICE)
	if count % 10 == 0 : sys.stderr.write("..")

sys.stderr.write("Done.\n")
