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

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 isGradDateAfter(row, year):
        '''Returns True if the student's graduation date is after the specified year, False otherwise'''

        gradYear = row[GRAD_YEAR_INDEX]

        if gradYear > year:
                return True
        else:
                return False

def query(data, year):
        '''Returns the ratio: average of final-year sessional averages for male students graduated after year
                                                        / average of final-year sessional averages for female students graduated after year'''

        numeratorList = []
        denominatorList = []
        
        #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 isGradDateAfter(row, year):
                        sessionalAvgList = row[SESSIONAL_AVG_INDEX]
                        finalYearAvg = sessionalAvgList[-1]
                        #Or use sessionalAvgList[len(sessionalAvgList)-1]
                        
                        if isGender(row,'M'):
                                numeratorList.append(finalYearAvg)
                        elif isGender(row,'F'):
                                denominatorList.append(finalYearAvg)

        numerator = float(sum(numeratorList)) / len(numeratorList)
        print numerator
        denominator = float(sum(denominatorList)) / len(denominatorList)
        print denominator
        result = numerator / denominator
        return result
	

'''
Design Question

If the database contains no female student records, the query function
will return ZeroDivisionError. 

Since we know the specific name of the error, we could use a try-except
statement as follows:

try:
	...
except ZeroDivisionError:
	...

The code that follows the except statement would depend on the desired behaviour.
We could return 0, return None, or return a string containing a message, for example. 

'''
##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

FRI = {'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': ['isGradDateAfter',[data[1], 2009]],
       'outputs': [True]},
       'test6':
       {'inputs': ['isGradDateAfter',[data[1], 2010]],
       'outputs': [False]},
       'test7':
       {'inputs': ['query',[data, 2010]],
       'outputs': [1.2439024390243902]}}
'''