--!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      arthapz
-- @file        xmake.lua
--

rule("qt.qmltyperegistrar")
    add_deps("qt.env")
    set_extensions(".h", ".hpp")

    on_config(function(target)
        import("lib.detect.find_file")

        -- get qt
        local qt = assert(target:data("qt"), "Qt not found!")

        -- get qmltyperegistrar
        local search_dirs = {}
        if qt.bindir_host then table.insert(search_dirs, qt.bindir_host) end
        if qt.bindir then table.insert(search_dirs, qt.bindir) end
        if qt.libexecdir_host then table.insert(search_dirs, qt.libexecdir_host) end
        if qt.libexecdir then table.insert(search_dirs, qt.libexecdir) end
        local qmltyperegistrar = find_file(is_host("windows") and "qmltyperegistrar.exe" or "qmltyperegistrar", search_dirs)
        assert(qmltyperegistrar and os.isexec(qmltyperegistrar), "qmltyperegistrar not found!")

        -- set targetdir
        local importname = target:values("qt.qmlplugin.import_name")
        assert(importname, "QML plugin import name not set")

        local targetdir = target:targetdir()
        for _, dir in ipairs(importname:split(".", {plain = true})) do
            targetdir = path.join(targetdir, dir)
        end
        os.mkdir(targetdir)
        target:set("targetdir", targetdir)

        -- add qmldir
        local qmldir = target:values("qt.qmlplugin.qmldirfile")
        if qmldir then
            target:add("installfiles", path.join(target:scriptdir(), qmldir), { prefixdir = path.join("bin", table.unpack(importname:split(".", { plain = true }))) })
        end

        -- add qmltypes
        target:add("installfiles", path.join(targetdir, "plugin.qmltypes"), { prefixdir = path.join("bin", table.unpack(importname:split(".", { plain = true }))) })

        local genbasename = path.join(target:autogendir(), "rules", "qt", "qmltyperegistrar", target:name())
        local metatypesfile = genbasename .. "_metatypes.json"
        local sourcefile = genbasename .. "_qmltyperegistrations.cpp"
        local sourcefile_dir = path.directory(sourcefile)
        os.mkdir(sourcefile_dir)
        target:data_set("qt.qmlplugin.metatypesfile", metatypesfile)
        target:data_set("qt.qmlplugin.sourcefile", sourcefile)

        -- add moc arguments
        target:add("qt.moc.flags", "--output-json")

        -- save qmltyperegistrar
        target:data_set("qt.qmltyperegistrar", qmltyperegistrar)
        -- save qmltyperegistrar
        target:data_set("qt.qmlplugin.qmltyperegistrar", qmltyperegistrar)
     end)

     on_buildcmd_files(function(target, batchcmds, sourcebatch, opt)
        -- setup qmltyperegistrar arguments
        local moc = target:data("qt.moc")
        local qmltyperegistrar = target:data("qt.qmltyperegistrar")
        local metatypesfile = target:data("qt.qmlplugin.metatypesfile")
        local sourcefile = target:data("qt.qmlplugin.sourcefile")

        local importname = target:values("qt.qmlplugin.import_name")
        local majorversion = target:values("qt.qmlplugin.majorversion") or 1
        local minorversion = target:values("qt.qmlplugin.minorversion") or 0

        local metatype_files = {}
        for _, mocedfile in ipairs(sourcebatch.sourcefiles) do
            target:add("includedirs", path.directory(mocedfile))
            local basename = path.basename(mocedfile)
            local filename_moc = "moc_" .. basename .. ".cpp"
            if mocedfile:endswith(".cpp") then
                filename_moc = basename .. ".moc"
            end
            local sourcefile_moc = target:autogenfile(path.join(path.directory(mocedfile), filename_moc))
            table.insert(metatype_files, path(sourcefile_moc .. ".json"))
        end

        -- generate a common metatypes.json file
        -- @see https://github.com/xmake-io/xmake/issues/6647
        local moc_args = {
            "--collect-json",
            "-o", path(metatypesfile)
        }
        batchcmds:show_progress(opt.progress, "${color.build.object}generating.qt.qmltyperegistrar %s", path.filename(metatypesfile))
        batchcmds:vrunv(moc, table.join(moc_args, metatype_files))

        -- gen sourcefile
        local targetdir = target:targetdir()
        local args = {
            "--generate-qmltypes=" .. path(path.join(targetdir, "plugin.qmltypes")),
            "--import-name=" .. importname,
            "--major-version=" .. majorversion,
            "--minor-version=" .. minorversion,
            "-o", path(sourcefile),
            path(metatypesfile)
        }
        batchcmds:show_progress(opt.progress, "${color.build.object}generating.qt.qmltyperegistrar %s", path.filename(sourcefile))
        batchcmds:vrunv(qmltyperegistrar, args)

        -- add objectfile
        local objectfile = target:objectfile(sourcefile)
        table.insert(target:objectfiles(), objectfile)

        -- compile sourcefile
        batchcmds:show_progress(opt.progress, "${color.build.object}compiling.qt.qmltyperegistrar %s", path.filename(sourcefile))
        batchcmds:compile(sourcefile, objectfile)

        batchcmds:add_depvalues(importname, majorversion, minorversion)
        batchcmds:add_depfiles(sourcefile, sourcebatch.sourcefiles)
        batchcmds:set_depmtime(os.mtime(objectfile))
        batchcmds:set_depcache(target:dependfile(objectfile))
    end)

    after_build(function(target)
        local qmldir = target:values("qt.qmlplugin.qmldirfile")
        if qmldir then
            os.cp(path.join(target:scriptdir(), qmldir), target:targetdir())
        end
    end)
