gitVersioningCommand = "git rev-list --count --all"
gitCurrentBranchCommand = "git symbolic-ref -q --short HEAD"

-- Quote the given string input as a C string
function cstrquote(value)
	if value == nil then
		return "\"\""
	end
	result = value:gsub("\\", "\\\\")
	result = result:gsub("\"", "\\\"")
	result = result:gsub("\n", "\\n")
	result = result:gsub("\t", "\\t")
	result = result:gsub("\r", "\\r")
	result = result:gsub("\a", "\\a")
	result = result:gsub("\b", "\\b")
	result = "\"" .. result .. "\""
	return result
end

dependencies = {
	basePath = "./deps"
}

function dependencies.load()
	dir = path.join(dependencies.basePath, "premake/*.lua")
	deps = os.matchfiles(dir)

	for i, dep in pairs(deps) do
		dep = dep:gsub(".lua", "")
		require(dep)
	end
end

function dependencies.imports()
	for i, proj in pairs(dependencies) do
		if type(i) == 'number' then
			proj.import()
		end
	end
end

function dependencies.projects()
	for i, proj in pairs(dependencies) do
		if type(i) == 'number' then
			proj.project()
		end
	end
end

newoption {
	trigger = "copy-to",
	description = "Optional, copy the EXE to a custom folder after build, define the path here if wanted.",
	value = "PATH"
}

newoption {
	trigger = "dev-build",
	description = "Enable development builds of the client."
}

newaction {
	trigger = "version",
	description = "Returns the version string for the current commit of the source code.",
	onWorkspace = function(wks)
		-- get current version via git
		local proc = assert(io.popen(gitVersioningCommand, "r"))
		local gitDescribeOutput = assert(proc:read('*a')):gsub("%s+", "")
		proc:close()
		local version = 'r' .. gitDescribeOutput

		proc = assert(io.popen(gitCurrentBranchCommand, "r"))
		local gitCurrentBranchOutput = assert(proc:read('*a')):gsub("%s+", "")
		local gitCurrentBranchSuccess = proc:close()
		if gitCurrentBranchSuccess then
			-- We got a branch name, check if it is a feature branch
			if gitCurrentBranchOutput ~= "master" then
				version = version .. " - " .. gitCurrentBranchOutput
			end
		end

		print(version)
		os.exit(0)
	end
}

newaction {
	trigger = "generate-buildinfo",
	description = "Sets up build information file like version.h.",
	onWorkspace = function(wks)
		-- get old version number from version.hpp if any
		local oldVersion = "(none)"
		local oldVersionHeader = io.open(wks.location .. "/src/version.h", "r")
		if oldVersionHeader ~= nil then
			local oldVersionHeaderContent = assert(oldVersionHeader:read('*l'))
			while oldVersionHeaderContent do
				local m = string.match(oldVersionHeaderContent, "#define VERSION \"(.+)\"%s*$")
				if m ~= nil then
						oldVersion = m
				end

				oldVersionHeaderContent = oldVersionHeader:read('*l')
			end
		end

		-- get current version via git
		local proc = assert(io.popen(gitVersioningCommand, "r"))
		local gitDescribeOutput = assert(proc:read('*a')):gsub("%s+", "")
		proc:close()
		local revision = 'r' .. gitDescribeOutput
		local version = revision

		proc = assert(io.popen(gitCurrentBranchCommand, "r"))
		local gitCurrentBranchOutput = assert(proc:read('*a')):gsub("%s+", "")
		local gitCurrentBranchSuccess = proc:close()
		if gitCurrentBranchSuccess then
			-- We got a branch name, check if it is a feature branch
			if gitCurrentBranchOutput ~= "stable" then
				version = version .. " - " .. gitCurrentBranchOutput
			end
		end
		
		if oldVersion == version then
			return
		end

		-- write version header
		local versionHeader = assert(io.open(wks.location .. "/src/version.h", "w"))
		versionHeader:write("/*\n")
		versionHeader:write(" * Automatically generated by premake5.\n")
		versionHeader:write(" * Do not touch!\n")
		versionHeader:write(" */\n")
		versionHeader:write("\n")
		versionHeader:write("#define REVISION_NUMBER " .. cstrquote(revision) .. "\n")
		versionHeader:write("#define BRANCH " .. cstrquote(gitCurrentBranchOutput) .. "\n")
		versionHeader:write("#define VERSION " .. cstrquote(version) .. "\n")
		if gitCurrentBranchOutput == "stable" then
			versionHeader:write("#define STABLE")
		end
		versionHeader:write("\n")
		versionHeader:close()

		local versionHeader = assert(io.open(wks.location .. "/src/version.hpp", "w"))
		versionHeader:write("/*\n")
		versionHeader:write(" * Automatically generated by premake5.\n")
		versionHeader:write(" * Do not touch!\n")
		versionHeader:write(" *\n")
		versionHeader:write(" * This file exists for reasons of complying with our coding standards.\n")
		versionHeader:write(" *\n")
		versionHeader:write(" * The Resource Compiler will ignore any content from C++ header files if they're not from STDInclude.hpp.\n")
		versionHeader:write(" * That's the reason why we now place all version info in version.h instead.\n")
		versionHeader:write(" */\n")
		versionHeader:write("\n")
		versionHeader:write("#include \".\\version.h\"\n")
		versionHeader:close()
	end
}


dependencies.load()

workspace "laochan-client"
startproject "client"
location "./build"
objdir "%{wks.location}/obj/"
targetdir "%{wks.location}/bin/%{cfg.platform}/%{cfg.buildcfg}"

configurations {"Debug", "Release"}

language "C++"
cppdialect "C++latest"

architecture "x86_64"
platforms "x64"

systemversion "latest"
symbols "On"
staticruntime "off"
editandcontinue "Off"
warnings "Extra"
characterset "ASCII"
floatingpoint "Fast"

if _OPTIONS["dev-build"] then
	defines {"DEV_BUILD"}
end

if os.getenv("CI") then
	defines {"CI"}
end

flags {"NoIncrementalLink", "NoMinimalRebuild", "MultiProcessorCompile", "No64BitChecks"}

filter "platforms:x64"
	defines {"_WINDOWS", "WIN32"}
filter {}

filter "configurations:Release"
	optimize "Speed"
	buildoptions {"/GL", "/arch:AVX2"}
	linkoptions {"/IGNORE:4702", "/IGNORE:4099", "/LTCG", "/NODEFAULTLIB:saucer.lib"}
	defines {"NDEBUG"}
	flags {"FatalCompileWarnings"}
filter {}

filter "configurations:Debug"
	optimize "Debug"
	defines {"DEBUG", "_DEBUG"}
	linkoptions {"/IGNORE:4099", "/NODEFAULTLIB:saucer.lib"}
filter {}

project "common"
kind "StaticLib"
language "C++"

disablewarnings { "4067" }

files {"./src/common/**.hpp", "./src/common/**.cpp"}

includedirs {"./src/common", "%{prj.location}/src"}

resincludedirs {"$(ProjectDir)src"}

dependencies.imports()

project "client"
kind "WindowedApp"
language "C++"

targetname "laochan_bootstrap64"

pchheader "std_include.hpp"
pchsource "src/client/std_include.cpp"

linkoptions {"/IGNORE:4254", "/DYNAMICBASE:NO", "/SAFESEH:NO", "/LARGEADDRESSAWARE", "/LAST:.main", "/PDBCompress"}

files {"./src/client/**.rc", "./src/client/**.hpp", "./src/client/**.cpp", "./src/client/resources/**.*"}

includedirs {"./src/client", "./src/common", "%{prj.location}/src"}

resincludedirs {"$(ProjectDir)src"}

links {"common"}

prebuildcommands {"pushd %{_MAIN_SCRIPT_DIR}", "tools\\premake5 generate-buildinfo", "popd"}

if _OPTIONS["copy-to"] then
	postbuildcommands {"copy /y \"$(TargetPath)\" \"" .. _OPTIONS["copy-to"] .. "\""}
end

dependencies.imports()

project "runner"
kind "WindowedApp"
language "C++"

files {"./src/runner/**.rc", "./src/runner/**.hpp", "./src/runner/**.cpp", "./src/runner/resources/**.*"}

includedirs {"./src/runner", "./src/common", "%{prj.location}/src"}

links {"common"}

resincludedirs {"$(ProjectDir)src"}

dependencies.imports()

group "Dependencies"
dependencies.projects()
