--!A cross-platform build utility based on Lua
--
-- 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.
--
-- Copyright (C) 2015-present, Xmake Open Source Community.
--
-- @author      ruki
-- @file        find_icxenv.lua
--

-- imports
import("lib.detect.find_file")
import("lib.detect.find_tool")

-- init icx variables
local icxvars = {"path",
                 "lib",
                 "libpath",
                 "include",
                 "DevEnvdir",
                 "VSInstallDir",
                 "VCInstallDir",
                 "WindowsSdkDir",
                 "WindowsLibPath",
                 "WindowsSDKVersion",
                 "WindowsSdkBinPath",
                 "UniversalCRTSdkDir",
                 "UCRTVersion"}

-- load icxvars_bat environment variables
function _load_icxvars(icxvars_bat, arch, opt)

    -- make the genicxvars.bat
    opt = opt or {}
    local genicxvars_bat = os.tmpfile() .. "_genicxvars.bat"
    local genicxvars_dat = os.tmpfile() .. "_genicxvars.txt"
    local file = io.open(genicxvars_bat, "w")
    file:print("@echo off")
    file:print("call \"%s\" -arch %s > nul", icxvars_bat, arch)
    for idx, var in ipairs(icxvars) do
        file:print("echo " .. var .. " = %%" .. var .. "%% %s %s", idx == 1 and ">" or ">>", genicxvars_dat)
    end
    file:close()

    -- run genicxvars.bat
    -- @note we use runv here so the bat path is not split on whitespace by os.argv,
    -- which breaks detection when the temp file lives under a path with spaces.
    os.runv(genicxvars_bat)

    -- load all envirnoment variables
    local variables = {}
    for _, line in ipairs((io.readfile(genicxvars_dat) or ""):split("\n")) do
        local p = line:find('=', 1, true)
        if p then
            local name = line:sub(1, p - 1):trim()
            local value = line:sub(p + 1):trim()
            variables[name] = value
        end
    end
    if not variables.path then
        return
    end

    -- remove some empty entries
    for _, name in ipairs(icxvars) do
        if variables[name] and #variables[name]:trim() == 0 then
            variables[name] = nil
        end
    end

    -- fix bin path for ia32
    if variables.path and arch == "ia32" then
        variables.path = variables.path:gsub("windows\\bin\\intel64;", "windows\\bin\\intel64_ia32;")
    end

    -- convert path/lib/include to PATH/LIB/INCLUDE
    variables.PATH    = variables.path
    variables.LIB     = variables.lib
    variables.LIBPATH = variables.libpath
    variables.INCLUDE = variables.include
    variables.path    = nil
    variables.lib     = nil
    variables.include = nil
    variables.libpath = nil
    return variables
end

-- find intel llvm c/c++ envirnoment on windows
function _find_intel_on_windows(opt)
    opt = opt or {}

    -- find icxvars_bat.bat
    local paths = {"$(env ONEAPI_ROOT)"}
    local icxvars_bat = find_file("setvars.bat", paths)
    if not icxvars_bat then
        paths = {}
        local keys = winos.registry_keys("HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\Intel\\DPCPPSuites\\**\\DPC++")
        for _, key in ipairs(keys) do
            table.insert(paths, format("$(reg %s;ProductDir)", key))
        end
        icxvars_bat = find_file("../../setvars.bat", paths)
    end
    if icxvars_bat then
        local icxvars_x86 = _load_icxvars(icxvars_bat, "ia32", opt)
        local icxvars_x64 = _load_icxvars(icxvars_bat, "intel64", opt)
        return {icxvars_bat = icxvars_bat, icxvars = {x86 = icxvars_x86, x64 = icxvars_x64}}
     end
end

-- find intel llvm c/c++ envirnoment on linux
function _find_intel_on_linux(opt)

    -- attempt to find the sdk directory
    local oneapi_rootdirs = {"~/intel/oneapi/compiler", "/opt/intel/oneapi/compiler"}
    paths = {}
    for _, rootdir in ipairs(oneapi_rootdirs) do
        table.insert(paths, path.join(rootdir, "*", is_host("macosx") and "mac" or "linux", "bin"))
        table.insert(paths, path.join(rootdir, "*", "bin"))
    end
    if #paths > 0 then
        local icx = find_file("icx", paths)
        if icx then
            local bindir = path.directory(icx)
            local sdkdir = path.directory(path.directory(bindir))
            return {sdkdir = sdkdir, bindir = bindir}
        end
    end
end

-- find intel c/c++ environment
function main(opt)
    if is_host("windows") then
        return _find_intel_on_windows(opt)
    else
        return _find_intel_on_linux(opt)
    end
end
