# Ryan Martin
# macid: abcd123
# student number: #######
# November 7, 2011
#
#
# This is a solution for Major Assignment 4 (Lab 09) on Monday.

import time


#Constants for Database Entries.
#Not required in the assignment specification,
#but improves module flexibility by allowing
#the user to configure the module in the event
#that the database specification changes.

#Extra Study Topic: This set of values could be 
#elegantly implemented using an Enumeration type.

GENDER_INDEX = 0
BIRTH_YEAR_INDEX = 1
GRAD_YEAR_INDEX = 2
SESSIONAL_AVG_INDEX = 3

def isGraduated(row):
	'''Returns True if the student has graduated, False otherwise'''

	gradYear = row[GRAD_YEAR_INDEX]
	currentYear = time.localtime().tm_year

	#If the grad year is before or equal to this year,
	#the student has graduated.
	if gradYear <= currentYear:
		return True
	else
		return False

def isGender(row, gender):
	'''Returns True if the student is of the specified gender, False otherwise'''

	rowGender = row[GENDER_INDEX]

	if rowGender == gender:
		return True
	else
		return False

def isLastYearAvgAbove(row, grade):
	'''Returns True if the student's last recorded year average is above grade, False otherwise'''

	sessionalAvgList = row[SESSIONAL_AVG_INDEX]
	finalYearAvg = sessionalAvgList[-1]
	#Or use sessionalAvgList[len(sessionalAvgList)-1]

	if finalYearAvg > grade:
		return True
	else
		return False

def query(data, grade, gender):
	'''Returns the percentage of graduated students of gender that have a final year average over grade.'''

	numerator = 0
	denominator = 0
	
	#The first row of data contains headings.
	#Only loop through the following rows.
	#Can also use: for i in range(1, len(data))
	for row in data[1:]:
		if isGraduated(row) and isGender(row, gender):
			denominator = denominator + 1

			if isFinalYearAvgAbove(row, grade):
				numerator = numerator + 1

    result = 100 * float(numerator) / denominator
    return result

'''
Design Question

The query function needs to determine the numerator and denominator of the percentage.
Since both are related by isGraduated and isGender, by nesting isLastYearAvgAbove
we reduce the number of evaluations required compared to doing an if-elif structure:

	if isGraduated and isGender and isLastYearAvgAbove:
		numerator += 1
		denominator +=1
	elif isGraduated and isGender:
		denominator += 1

compared to:

	if isGraduated and isGender:
		denominator += 1
		if isFinalYearAvgAbove:
			numerator += 1

For a large-scale database, this could have a positive effect on performance due
to less statements being evaluated.
'''
##Note: This format is used by our automated marking system.
##You will see that, for inputs, the function name is
##given with the corresponding inputs to that function
##listed right after it. Our automated marking system uses
##the variable data you see here.
'''

Testing Report

data = [ ["GENDER","BIRTH_YEAR","GRAD_YEAR","SESSIONAL_AVERAGES"],
		['F', 1988, 2010, [1.5,2.4,3.3,4.2,5.1] ],	#3.3
		['F', 1989, 2011, [1.4,2.3,3.2,4.1] ],		#2.75
		['F', 1990, 2012, [1.3,2.2,3.1] ],			#2.2
		['F', 1991, 2013, [1.2,2.1] ],				#1.65
		['M', 1988, 2010, [2.5,3.4,4.3,5.2,6.1] ],	#4.3
		['M', 1989, 2011, [2.4,3.3,4.2,5.1] ],		#3.75
		['M', 1990, 2012, [2.3,3.2,4.1] ],			#3.2
		['M', 1991, 2013, [2.2,3.1] ] ]				#2.65

MON = {'test1': 
       {'inputs': ['isGraduated',[data[1]]],
       'outputs': [True]},
       'test2':
       {'inputs': ['isGraduated',[data[3]]],
       'outputs': [False]},
       'test3':
       {'inputs': ['isGender',[data[1], 'F']],
       'outputs': [True]},
       'test4':
       {'inputs': ['isGender',[data[1], 'M']],
       'outputs': [False]},
       'test5':
       {'inputs': ['isLastYearAvgAbove',[data[1], 5]],
       'outputs': [True]},
       'test6':
       {'inputs': ['isLastYearAvgAbove',[data[1], 5.2]],
       'outputs': [False]},
       'test7':
       {'inputs': ['query',[data, 6.0, 'M']],
       'outputs': [50.0]}}

'''