# -*- 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")

	# Quick 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)
