#!/usr/bin/python3
#  Copyright 2019 The ANGLE Project Authors. All rights reserved.
#  Use of this source code is governed by a BSD-style license that can be
#  found in the LICENSE file.
#
#  Code generation for:
#  - src/tests/deqp_support/BUILD.gn
#  - src/tests/deqp_data.gni
#  NOTE: don't run this script directly. Run scripts/run_code_generation.py.

import errno
import os
import sys
import shutil


def initDataDirectories(dataDirectories):
    dataDirectories.append(os.path.join("data", "gles2"))
    dataDirectories.append(os.path.join("data", "gles3"))
    dataDirectories.append(os.path.join("data", "gles31"))
    dataDirectories.append(os.path.join("external", "graphicsfuzz", "data", "gles3"))
    dataDirectories.append(os.path.join("external", "openglcts", "data", "gles3"))
    dataDirectories.append(os.path.join("external", "openglcts", "data", "gles31"))
    dataDirectories.append(os.path.join("external", "openglcts", "data", "gles32"))


def initPathReplacements(pathReplacements):
    # The GraphicsFuzz data files need the 'external/graphicsfuzz/' prefix removed
    pathToReplace = os.path.join("external", "graphicsfuzz", "")  # Include trailing slash
    pathReplacements[pathToReplace] = ""
    # The KHR dEQP tests expect a root prefix of "gl_cts" for some reason.
    pathToReplace = os.path.join("external", "openglcts", "")  # Include trailing slash
    pathReplacements[pathToReplace] = os.path.join("data", "gl_cts", "")


def createBuildGnFile(buildGnPath):
    # Cleanup the old file
    if os.path.exists(buildGnPath):
        os.remove(buildGnPath)
    # Make the new one
    return open(buildGnPath, "w+")


def createGniFile(gniFilename):
    # Cleanup the old file
    if os.path.exists(gniFilename):
        os.remove(gniFilename)
    # Make the new one
    return open(gniFilename, "w+")


def writeFileHeader(fileIn):
    templateFileHeader = """# GENERATED FILE - DO NOT EDIT.
# Generated by: {script_name}
#
# Copyright 2019 The ANGLE Project Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

"""

    fileHeader = templateFileHeader.format(script_name=os.path.basename(__file__))
    fileIn.write(fileHeader)


def fixDestinationDirectory(pathReplacements, relativeDirectory):
    for pathReplacement in pathReplacements:
        if pathReplacement in relativeDirectory:
            return relativeDirectory.replace(pathReplacement, pathReplacements[pathReplacement])
    return relativeDirectory


def convertPathToVarName(path):
    return path.replace(os.sep, "_")


def getCMakeLists(deqpSrcDir):
    cmakeLists = []
    for root, directories, filenames in os.walk(deqpSrcDir):
        for filename in filenames:
            relativeDirectory = os.path.relpath(root, deqpSrcDir)
            if filename == "CMakeLists.txt":
                cmakeLists.append(os.path.join(relativeDirectory, filename))
    return cmakeLists


def main():
    # List of directories containing data files
    dataDirectories = []
    # List of directories to exclude from the copy
    excludedDirectories = [
        ".git",
    ]
    # List of files to exclude from the copy
    excludedFilenames = [
        "LICENSE",
    ]
    # Dictionary of parts of paths that need to be replaced
    # Key: Part of path to be replaced
    # Value: What to replace it with
    pathReplacements = {}
    # List of unique relative directories for the copy() command outputs
    relativeDirectories = []
    # VK-GL-CTS source directory
    deqpSourceDirectory = os.path.join("..", "third_party", "VK-GL-CTS", "src")
    # Tests Directory
    testsDirectory = os.path.join("..", "src", "tests")
    # dEQP Support Directory
    deqpSupportDirectory = "deqp_support"
    # BUILD.gn file to write to
    buildGnFilename = "BUILD.gn"
    # Path to BUILD.gn
    buildGnPath = os.path.join(testsDirectory, deqpSupportDirectory, buildGnFilename)
    # dEQP data GNI File to write to
    dataGniFilename = os.path.join(testsDirectory, deqpSupportDirectory, "deqp_data_autogen.gni")

    # run_code_generation.py parameters.
    if len(sys.argv) > 1:
        # All CMakeLists.txt in the dEQP source tree (at the time)
        cmakeDirs = getCMakeLists(deqpSourceDirectory)
        inputs = [os.path.join(deqpSourceDirectory, "%s" % dir) for dir in cmakeDirs]
        outputs = [dataGniFilename, buildGnPath]

        if sys.argv[1] == 'inputs':
            print(','.join(inputs))
        elif sys.argv[1] == 'outputs':
            print(','.join(outputs))
        else:
            print('Invalid script parameters')
            return 1
        return 0

    deqpSrcDir = os.path.abspath(os.path.join(sys.path[0], deqpSourceDirectory))

    initDataDirectories(dataDirectories)
    initPathReplacements(pathReplacements)

    dataFiles = []
    for dataDir in dataDirectories:
        dataPath = os.path.join(deqpSrcDir, dataDir)
        for root, directories, filenames in os.walk(dataPath):
            for filename in filenames:
                relativeDirectory = os.path.relpath(root, deqpSrcDir)
                # Skip any excluded directories
                if any(directory in relativeDirectory for directory in excludedDirectories):
                    continue
                # Skip any excluded files
                if any(excludedFilename in filename for excludedFilename in excludedFilenames):
                    continue
                # Record the relative directories and full paths to each data file
                if relativeDirectory not in relativeDirectories:
                    relativeDirectories.append(relativeDirectory)
                dataFiles.append(os.path.join(relativeDirectory, filename))

    dataFiles.sort()
    relativeDirectories.sort(key=convertPathToVarName)

    #
    # BUILD.gn
    #
    buildGnFile = createBuildGnFile(buildGnPath)
    writeFileHeader(buildGnFile)
    # Definitions
    buildGnFile.write("deqp_path = \"../../../third_party/VK-GL-CTS/src\"\n")
    # Create the copy() commands
    templateFilesToCopy = """    "$deqp_path/{dataFile}",
"""
    templateCopyCommand = """
copy("vk_gl_cts_data_{relDir}") {{
  sources = [
    {filesToCopy}
  ]
  outputs = [ "$root_gen_dir/vk_gl_cts_data/{destDir}/{{{{source_file_part}}}}" ]
}}
"""
    for relativeDirectory in relativeDirectories:
        filesToCopy = ""
        for dataFile in dataFiles:
            path, filename = os.path.split(dataFile)
            if relativeDirectory == path:
                filesToCopy += templateFilesToCopy.format(dataFile=dataFile.replace(os.sep, '/'))
        copyCommand = ""
        destDir = fixDestinationDirectory(pathReplacements, relativeDirectory)
        copyCommand += templateCopyCommand.format(
            relDir=convertPathToVarName(relativeDirectory),
            filesToCopy=filesToCopy,
            destDir=destDir.replace(os.sep, '/'))
        buildGnFile.write(copyCommand)

    #
    # .gni
    #
    gniFile = createGniFile(dataGniFilename)
    writeFileHeader(gniFile)
    # Imports
    templateImports = """import("deqp.gni")
"""
    gniFile.write(templateImports)
    # Write the lists of data file dependencies
    templateDataFiles = """  "$root_gen_dir/vk_gl_cts_data/{dataFile}",
"""
    templateDataFileDeps = """
{dataDepName} = [
{files}]
"""
    for dataDirectory in dataDirectories:
        files = ""
        for dataFile in dataFiles:
            if dataDirectory + os.sep in dataFile:
                files += templateDataFiles.format(
                    dataFile=fixDestinationDirectory(pathReplacements, dataFile).replace(
                        os.sep, '/'))
        dataDepName = "angle_deqp_" + convertPathToVarName(dataDirectory)
        fileDeps = templateDataFileDeps.format(dataDepName=dataDepName, files=files)
        gniFile.write(fileDeps)

    templateCopyTarget = """  "{deqpSupportDirectory}:vk_gl_cts_data_{relDir}",
"""
    templateCopyTargets = """
angle_deqp_data_copy_targets = [
{targets}]
"""
    targets = ""
    for relativeDirectory in relativeDirectories:
        targets += templateCopyTarget.format(
            deqpSupportDirectory=deqpSupportDirectory,
            relDir=convertPathToVarName(relativeDirectory))
    gniFile.write(templateCopyTargets.format(targets=targets))


if __name__ == '__main__':
    sys.exit(main())
