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

#-------------------------------------------------------------------------
# drawElements Quality Program utilities
# --------------------------------------
#
# Copyright 2016 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 os
import argparse
import tempfile

from build.common import *
from build.build import *

class Environment:
	def __init__ (self, srcDir, tmpDir):
		self.srcDir	= srcDir
		self.tmpDir	= tmpDir

class BuildTestStep:
	def getName (self):
		return "<unknown>"

	def isAvailable (self, env):
		return True

	def run (self, env):
		raise Exception("Not implemented")

class RunScript(BuildTestStep):
	def __init__ (self, scriptPath, getExtraArgs = None):
		self.scriptPath		= scriptPath
		self.getExtraArgs	= getExtraArgs

	def getName (self):
		return self.scriptPath

	def run (self, env):
		args = ["python", os.path.join(env.srcDir, self.scriptPath)]

		if self.getExtraArgs != None:
			args += self.getExtraArgs(env)

		execute(args)

def makeCflagsArgs (cflags):
	cflagsStr = " ".join(cflags)
	return ["-DCMAKE_C_FLAGS=%s" % cflagsStr, "-DCMAKE_CXX_FLAGS=%s" % cflagsStr]

def makeBuildArgs (target, cc, cpp, cflags):
	return ["-DDEQP_TARGET=%s" % target, "-DCMAKE_C_COMPILER=%s" % cc, "-DCMAKE_CXX_COMPILER=%s" % cpp] + makeCflagsArgs(cflags)

class BuildConfigGen:
	def isAvailable (self, env):
		return True

class UnixConfig(BuildConfigGen):
	def __init__ (self, target, buildType, cc, cpp, cflags):
		self.target		= target
		self.buildType	= buildType
		self.cc			= cc
		self.cpp		= cpp
		self.cflags		= cflags

	def isAvailable (self, env):
		return which(self.cc) != None and which(self.cpp) != None

	def getBuildConfig (self, env, buildDir):
		args = makeBuildArgs(self.target, self.cc, self.cpp, self.cflags)
		return BuildConfig(buildDir, self.buildType, args, env.srcDir)

class VSConfig(BuildConfigGen):
	def __init__ (self, buildType):
		self.buildType = buildType

	def getBuildConfig (self, env, buildDir):
		args = ["-DCMAKE_C_FLAGS=/WX -DCMAKE_CXX_FLAGS=/WX"]
		return BuildConfig(buildDir, self.buildType, args, env.srcDir)

class Build(BuildTestStep):
	def __init__ (self, buildDir, configGen, generator):
		self.buildDir	= buildDir
		self.configGen	= configGen
		self.generator	= generator

	def getName (self):
		return self.buildDir

	def isAvailable (self, env):
		return self.configGen.isAvailable(env) and self.generator != None and self.generator.isAvailable()

	def run (self, env):
		# specialize config for env
		buildDir	= os.path.join(env.tmpDir, self.buildDir)
		curConfig	= self.configGen.getBuildConfig(env, buildDir)

		build(curConfig, self.generator)

class CheckSrcChanges(BuildTestStep):
	def getName (self):
		return "check for changes"

	def run (self, env):
		pushWorkingDir(env.srcDir)
		execute(["git", "diff", "--exit-code"])
		popWorkingDir()

def getClangVersion ():
	knownVersions = ["4.0", "3.9", "3.8", "3.7", "3.6", "3.5"]
	for version in knownVersions:
		if which("clang-" + version) != None:
			return "-" + version
	return ""

def runSteps (steps):
	for step in steps:
		if step.isAvailable(env):
			print "Run: %s" % step.getName()
			step.run(env)
		else:
			print "Skip: %s" % step.getName()

COMMON_GCC_CFLAGS	= ["-Werror"]
COMMON_CLANG_CFLAGS	= COMMON_GCC_CFLAGS + ["-Wno-error=unused-command-line-argument"]
GCC_32BIT_CFLAGS	= COMMON_GCC_CFLAGS + ["-m32"]
CLANG_32BIT_CFLAGS	= COMMON_CLANG_CFLAGS + ["-m32"]
GCC_64BIT_CFLAGS	= COMMON_GCC_CFLAGS + ["-m64"]
CLANG_64BIT_CFLAGS	= COMMON_CLANG_CFLAGS + ["-m64"]
CLANG_VERSION		= getClangVersion()

# Always ran before any receipe
PREREQUISITES		= [
	RunScript(os.path.join("external", "fetch_sources.py"))
]

# Always ran after any receipe
POST_CHECKS			= [
	CheckSrcChanges()
]

BUILD_TARGETS		= [
	Build("clang-64-debug",
		  UnixConfig("null",
					 "Debug",
					 "clang" + CLANG_VERSION,
					 "clang++" + CLANG_VERSION,
					 CLANG_64BIT_CFLAGS),
		  ANY_UNIX_GENERATOR),
	Build("gcc-32-debug",
		  UnixConfig("null",
					 "Debug",
					 "gcc",
					 "g++",
					 GCC_32BIT_CFLAGS),
		  ANY_UNIX_GENERATOR),
	Build("gcc-64-release",
		  UnixConfig("null",
					 "Release",
					 "gcc",
					 "g++",
					 GCC_64BIT_CFLAGS),
		  ANY_UNIX_GENERATOR),
	Build("vs-64-debug",
		  VSConfig("Debug"),
		  ANY_VS_X64_GENERATOR),
]

SPECIAL_RECIPES		= [
	('android-mustpass', [
			RunScript(os.path.join("scripts", "build_android_mustpass.py"),
					  lambda env: ["--build-dir", os.path.join(env.tmpDir, "android-mustpass")]),
		]),
	('vulkan-mustpass', [
			RunScript(os.path.join("external", "vulkancts", "scripts", "build_mustpass.py"),
					  lambda env: ["--build-dir", os.path.join(env.tmpDir, "vulkan-mustpass")]),
		]),
	('spirv-binaries', [
			RunScript(os.path.join("external", "vulkancts", "scripts", "build_spirv_binaries.py"),
					  lambda env: ["--build-dir", os.path.join(env.tmpDir, "spirv-binaries")]),
		]),
	('gen-inl-files', [
			RunScript(os.path.join("scripts", "gen_egl.py")),
			RunScript(os.path.join("scripts", "opengl", "gen_all.py")),
			RunScript(os.path.join("external", "vulkancts", "scripts", "gen_framework.py")),
			RunScript(os.path.join("scripts", "gen_android_mk.py")),
			RunScript(os.path.join("scripts", "src_util", "check_all.py")),
		])
]

def getBuildRecipes ():
	return [(b.getName(), [b]) for b in BUILD_TARGETS]

def getAllRecipe (recipes):
	allSteps = []
	for name, steps in recipes:
		allSteps += steps
	return ("all", allSteps)

def getRecipes ():
	recipes = getBuildRecipes()
	recipes += SPECIAL_RECIPES
	return recipes

def getRecipe (recipes, recipeName):
	for curName, steps in recipes:
		if curName == recipeName:
			return (curName, steps)
	return None

RECIPES			= getRecipes()

def parseArgs ():
	parser = argparse.ArgumentParser(description = "Build and test source",
									 formatter_class=argparse.ArgumentDefaultsHelpFormatter)
	parser.add_argument("-s",
						"--src-dir",
						dest="srcDir",
						default=DEQP_DIR,
						help="Source directory")
	parser.add_argument("-t",
						"--tmp-dir",
						dest="tmpDir",
						default=os.path.join(tempfile.gettempdir(), "deqp-build-test"),
						help="Temporary directory")
	parser.add_argument("-r",
						"--recipe",
						dest="recipe",
						choices=[n for n, s in RECIPES] + ["all"],
						default="all",
						help="Build / test recipe")
	parser.add_argument("-d",
						"--dump-recipes",
						dest="dumpRecipes",
						action="store_true",
						help="Print out recipes that have any available actions")
	parser.add_argument("--skip-prerequisites",
						dest="skipPrerequisites",
						action="store_true",
						help="Skip external dependency fetch")

	return parser.parse_args()

if __name__ == "__main__":
	args	= parseArgs()
	env		= Environment(args.srcDir, args.tmpDir)

	if args.dumpRecipes:
		for name, steps in RECIPES:
			for step in steps:
				if step.isAvailable(env):
					print name
					break
	else:
		name, steps	= getAllRecipe(RECIPES) if args.recipe == "all" \
					  else getRecipe(RECIPES, args.recipe)

		print "Running %s" % name

		allSteps = (PREREQUISITES if (args.skipPrerequisites == False) else []) + steps + POST_CHECKS
		runSteps(allSteps)

		print "All steps completed successfully"
