#!/usr/bin/env python

# qpa.py
# based on simpleSQL.py example for using pyparsing to parse the SQL queries
# simpleSQL.py does not handle UNION, INTERSECT, EXCEPT or nested SQLs
# It also does not handle mathematical or other expressions in the filter conditions (eg. WHERE AGE = 2 * 18)
#
# ankesh

import sys
from traceback import print_exc
from time import localtime, strftime
from getopt import getopt
from csv import reader
from httplib import HTTPConnection
from urllib import urlencode

from pyparsing import alphanums, alphas, Keyword, Optional, ParseException, Word
from simpleSQL import simpleSQL
from tmswap.llyn import RDFStore
from tmswap.policyrunner import runPolicy

NONEXAMHARNESSMODE = False
globalusername = ""

qpa_namespace = "http://dig.csail.mit.edu/2009/IARPA-PIR/test/qpa#"
default_namespace = "http://dig.csail.mit.edu/2009/IARPA-PIR/test/qpa-query#"
apprelations =  ["http://dig.csail.mit.edu/2009/IARPA-PIR/test/app-relations.n3"]
#list of properties to be filtered, passed to the AIR reasoner 
filterProperties = ['http://dig.csail.mit.edu/TAMI/2007/amord/air#compliant-with', 
		'http://dig.csail.mit.edu/TAMI/2007/amord/air#non-compliant-with'
		#'http://dig.csail.mit.edu/2009/IARPA-PIR/test/qpa#related',
		#'http://dig.csail.mit.edu/2009/IARPA-PIR/test/qpa#notContradictory',
		#'http://dig.csail.mit.edu/2009/IARPA-PIR/test/qpa#contradictory'
]

#Rules for transitiveness and reflexiveness of qpa:prevQuery are in prevquery.n3
prevqueryrules = "file:///home/ankesh/SUT/policies/prevquery.n3"

#rdf representation of SQL queries are stored in this directory
queryLogsDir = "/home/ankesh/SUT/querylogs/"

#web directory to access files stored in 'queryLogsDir' on the web
#queryLogsBaseUri = "http://air.csail.mit.edu/queries/"

#read policy files associated with users from a 
## csv file. (username, file1, file2, file3..)
## rdf file. ({:userid air:policy :file1, :file2 ... })
#userPolicyAssocFile = "file:///home/ankesh/codes/python/policies.csv" 

#reasons for decisions (ALLOWED, DENIED) are stored here :
## justification returned by AIR reasoner.
## parsing error or any other errors.
reasonsDir = "/home/ankesh/SUT/reasons/"

#web directory to access files stored in 'reasonsDir' on the web
reasonsBaseURL = "file:///home/ankesh/SUT/reasons/"

#contains dictionary for tables (table, col1, col2, ....)
dbDictionary = "file:///home/ankesh/SUT/db_dictionary.csv"

#log of queries consided in 1 session are logged. 
## multiple sessions are separated by session start time stamps
sessionQueriesLog = "/home/ankesh/SUT/logs/executed.dryrun"

#Since exam policy harness expects only 1 line output, AIR reasoner dumps are diverted to this file
## The file is opened in 'w' mode (not 'a', unlike 'sessionQueriesLog')
policyRunnerOut = "/home/ankesh/SUT/logs/policyrunner.out"

errorLog = "/home/ankesh/SUT/logs/errorlog"

#expression for parsing 'TABLE.COLUMN' 
tableDotColumn = Word(alphas, alphanums) + Optional("." + Word(alphas, alphanums))
#expression for parsing 'user userid'
userName = Keyword("user", caseless=True) + Word(alphanums + "/:.-")

columnsOfTables = dict() # {'table': ['col1', 'col2'...], ...}
columnTypes = dict() # {'table' : {'col1':<number or string>, ...}, ...}

def formattedLocalTime() :
    	return strftime("%a, %d %b %Y %H:%M:%S + 0530", localtime())

def getPrefixDeclarations() :
	global qpa_namespace, default_namespace
	n3string="#$ Generated by code $\n"
	n3string+="#$ at %s $\n"%formattedLocalTime()
	n3string+="\n@prefix math: <http://www.w3.org/2000/10/swap/math#> ."
	n3string+="\n@prefix string: <http://www.w3.org/2000/10/swap/string#> ."
	n3string+="\n@prefix qpa: <%s> ."%qpa_namespace
	n3string+="\n@prefix : <%s> .\n"%default_namespace
	return n3string

def populateTableDescs() :
	global columnsOfTables, columnTypes
	if columnsOfTables <> {} : return
	if dbDictionary.endswith(".csv") :
		filename = dbDictionary.replace("file://","")
		lines = reader(open(filename), delimiter = ',', quotechar='|')
		for row in lines :
			table = ""
			columns = []
			for string in row :
				if table : columns.append(string.upper())
				else : table = string.upper()
			columnsOfTables[table] = columns
	else :
		#TODO - db dictionary described in rdf
		pass

def populateColumnTypes() :
	global columnTypes
	#TODO - 
	columnTypes = dict()

def setColumnType(table, column, type) :
	global columnTypes
	if not table : return
	if table not in columnTypes : columnTypes[table] = {column : type}
	elif column not in columnTypes : columnTypes[table].update({column : type })
	else : pass

userPolicies = dict() # {'userid': [file1, file2 ...], ...}

def separateTableColumn(string, tables) :
        tokens = tableDotColumn.parseString(string)
        if len(tokens) == 3 :
                return (tokens[0], tokens[2])
        else :
                if len(tables) == 1 :
                        return (tables[0], tokens[0])
                else :
                        return (None, tokens[0]) #TODO

def getOperatorUri(table, column, operator, value) :
	global mapNumericOperators, mapStringOperators, columnTypes
	if table in columnTypes and column in columnTypes[table] :
		return mapNumericOperators[operator] if columnTypes[table][column] == 'number' else mapStringOperators[operator]	
	if isNumeric(value) : 
		setColumnType(table, column, 'number')
		return mapNumericOperators[operator]
	elif isQuotedString(value) : 
		setColumnType(table, column, 'string')
		return mapStringOperators[operator]
	elif not (operator in mapStringOperators) : 
		setColumnType(table, column, 'number')
		return mapNumericOperators[operator]
	#TODO :TABLE1.COLx (=|<>) TABLE2.COLy type filter condition. decide operator based on type(COLx) or type(COLy)
	#current approach is flawed
	else : 
		return mapStringOperators[operator]
	
def isNumeric(value) :
	try:
		float(value)
		return True
	except: 
		return False	

def isQuotedString(value) :
	return (value.startswith('"') and value.endswith('"'))

mapStringOperators = {"=":"string:matches", "!=":"string:notMatches", "<>":"string:notMatches"}
mapNumericOperators = {"=":"math:equalTo", "!=":"math:notEqualTo", "<>":"math:notEqualTo", ">":"math:greaterThan", "<":"math:lessThan", ">=":"math:notLessThan", "=>":"math:notLessThan", "<=":"math:notGreaterThan", "=<":"math:notGreaterThan"}

filterConditionIds = dict() #key = (lhs, op, rhs) where filter condition is 'lhs op rhs'

def getRDFofSQL(user, queryId, prevQueryId, query) :
    global columnsOfTables, filterConditionIds, mapStringOperators, mapNumericOperators
    ERROR = True
    try:
	presuf = ("<",">") if (user.startswith("http://") or user.endswith("file://")) else ('"','"')
	user = presuf[0] + user + presuf[1]
	n3query = '\n%s a qpa:Query ;\n'%queryId
	n3query += '	qpa:user %s ;\n'%user
	n3query += '	qpa:prevQuery %s ;\n'%prevQueryId if prevQueryId else ""
	#n3query += '	qpa:prevQuery %i ;\n'%queryId
        tokens = simpleSQL.parseString(query.replace('"', "'"))

	columns = tokens.columns if tokens.columns <> "*" \
		  else reduce(list.__add__, [columnsOfTables[table] for table in tokens.tables], [])
	
	n3fields = ""	
	for column in columns :
		(table, col) = separateTableColumn(column, tokens.tables)
		n3fields += "," if n3fields else "	qpa:field"
		if table :
			n3fields += '\n		[ qpa:table "%s" ;'%table
			n3fields += '\n		  qpa:column "%s" ]'%col
		else :
			n3fields += '\n		[ qpa:column "%s" ]'%col

	n3fields += " ;\n" if columns else ""
	n3fromtables = ""		
	for table in tokens.tables :
		n3fromtables += ', "%s"'%table if n3fromtables else '	qpa:fromTable "%s"'%table
	n3fromtables += " ;\n" if tokens.tables else ""
	
	if len(tokens.where)>1: 
		return ERROR, "Parse Exception %s\nQUERY = %s\nUnexpected expression in Where Clause : %s"%(formattedLocalTime(), query, tokens.where[1])
	
	n3whereconditions = ""
	conditionIdsList = ""
	conditionNum = 0
	n3aggrConditions = ""
	#num_of_filters = len(tokens.where[0]) / 2
	
	for condition in tokens.where[0] :
		if isinstance(condition, str) :
			COND = str(condition).upper()
			if COND == "WHERE" : pass
			elif COND == "AND" : pass
			elif COND == "OR" : pass #"OR" is, for now, treated as "AND"
			else : return ERROR, "Parse Exception %s\nQUERY = %s\nUnexpected Boolean Operator '%s'"%(formattedLocalTime(), query, str(condition).upper())
		else :
			if len(condition)<>3 or condition[1] == 'IN':  
				return ERROR, "Parse Exception %s\nQUERY = %s\nUnexpected Filter condition in where clause: %s"%(formattedLocalTime(), query, str(condition))
			conditionNum += 1
			attribute = condition[0]
			reloperator = condition[1]
			value = condition[2]
			(table, col) = separateTableColumn(attribute, tokens.tables)
			isNumber = isNumeric(value)
			reloperator = getOperatorUri(table, col, reloperator, value)
			key = ()
	
			n3condition = "	qpa:attribute\n"
			if table :
				n3condition += '		[ qpa:table "%s" ;\n'%table
				n3condition += '	  	  qpa:column "%s" ] ;\n'%col
				key += (table, col)
			else :
				n3condition += '		[ qpa:column "%s" ] ;\n'%col
				key += (col,)
			
			n3condition += "	qpa:relOperator %s ;\n"%reloperator
			key += (reloperator,)
			if isNumber :
				n3condition += "	qpa:value %s .\n"%str(value)
				key += (value,)
			else :
				value = value.replace("'", '"')		
				if isQuotedString(value) : #color = 'red' 
					n3condition += "	qpa:value %s .\n"%value
					key += (value,)
				else : #object.color = thing.color
					(table, col) = separateTableColumn(value, tokens.tables)
					n3condition += "	qpa:attribute-2\n"
					if table :
						n3condition += '		[ qpa:table "%s" ;\n'%table
						n3condition += '  		  qpa:column "%s" ] .\n'%col
						key += (table, col)
					else :
						n3condition += '		[ qpa:column "%s" ] .\n'%col	
						key += (col,)
			
			filterConditionId = ""
			if key in filterConditionIds: 
				filterConditionId = filterConditionIds[key]
			else :
				filterConditionId = "%s-filter-%i"%(queryId, conditionNum)
				filterConditionIds[key] = filterConditionId
				n3condition = '%s a qpa:FilterCondition ;\n'%filterConditionId + n3condition
				n3aggrConditions += "\n" + n3condition
		
			n3whereconditions += (", " if n3whereconditions else "	qpa:filterCondition ") + filterConditionId

                        if conditionIdsList :  conditionIdsList += " "
                        conditionIdsList += filterConditionId
			
			#n3condition = filterConditionId + " a qpa:FilterCondition ;\n" + n3condition
			#n3aggrConditions += "\n" + n3condition
	
	if n3whereconditions : 
		n3whereconditions += " ;\n"                  
	conditionIdsList = "(" + conditionIdsList + ")"
	n3query += n3fields + n3fromtables + n3whereconditions
	n3query += "	qpa:filterConditionsList %s .\n"%conditionIdsList
	n3query += n3aggrConditions
	
	return not ERROR, n3query
    except ParseException, err:
	return ERROR, "Parse Exception %s \n QUERY = %s\n"%(formattedLocalTime(), query)\
		+ " "*err.loc + "^\n%s\n%s"%(err.msg, str(err))
	
foafPrimaryTopics = dict()

def dealWithError(msg, reasonfilename) :
	global errorLog, reasonsDir, reasonsBaseURL, NONEXAMHARNESSMODE
	if NONEXAMHARNESSMODE : 
		print_exc()
		print msg	
	
	f_errorlog = open(errorLog, 'a')
	f_reason = open(reasonsDir + reasonfilename, "w")
	f_errorlog.write(msg)
	f_errorlog.close()
	f_reason.write(msg)
	f_reason.close()
	sys.stdout.write('DENIED ' + reasonsBaseURL + reasonfilename)
	sys.stdout.flush()
	if NONEXAMHARNESSMODE : print ""

def getFoafPrimaryTopic(foaf, formula) :
	global foafPrimaryTopics, globalusername
	ERROR = True
	if foaf in foafPrimaryTopics : 
		return not ERROR, foafPrimaryTopics[foaf]
	try : 
        	topic = formula.newSymbol("http://xmlns.com/foaf/0.1/primaryTopic")
        	statements = formula.statementsMatching(pred = topic)
        	OBJ = 3
        	for s in statements :
			globalusername = str(s[OBJ])
			foafPrimaryTopics[foaf] = s[OBJ].uriref()
			return not ERROR, foafPrimaryTopics[foaf]
	except IOError, err :
		return ERROR, "Error in Getting the FOAF Primary Topic %s.\n FOAF FILE = %s.\n%s"%(formattedLocalTime(), foaf, err)

def getUserAndPolicies(foaf) :
	global userPolicies, foafPrimaryTopics
	ERROR = True
	if foaf in userPolicies :
		return not ERROR, foafPrimaryTopics[foaf], userPolicies[foaf]
	
	policies = [foaf]
	try :
		store = RDFStore()
		formula = store.load(foaf)
		err, user = getFoafPrimaryTopic(foaf, formula)
		if err: return Error, user, None
		(SUBJ, PRED, OBJ) = (2, 1, 3)
		includepolicy = formula.newSymbol("http://dig.csail.mit.edu/TAMI/2007/amord/air#include-policy-file")
		morepolicies = [s[OBJ].uriref() for s in formula.statementsMatching(pred = includepolicy)]
		while morepolicies != [] :			
			policies.extend(morepolicies)
			store = RDFStore()
			formula = store.loadMany(morepolicies)
			morepolicies = [s[OBJ].uriref() for s in formula.statementsMatching(pred = includepolicy)]
			morepolicies = list(set(morepolicies) - set(policies))
		return not ERROR, user, policies
	except IOError, err :
		return ERROR, "Error in getting 'include-policy' %s.\n FOAF FILE = %s. \n%s"%(formattedLocalTime(), foaf, err), None

	'''policylookup = userPolicyAssocFile
	if policylookup.endswith(".csv") :
		filename = policylookup.replace("file://", "")
		lines = reader(open(filename), delimiter=',', quotechar='|')
		for row in lines :
			userknown = False
			policies = []
			for string in row :
				if userknown :
					policies.append(string)	 	
				else :					
					if string == user : userknown = True
					else : break
			if userknown :
				userPolicies[user] = policies
				return userPolicies[user]
	else :
		store = RDFStore()
		policylookup = user #assumption user is identified by foaf file
		f = store.load(policylookup)
		policy = f.newSymbol('http://dig.csail.mit.edu/TAMI/2007/amord/air#policy')
		policies = []
		OBJ = 3
		for s in f.statementsMatching(pred = policy) :
			policies.append(str(s[OBJ]))
		userPolicies[user] = policies
		return userPolicies[user]'''

def getPolicyDecision(baseDir, filename) :
	global reasonsBaseURL
	#NO NON-COMPLIANT TRIPLE ASSERTION ==> COMPLY.
	#i.e. (SEQUENCE) QUERY IS NON-COMPLIANT ONLY IF THERE IS ONE NON-COMPLIANT ASSERTION
	store = RDFStore()
	f = store.load(baseDir + filename)
	comply = store.newSymbol('http://dig.csail.mit.edu/TAMI/2007/amord/air#compliant-with')
        noncomply = store.newSymbol('http://dig.csail.mit.edu/TAMI/2007/amord/air#non-compliant-with')
	(SUBJ, PRED, OBJ) = (2, 1, 3)

	statements = f.statementsMatching(pred = noncomply)
	out = ("DENIED" if statements else "ALLOWED") + " " + reasonsBaseURL + filename + "\n\r"
	#for s in statements : out += "\n %s does not comply with"%(str(s[SUBJ]), str(s[OBJ]))
	#out +=  "Reasons " + reasonsBaseURL + filename
	return out

executeNum = -1
queryNum = -1

def processQueries(SQLQueries, user) :
	global executeNum, queryNum, queryLogsDir, NONEXAMHARNESSMODE
	global globalusername
	policies = None

	if not user : return
	if user.startswith("http://") or user.startswith("file://") :
		err, user, policies = getUserAndPolicies(user) 
		rdfofsqlfilename = "rdfofsql-%s-%i.n3"%(globalusername, executeNum)
		reasonfilename = "dryrun.sql-%s-%i.dmp"%(globalusername, executeNum)
		#when foaf file contains references to policy files are web retrievable. {foaf#me air:policy :Policy-name}
		# not used under current scheme
	        #policies = [user] #foaf file contains the policies
		# qpa:user value in policy must be the same as foaf:primaryTopicpolicy
		#err, user = getFoafPrimaryTopic(user)
		if err :
			dealWithError(user, reasonfilename)
			return
	else : pass
		#not used under current scheme
		#policies = getUserPolicies(user)
		
	
	#if not policies : print "There are no policies associated with the user. Therefore the SQL queries are GOOD (by default)!"
	
	queries = []
	n3string = getPrefixDeclarations()
		
	for query in SQLQueries :
		n3string += "\n# %s"%query
		queryNum += 1
		queryId = ":query-%i"%queryNum
		prevQueryId = queries[len(queries)-1] if len(queries)>0 else None
		queries.append(queryId)
		err, rdfofsql = getRDFofSQL(user, queryId, prevQueryId, query)
		if not err : 
			n3string += "\n " + rdfofsql
		else :
			queries.pop()
			dealWithError(rdfofsql, reasonfilename)
			return #may opt to continue. for that change dealWithError
	
	try :	
		if NONEXAMHARNESSMODE : print n3string
		file = open(queryLogsDir + rdfofsqlfilename, "w")
		file.write(n3string)
		file.close()
	except IOError, err: 
		print err
	#print n3string
	global apprelations, prevqueryrules, filterProperties, reasonsDir
	logURIs = ["file://%s%s"%(queryLogsDir,rdfofsqlfilename)]
	logURIs.extend(apprelations)
	policies.append(prevqueryrules)
	#print logURIs, policies, filterProperties
	saveout = sys.stdout  # to divert AIR reasoner's output
	try : 
		sys.stdout = open(policyRunnerOut, "w")
	except IOError, err: 
		print err

	#runPolicy returns empty justification, doesn't ever throw exception
	justification = ""
	try :
		store = RDFStore()
	        trace, result = runPolicy(logURIs, policies, filterProperties = filterProperties, store = store)
		justification = trace.n3String()
	except Exception, err : 
		msg = "AIR reasoner found an error %s\nSQL QUERIES = %s\n%s"%(formattedLocalTime(), str(SQLQueries), err)
		dealWithError(msg, reasonfilename)
	#	sys.stdout = saveout
		return
	
	sys.stdout = saveout
	"""		
	#for web connection
	conn = HTTPConnection("mr-burns.w3.org", "80")
	resource = "/cgi-bin/air_2_0.py?logFile="+queryLogsBaseUri + rdfofsqlfilename
	resource += "&rulesFile=" + prevqueryrules
	for policy in policies : resource += "&rulesFile="+policy.strip()
	conn.request("GET", resource)
	response = conn.getresponse()
	data = response.read()
	conn.close()
	"""
	#print justification
	if NONEXAMHARNESSMODE : print justification
	try :	
		file_reason = open(reasonsDir + reasonfilename, "w")
		file_reason.write(justification)
		file_reason.close()
	except IOError, err :
		print err
	
	sys.stdout.write(getPolicyDecision("file://" + reasonsDir, reasonfilename))
	sys.stdout.flush()
	if NONEXAMHARNESSMODE : print ""
	
		
def runSession() :
	global executeNum, filterConditionIds, sessionQueriesLog
        populateTableDescs()
	#populateColumnTypes()
        user = None
        SQLQueries = []
	file = open(sessionQueriesLog, "a")
	print >> file, "NEXT SESSION : %s"%formattedLocalTime()
        done = False
        while not done :
		sys.stdout.write('\n\r>> ')
		sys.stdout.flush()
                command = "" 
		while not command: command = sys.stdin.readline().strip()
		print >> file, "command", command
		COMMAND = command.upper()
                if COMMAND.startswith("SELECT") : SQLQueries.append(command)
                elif COMMAND == "EXECUTE" :
			executeNum += 1
                        processQueries(SQLQueries, user)
			SQLQueries = []
			filterConditionIds = dict() 
                elif COMMAND.startswith("USER"): user = userName.parseString(command)[1]
		elif COMMAND == "DONE": done = True
		else : print >> file, "IGNORED LAST COMMAND. First word not in ('USER', 'SELECT', 'EXECUTE', 'DONE')"

t_input = dict()

def test(testtype, testid) :
	global t_input, filterConditionIds
	if testtype not in t_input : 
		print "WRONG TESTTYPE"
		return
	if not testid :
		for id in t_input[testtype] : 
			test(testtype, id)
		return
	filterConditionIds = dict()
	input = t_input[testtype][testid]
        """
	input = ["USER bsmith", "SELECT firstName FROM table WHERE age = 'fourteen'", "SELECT Age FROM table WHERE age = 14"]
	"""
        populateTableDescs()
	populateColumnTypes()
        user = userName.parseString(input[0])[1]
        SQLQueries = input[1:]
        processQueries(SQLQueries, user)

# One test policy for all tests below.

# user is not a foaf file. get list of policies from csv file
#t_input["csv"] = ["USER bsmith", "SELECT firstName FROM table WHERE age = 'fourteen'", "SELECT Age FROM table WHERE age = 14"]
t_input = {"parser":dict(), "error":dict(), "bill":dict(), "george":dict(), "mary":dict(), "sarah":dict(), "sarahssn":dict()}
# test SQL parsing. same filter conditions mapped to the same URI
testpolicy = "file:///home/ankesh/exam-harness/Policy-dryrun/policies/bill-smith.n3"
t_input["parser"]["1"] = \
	["USER " + testpolicy, 
	"SELECT AGE FROM PEOPLE",
	"SELECT * FROM PEOPLE",
	"SELECT AGE, FIRSTNAME FROM PEOPLE WHERE STATE = 'MA'",
	"SELECT AGE, FIRSTNAME FROM PEOPLE WHERE AGE >= 19",
	"SELECT AGE, FIRSTNAME FROM PEOPLE WHERE AGE = 14 AND STATE = 'MA' AND OCCUPATION = 'COMPANYFOUNDER'",
	"SELECT PEOPLE.FIRSTNAME, USDATA.STATUS FROM PEOPLE, USDATA WHERE PEOPLE.AGE = 14 AND PEOPLE.SSN = USDATA.SSN AND USDATA.CITIZEN = 'US'"]

t_input["error"] = {"1": [ "USER http://arbit/", "SELECT AGE FROM PEOPLE" ],\
	"2": [ "USER " + testpolicy, "SELECT AGE FROM PEOPLE WHERE AGE = 12 OR AGE = 14"],\
	"3": [ "USER " + testpolicy, "SELECT AGE FROM PEOPLE WHERE AGE IN (12, 14)"] }

# The user may not filter based on State.
# The user may not retrieve State.
testpolicy = "file:///home/ankesh/exam-harness/Policy-dryrun/policies/bill-smith.n3"
t_input["bill"] = \
	{"1" : ["USER " + testpolicy, "SELECT firstname FROM people where Age = 18"],\
	 "2" : ["USER " + testpolicy, "SELECT state FROM people WHERE Age = 18"], \
	 "3" : ["USER " + testpolicy, "SELECT firstname FROM people WHERE State='MT'"] }

# The user may not filter for persons born in Massachusetts.
testpolicy = "file:///home/ankesh/exam-harness/Policy-dryrun/policies/mary-gomez.n3"
t_input["mary"] = \
	{"1" : ["USER " + testpolicy, "SELECT firstname FROM people WHERE birthstate='TX'"],\
	 "2" : ["USER " + testpolicy, "SELECT firstname FROM people WHERE birthstate='MA'"],\
	 "3" : ["USER " + testpolicy, "SELECT firstname FROM people WHERE birthzipcode='12180'"],\
	 "4" : ["USER " + testpolicy, "SELECT firstname FROM people WHERE birthzipcode='02139'"] }

# The user may not retrieve data for persons living in the West.
testpolicy = "file:///home/ankesh/exam-harness/Policy-dryrun/policies/george-wilson.n3"
t_input["george"] = \
	{ "1" : ["USER " + testpolicy, "SELECT firstName FROM people WHERE State='CA'"],\
	"2" : ["USER " + testpolicy, "SELECT firstName FROM people WHERE State='TX'"],\
	"3" : ["USER " + testpolicy, "SELECT firstName FROM people where STATE = 'CA' and STATE  = 'TX'"],\
	"4" : ["USER " + testpolicy, "SELECT firstname from people where zipcode = '94536'"],\
	"5" : ["USER " + testpolicy, "SELECT firstname from people where zipcode = '02139'"],\
	"6" : ["USER " + testpolicy, "SELECT firstname from people where place = 'LOS ANGELES'"],\
	"7" : ["USER " + testpolicy, "SELECT firstname from people where place = 'BOSTON'"],\
	"8" : ["USER " + testpolicy, "SELECT firstname from people where age = 10"],\
	"9" : ["USER " + testpolicy, "SELECT firstname from people"] }

# The user may not retrieve both firstName and lastName.
testpolicy = "file:///home/ankesh/exam-harness/Policy-dryrun/policies/sarah-thompson.n3"
t_input["sarah"] = \
	{ "1" : ["USER " + testpolicy, "SELECT firstname FROM people WHERE State='NY'", "SELECT lastName FROM people WHERE age=18 and zipcode='12180'" ],\
	"2" : ["USER " + testpolicy, "SELECT firstname FROM people WHERE zipcode = '12180'", "SELECT lastName FROM people WHERE age=18 and state='NY'" ],\
	"3" : ["USER " + testpolicy, "SELECT firstname FROM people WHERE state='NY'", "SELECT lastName FROM people WHERE age=18 and place='TROY'" ],\
	"4" : ["USER " + testpolicy, "SELECT firstname FROM people WHERE place='TROY'", "SELECT lastName FROM people WHERE age=18 and state='NY'" ],\
	"5" : ["USER " + testpolicy, "SELECT firstname FROM people WHERE zipcode='12180'", "SELECT lastName FROM people WHERE age=18 and place='TROY'" ],\
	"6" : ["USER " + testpolicy, "SELECT firstname FROM people WHERE place='TROY'", "SELECT lastName FROM people WHERE age=18 and zipcode='12180'" ],\
	"7" : ["USER " + testpolicy,"SELECT firstname FROM people where STATE='NY'","SELECT lastName FROM people where zipcode='02139'"],\
	"8" : ["USER " + testpolicy,
		"SELECT firstname FROM people",
		"SELECT lastname FROM people"],\
	"9" : ["USER " + testpolicy, 
		"SELECT firstname FROM people",
		"SELECT lastname FROM people where age = 18"],\
	"10" : ["USER " + testpolicy, 
		"SELECT firstname FROM people WHERE age >= 18 AND state = 'NY'",
		"SELECT lastname FROM people WHERE age < 18"],\
	"11" : ["USER " + testpolicy, 
		"SELECT firstname FROM people WHERE age <> 18 AND state = 'NY'",
		"SELECT lastname FROM people WHERE age > 15" ],\
	"12" : ["USER " + testpolicy, 
		"SELECT firstname FROM people WHERE state = 'NY'",
		"SELECT lastname FROM people WHERE state = 'TX'"],\
	"13" : ["USER " + testpolicy, "SELECT * from people WHERE state = 'NY'"] ,\
	"14" : ["USER " + testpolicy, "SELECT firstname FROM people WHERE state='NY'", "SELECT lastName FROM people WHERE age=18 and place='AUSTIN'" ] ,\
	"15" : ["USER " + testpolicy, "SELECT people.firstname FROM people, patient WHERE people.id=patient.id", "SELECT people.lastname FROM people, patient WHERE people.id = patient.id and age = 18"],\
	"16" : ["USER " + testpolicy, "SELECT people.firstname FROM people, patient WHERE people.id=patient.id and age<30", "SELECT people.lastName FROM people, patient WHERE people.id = patient.id and age >=30"] }

# The user may not retrieve firstName, lastName and SSN
testpolicy = "file:///home/ankesh/exam-harness/Policy-dryrun/policies/sarah-ssn.n3"
t_input["sarahssn"] = \
	{ "1" : [ "USER " + testpolicy,
		"SELECT firstname from people where state = 'MA'",
		"SELECT lastname from people where state = 'MA' and age = 12 ",
		"SELECT ssn from people where zipcode = '02139'"],\
	"2" : [ "USER " + testpolicy,
		"SELECT firstname from people where state = 'MA'",
		"SELECT lastname from people where state = 'MA' and age = 12 ",
		"SELECT ssn from people where zipcode = '12180'"],\
	"3" : [ "USER " + testpolicy,
		"SELECT firstname,lastname,ssn from people where state = 'MA'"],
	"4" : [ "USER " + testpolicy,
		"SELECT firstname from people where age > 18",
		"SELECT lastname from people where age < 24",
		"SELECT ssn from people where age = 21" ],\
	"5" : [ "USER " + testpolicy,
		"SELECT firstname from people where age > 18",
		"SELECT lastname from people where age < 24",
		"SELECT ssn from people where age >= 30" ] }

# The user may not filter based on New England.
testpolicy = "http://dig.csail.mit.edu/2009/IARPA-PIR/test/alice.n3"
t_input["alice"] = \
	{ "1" : [ "USER " + testpolicy,
		"SELECT firstname from people where city= 'BOSTON'"] }

def main(argv = None) :
	if argv is None : argv = sys.argv
	try :
		opts, args = getopt(sys.argv[1:], 'h', ['t=', 'n='])
		if opts :
			testtype = ""
			testid = ""
			for o, a in opts :
				if o == '-h' :
					print '''options
						 -h help
						 -t= parsing, <user-id>
						 -n= test number of above type'''
		                elif o=='--t' : testtype = a
				elif o=='--n' : testid = a
			if testtype : test(testtype, testid)
			else : runSession()
		else :
			runSession()		
	except Exception, err:
		print err

if __name__ == "__main__" :
	main()
