# -*- coding: utf-8 -*-

#-------------------------------------------------------------------------
# drawElements Quality Program utilities
# --------------------------------------
#
# Copyright 2015 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
#-------------------------------------------------------------------------

import sys
import random
import string
import subprocess
from optparse import OptionParser

def all (results, predicate):
	for result in results:
		if not predicate(result):
			return False
	return True

def any (results, predicate):
	for result in results:
		if predicate(result):
			return True
	return False

class FilterRule:
	def __init__ (self, name, description, filters):
		self.name			= name
		self.description	= description
		self.filters		= filters

class TestCaseResult:
	def __init__ (self, name, results):
		self.name		= name
		self.results	= results

class Group:
	def __init__ (self, name):
		self.name		= name
		self.cases		= []

def readCaseList (filename):
	f = open(filename, 'rb')
	cases = []
	for line in f:
		if line[:6] == "TEST: ":
			case = line[6:].strip()
			if len(case) > 0:
				cases.append(case)
	return cases

def toResultList (caselist):
	results = []
	for case in caselist:
		results.append(TestCaseResult(case, []))
	return results

def addResultsToCaseList (caselist, results):
	resultMap	= {}
	caseListRes	= toResultList(caselist)

	for res in caseListRes:
		resultMap[res.name] = res

	for result in results:
		if result.name in resultMap:
			resultMap[result.name].results += result.results

	return caseListRes

def readTestResults (filename):
	f			= open(filename, 'rb')
	csvData		= f.read()
	csvLines	= csvData.splitlines()
	results		= []

	f.close()

	for line in csvLines[1:]:
		args = line.split(',')
		if len(args) == 1:
			continue # Ignore

		results.append(TestCaseResult(args[0], args[1:]))

	if len(results) == 0:
		raise Exception("Empty result list")

	# Sanity check for results
	numResultItems	= len(results[0].results)
	seenResults		= set()
	for result in results:
		if result.name in seenResults:
			raise Exception("Duplicate result row for test case '%s'" % result.name)
		if len(result.results) != numResultItems:
			raise Exception("Found %d results for test case '%s', expected %d" % (len(result.results), result.name, numResultItems))
		seenResults.add(result.name)

	return results

def readGroupList (filename):
	f = open(filename, 'rb')
	groups = []
	for line in f:
		group = line.strip()
		if group != "":
			groups.append(group)
	return groups

def createGroups (results, groupNames):
	groups	= []
	matched	= set()

	for groupName in groupNames:
		group = Group(groupName)
		groups.append(group)

		prefix		= groupName + "."
		prefixLen	= len(prefix)
		for case in results:
			if case.name[:prefixLen] == prefix:
				if case in matched:
					die("Case '%s' matched by multiple groups (when processing '%s')" % (case.name, group.name))
				group.cases.append(case)
				matched.add(case)

	return groups

def createLeafGroups (results):
	groups = []
	groupMap = {}

	for case in results:
		parts		= case.name.split('.')
		groupName	= string.join(parts[:-1], ".")

		if not groupName in groupMap:
			group = Group(groupName)
			groups.append(group)
			groupMap[groupName] = group
		else:
			group = groupMap[groupName]

		group.cases.append(case)

	return groups

def filterList (results, condition):
	filtered = []
	for case in results:
		if condition(case.results):
			filtered.append(case)
	return filtered

def getFilter (list, name):
	for filter in list:
		if filter.name == name:
			return filter
	return None

def getNumCasesInGroups (groups):
	numCases = 0
	for group in groups:
		numCases += len(group.cases)
	return numCases

def getCasesInSet (results, caseSet):
	filtered = []
	for case in results:
		if case in caseSet:
			filtered.append(case)
	return filtered

def selectCasesInGroups (results, groups):
	casesInGroups = set()
	for group in groups:
		for case in group.cases:
			casesInGroups.add(case)
	return getCasesInSet(results, casesInGroups)

def selectRandomSubset (results, groups, limit, seed):
	selectedCases	= set()
	numSelect		= min(limit, getNumCasesInGroups(groups))

	random.seed(seed)
	random.shuffle(groups)

	groupNdx = 0
	while len(selectedCases) < numSelect:
		group = groups[groupNdx]
		if len(group.cases) == 0:
			del groups[groupNdx]
			if groupNdx == len(groups):
				groupNdx -= 1
			continue # Try next

		selected = random.choice(group.cases)
		selectedCases.add(selected)
		group.cases.remove(selected)

		groupNdx = (groupNdx + 1) % len(groups)

	return getCasesInSet(results, selectedCases)

def die (msg):
	print msg
	sys.exit(-1)

# Named filter lists
FILTER_RULES = [
	FilterRule("all",			"No filtering",											[]),
	FilterRule("all-pass",		"All results must be 'Pass'",							[lambda l: all(l, lambda r: r == 'Pass')]),
	FilterRule("any-pass",		"Any of results is 'Pass'",								[lambda l: any(l, lambda r: r == 'Pass')]),
	FilterRule("any-fail",		"Any of results is not 'Pass' or 'NotSupported'",		[lambda l: not all(l, lambda r: r == 'Pass' or r == 'NotSupported')]),
	FilterRule("prev-failing",	"Any except last result is failure",					[lambda l: l[-1] == 'Pass' and not all(l[:-1], lambda r: r == 'Pass')]),
	FilterRule("prev-passing",	"Any except last result is 'Pass'",						[lambda l: l[-1] != 'Pass' and any(l[:-1], lambda r: r == 'Pass')])
]

if __name__ == "__main__":
	parser = OptionParser(usage = "usage: %prog [options] [caselist] [result csv file]")
	parser.add_option("-f", "--filter", dest="filter", default="all", help="filter rule name")
	parser.add_option("-l", "--list", action="store_true", dest="list", default=False, help="list available rules")
	parser.add_option("-n", "--num", dest="limit", default=0, help="limit number of cases")
	parser.add_option("-s", "--seed", dest="seed", default=0, help="use selected seed for random selection")
	parser.add_option("-g", "--groups", dest="groups_file", default=None, help="select cases based on group list file")

	(options, args)	= parser.parse_args()

	if options.list:
		print "Available filter rules:"
		for filter in FILTER_RULES:
			print "  %s: %s" % (filter.name, filter.description)
		sys.exit(0)

	if len(args) == 0:
		die("No input files specified")
	elif len(args) > 2:
		die("Too many arguments")

	# Fetch filter
	filter = getFilter(FILTER_RULES, options.filter)
	if filter == None:
		die("Unknown filter '%s'" % options.filter)

	# Read case list
	caselist = readCaseList(args[0])
	if len(args) > 1:
		results = readTestResults(args[1])
		results = addResultsToCaseList(caselist, results)
	else:
		results = toResultList(caselist)

	# Execute filters for results
	for rule in filter.filters:
		results = filterList(results, rule)

	if options.limit != 0:
		if options.groups_file != None:
			groups = createGroups(results, readGroupList(options.groups_file))
		else:
			groups = createLeafGroups(results)
		results = selectRandomSubset(results, groups, int(options.limit), int(options.seed))
	elif options.groups_file != None:
		groups = createGroups(results, readGroupList(options.groups_file))
		results = selectCasesInGroups(results, groups)

	# Print test set
	for result in results:
		print result.name
