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


#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 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 isBirthDateBefore(row, year):
        '''Returns True if the student was born before the specified year, False otherwise'''

        birthYear = row[BIRTH_YEAR_INDEX]

        if birthYear < year:
                return True
        else:
                return False

def isCumulativeAvgAbove(row, grade):
        '''Returns True if the student's cumulative average is above grade, False otherwise'''

        sessionalAvgList = row[SESSIONAL_AVG_INDEX]
        cumulativeAvg = float(sum(sessionalAvgList)) / len(sessionalAvgList)

        if cumulativeAvg > grade:
                return True
        else:
                return False

def query(data, grade, gender, year):
        '''Returns the ratio: students of gender with a cumulative average over grade born before year 
                                                        / students of gender with a cumulative average over grade born after year'''

        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 isGender(row, gender) and isCumulativeAvgAbove(row, grade):
                        if isBirthDateBefore(row, year):
                                numerator = numerator + 1
                        else:
                                denominator = denominator + 1

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

'''
Design Question

Short circuit evaluation is the behaviour of boolean operators (and, or)
to ignore (skip) the second term when it is uneccesary.

For example, if x = False and y = True, the statement (x and y) only examines
the first argument (x) and ignores y, since (False and y) is always false.

By combining statements such as "if isGender and isCumulativeAvgAbove", 
we avoid the calling isCumulativeAvgAbove when isGender returns False.
This can improve performance in the query function, especially since 
isCumulativeAvgAbove is a more resource-intensive function compared to isGender.

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

WED = {'test1': 
       {'inputs': ['isGender',[data[1], 'F']],
       'outputs': [True]},
       'test2':
       {'inputs': ['isGender',[data[1], 'M']],
       'outputs': [False]},
       'test3':
       {'inputs': ['isBirthDateBefore',[data[1], 1989]],
       'outputs': [True]},
       'test4':
       {'inputs': ['isBirthDateBefore',[data[1], 1988]],
       'outputs': [False]},
	   'test5':
       {'inputs': ['isCumulativeAvgAbove',[data[1], 3]],
       'outputs': [True]},
       'test6':
       {'inputs': ['isCumulativeAvgAbove',[data[1], 3.5]],
       'outputs': [False]},
       'test7':
       {'inputs': ['query',[data, 3.0, 'M', 1990]],
       'outputs': [2.0]}}
'''