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

#-------------------------------------------------------------------------
# Khronos OpenGL CTS
# ------------------
#
# Copyright (c) 2016 The Khronos Group Inc.
#
# 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 os
import sys
import xml.dom.minidom
import re

ROOT_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "..", ".."))
sys.path.append(os.path.join(ROOT_DIR, "scripts", "verify"))
sys.path.append(os.path.join(ROOT_DIR, "scripts", "build"))
sys.path.append(os.path.join(ROOT_DIR, "scripts", "log"))

from package import getPackageDescription
from verify import *
from message import *
from common import *
from log_parser import *
from summary import *

def getConfigCaseName (type):
	configs = { "es32" : ["CTS-Configs.es32", "CTS-Configs.es31", "CTS-Configs.es3", "CTS-Configs.es2"],
				"es31" : ["CTS-Configs.es31", "CTS-Configs.es3", "CTS-Configs.es2"],
				"es3"  : ["CTS-Configs.es3", "CTS-Configs.es2"],
				"es2"  : ["CTS-Configs.es2"]}
	return configs[type]

def retrieveReportedConfigs(caseName, log):
	doc				= xml.dom.minidom.parseString(log)
	sectionItems	= doc.getElementsByTagName('Section')
	sectionName		= None

	configs = []
	for sectionItem in sectionItems:
		sectionName	= sectionItem.getAttributeNode('Name').nodeValue
		if sectionName == "Configs":
			assert len(configs) == 0
			textItems = sectionItem.getElementsByTagName('Text')
			for textItem in textItems:
				configs.append(getNodeText(textItem))
	res = {caseName : configs}
	return res

def compareConfigs(filename, baseConfigs, cmpConfigs):
	messages = []
	assert len(list(baseConfigs.keys())) == 1
	assert len(list(cmpConfigs.keys())) == 1
	baseKey = list(baseConfigs.keys())[0]
	cmpKey = list(cmpConfigs.keys())[0]

	if cmp(baseConfigs[baseKey], cmpConfigs[cmpKey]) != 0:
		messages.append(error(filename, "Confomant configs reported for %s and %s do not match" % (baseKey,cmpKey)))

	return messages

def verifyConfigFile (filename, type):
	messages  = []
	caseNames = getConfigCaseName(type)

	parser		= BatchResultParser()
	results		= parser.parseFile(filename)
	baseConfigs	= None

	for caseName in caseNames:
		caseResult	= None
		print "Verifying %s in %s" % (caseName, filename)
		for result in results:
			if result.name == caseName:
				caseResult = result
				break;
		if caseResult == None:
			messages.append(error(filename, "Missing %s" % caseName))
		else:
			configs = retrieveReportedConfigs(caseName, result.log)
			if baseConfigs == None:
				baseConfigs = configs
			else:
				messages += compareConfigs(filename, baseConfigs, configs)
			if not caseResult.statusCode in ALLOWED_STATUS_CODES:
				messages.append(error(filename, "%s failed" % caseResult))

	return messages

def verifyMustpassCases(package, mustpassCases, type):
	messages = []
	apiToTest = { "es32" : ["gles32", "gles31", "gles3", "gles2"],
				"es31" : ["gles31", "gles3", "gles2"],
				"es3"  : ["gles3", "gles2"],
				"es2"  : ["gles2"]}

	for mustpass in mustpassCases:
		mustpassXML = os.path.join(mustpass, "mustpass.xml")
		doc = xml.dom.minidom.parse(mustpassXML)
		testConfigs = doc.getElementsByTagName("Configuration")
		# check that all configs that must be tested are present
		for testConfig in testConfigs:
			caseListFile = testConfig.getAttributeNode("caseListFile").nodeValue
			# identify APIs that must be tested for the given type
			apis = apiToTest[type]
			# identify API tested by the current config
			configAPI = caseListFile.split('-')[0]
			if configAPI in apis:
				# the API in this config is expected to be tested
				mustTest = True
			else:
				mustTest = False
			pattern = "config-" + os.path.splitext(caseListFile)[0] + "-cfg-[0-9]*"+"-run-[0-9]*"
			cmdLine = testConfig.getAttributeNode("commandLine").nodeValue
			cfgItems = {'height':None, 'width':None, 'seed':None, 'rotation':None}
			for arg in cmdLine.split():
				val = arg.split('=')[1]
				if "deqp-surface-height" in arg:
					cfgItems['height'] = val
				elif "deqp-surface-width" in arg:
					cfgItems['width'] = val
				elif "deqp-base-seed" in arg:
					cfgItems['seed'] = val
				elif "deqp-screen-rotation" in arg:
					cfgItems['rotation'] = val
			pattern += "-width-" + cfgItems['width'] + "-height-" + cfgItems['height']
			if cfgItems['seed'] != None:
				pattern += "-seed-" + cfgItems['seed']
			pattern += ".qpa"
			p = re.compile(pattern)
			matches = [m for l in mustpassCases[mustpass] for m in (p.match(l),) if m]
			if len(matches) == 0 and mustTest == True:
					conformOs = testConfig.getAttributeNode("os").nodeValue
					txt = "Configuration %s %s was not executed" % (caseListFile, cmdLine)
					if conformOs == "any" or (package.conformOs != None and conformOs in package.conformOs.lower()):
						msg = error(mustpassXML, txt)
					else:
						msg = warning(mustpassXML, txt)
					messages.append(msg)
			elif len(matches) != 0 and mustTest == False:
				messages.append(error(mustpassXML, "Configuration %s %s was not expected to be tested but present in cts-run-summary.xml" % (caseListFile, cmdLine)))

	return messages

def verifyTestLogs (package):
	messages = []

	try:
		execute(['git', 'checkout', '--quiet', package.conformVersion])
	except Exception, e:
		print str(e)
		print "Failed to checkout release tag %s." % package.conformVersion
		return messages

	messages = []
	summary	= parseRunSummary(os.path.join(package.basePath, package.summary))
	mustpassDirs = []

	# Check Conformant attribute
	if not summary.isConformant:
		messages.append(error(package.summary, "Runner reported conformance failure (Conformant=\"False\" in <Summary>)"))

	# Verify config list
	messages += verifyConfigFile(os.path.join(package.basePath, summary.configLogFilename), summary.type)

	mustpassCases = {}
	# Verify that all run files passed
	for runLog in summary.runLogAndCaselist:
		sys.stdout.write("Verifying %s -" % runLog)
		sys.stdout.flush()

		mustpassFile = os.path.join(ROOT_DIR, "external", "openglcts", summary.runLogAndCaselist[runLog])
		key = os.path.dirname(mustpassFile)
		if key in mustpassCases:
			mpCase = mustpassCases[key]
		else:
			mpCase = []
		mpCase.append(runLog)
		mustpassCases[os.path.dirname(mustpassFile)] = mpCase
		mustpass = readMustpass(mustpassFile)
		messages_log = verifyTestLog(os.path.join(package.basePath, runLog), mustpass)

		errors	= [m for m in messages_log if m.type == ValidationMessage.TYPE_ERROR]
		warnings	= [m for m in messages_log if m.type == ValidationMessage.TYPE_WARNING]
		if len(errors) > 0:
			sys.stdout.write(" finished with ERRRORS")
		if len(warnings) > 0:
			sys.stdout.write(" finished with WARNINGS")
		if len(errors) == 0 and len(warnings) == 0:
			sys.stdout.write(" OK")
		sys.stdout.write("\n")
		sys.stdout.flush()

		messages += messages_log

	messages += verifyMustpassCases(package, mustpassCases, summary.type)

	return messages

def verifyGitStatusFiles (package):
	messages = []

	if len(package.gitStatus) != 2:
		messages.append(error(package.basePath, "Exactly two git status files must be present, found %s" % len(package.gitStatus)))

	messages += verifyGitStatus(package)

	return messages

def verifyGitLogFiles (package):
	messages = []

	if len(package.gitLog) != 2:
		messages.append(error(package.basePath, "Exactly two git log file must be present, found %s" % len(package.gitLog)))

	messages += verifyGitLog(package)

	return messages

def verifyPackage (package):
	messages = []

	messages += verifyStatement(package)
	messages += verifyGitStatusFiles(package)
	messages += verifyGitLogFiles(package)
	messages += verifyPatches(package)

	for item in package.otherItems:
		messages.append(warning(os.path.join(package.basePath, item), "Unknown file"))

	return messages

def verifyESSubmission(argv):
	if len(argv) != 2:
		print "%s: [extracted submission package directory]" % sys.argv[0]
		sys.exit(-1)
	try:
		execute(['git', 'ls-remote', 'origin', '--quiet'])
	except Exception, e:
		print str(e)
		print "This script must be executed inside VK-GL-CTS directory."
		sys.exit(-1)

	packagePath		=  os.path.normpath(sys.argv[1])
	package			=  getPackageDescription(packagePath)
	messages		=  verifyPackage(package)
	messages		+= verifyTestLogs(package)

	errors			= [m for m in messages if m.type == ValidationMessage.TYPE_ERROR]
	warnings		= [m for m in messages if m.type == ValidationMessage.TYPE_WARNING]

	for message in messages:
		print str(message)

	print ""

	if len(errors) > 0:
		print "Found %d validation errors and %d warnings!" % (len(errors), len(warnings))
		sys.exit(-2)
	elif len(warnings) > 0:
		print "Found %d warnings, manual review required" % len(warnings)
		sys.exit(-1)
	else:
		print "All validation checks passed"

if __name__ == "__main__":
	verifyESSubmission(sys.argv)
