# A part of NonVisual Desktop Access (NVDA)
# Copyright (C) 2011-2025 NV Access Limited, Joseph Lee, Babbage B.V., Leonard de Ruijter
# This file may be used under the terms of the GNU General Public License, version 2 or later, as modified by the NVDA license.
# For full terms and any additional permissions, see the NVDA license file: https://github.com/nvaccess/nvda/blob/master/copying.txt

import os
import re
import glob
from SCons.Tool.MSCommon.vc import find_vc_pdir
import typing
from SCons.Environment import Environment
from SCons.Environment import Base

Import(
	[
		"thirdPartyEnv",
		"sourceDir",
	]
)
sourceDir: Base = sourceDir
thirdPartyEnv: Environment = thirdPartyEnv
env: Environment = typing.cast(Environment, thirdPartyEnv.Clone())

louisRootDir = env.Dir("#include/liblouis")
louisSourceDir = louisRootDir.Dir("liblouis")
louisTableDir = louisRootDir.Dir("tables")
outDir = sourceDir.Dir("louis")
unitTestTablesDir = env.Dir("#tests/unit/brailleTables")
signExec = env["signExec"] if sum(bool(x) for x in (env["certFile"], env["apiSigningToken"], env["humanwareSign"])) == 1 else None

RE_AC_INIT = re.compile(
	r"^AC_INIT\(\[(?P<package>.*)\], \[(?P<version>.*)\], \[(?P<bugReport>.*)\], \[(?P<tarName>.*)\], \[(?P<url>.*)\]\)"
)


def getLouisVersion():
	# Get the version from configure.ac.
	with open(louisRootDir.File("configure.ac").abspath) as f:
		for line in f:
			m = RE_AC_INIT.match(line)
			if m:
				return m.group("version")
	return "unknown"


# Liblouis is build with Clang, as Microsoft Visual C++ is unable to build C99 code.
clangDirs = glob.glob(os.path.join(find_vc_pdir(env.get("MSVC_VERSION"), env), r"Tools\Llvm\bin"))
if len(clangDirs) == 0:
	raise RuntimeError(
		"Could not find the Clang compiler. "
		"Perhaps the C++ Clang tools for Windows component in visual Studio is not installed"
	)
env["CC"] = "clang-cl"
env["M4"] = f'"{env.File("#miscdeps/tools/m4.exe")}"'
# Liblouis disables GNU extensions for m4
env.Append(M4FLAGS="-G")
# Don't analyze the code as not our project
if "analyze" in env["nvdaHelperDebugFlags"]:
	env.Append(CCFLAGS="/analyze-")

if env["TARGET_ARCH"] in ("x86_64", "arm64"):
	# We need to build as 64-bit
	env.Append(CCFLAGS="-m64")

env.Append(
	CPPDEFINES=[
		# The Visual C++ C Runtime deprecates standard POSIX APIs that conflict with
		# reserved ISO C names (like strdup) in favour of non-portable conforming
		# variants that start with an '_'. This removes those deprecation warnings. */
		"_CRT_NONSTDC_NO_DEPRECATE",
		("PACKAGE_VERSION", r"\"%s\"" % getLouisVersion()),
		"WIDECHARS_ARE_UCS4",
		# Tell liblouis.h that we're exporting liblouis dll functions, not importing them.
		"_EXPORTING",
	]
)
env.Prepend(CPPPATH=[".", louisSourceDir])

# Upstream liblouis compiles without UNICODE defined.
env["CPPDEFINES"].remove("UNICODE")

liblouisH = env.Substfile(
	"liblouis.h", louisSourceDir.File("liblouis.h.in"), SUBST_DICT={"@WIDECHAR_TYPE@": "unsigned int"}
)

sourceFiles = [
	"compileTranslationTable.c",
	"lou_translateString.c",
	"lou_backTranslateString.c",
	"logging.c",
	"pattern.c",
	"commonTranslationFunctions.c",
	"metadata.c",
	"utils.c",
]
objs = [env.Object("%s.obj" % f, louisSourceDir.File(f)) for f in sourceFiles]
louisLib = env.SharedLibrary("liblouis", objs)
if signExec:
	env.AddPostAction(louisLib[0], [signExec])
env.Install(sourceDir, louisLib)

louisPython = env.Substfile(
	outDir.File("__init__.py"),
	louisRootDir.File("python/louis/__init__.py.in"),
	SUBST_DICT={"###LIBLOUIS_SONAME###": louisLib[0].name},
)

env.Install(
	outDir.Dir("tables"),
	[
		f
		for f in env.Glob(f"{louisTableDir}/*")
		if f.name
		not in (
			"Makefile.am",
			"README",
			"maketablelist.sh",
		)
		and not f.name.endswith(".in")
	],
)
# Tables containing macros
for f in env.Glob(f"{louisTableDir}/*.in"):
	env.M4(source=f, target=outDir.Dir("tables").File(os.path.splitext(f.name)[0]))
# Custom tables unit test
testTable = env.InstallAs(unitTestTablesDir.File("test.utb"), louisTableDir.File("en-us-comp8-ext.utb"))
env.Depends(
	testTable,
	env.Install(
		unitTestTablesDir,
		[louisTableDir.File("latinLetterDef8Dots.uti"), louisTableDir.File("en-us-comp8-ext.utb")],
	),
)
# Ensure the braille tables for tests are installed when copying the louis wrapper
env.Depends(louisPython, testTable)
