%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Build static library for multiple platforms and optionally copy
% them into the default TwinCAT Target custom libraries folder
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Beckhoff Automation GmbH
% 28.10.2024
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function BuildLibProject(projectPath,libdir,modelname)
	%% Build Settings
    % Check system software
    x64Matlab = strcmp(computer('arch'),'win64');
    try
        if (x64Matlab)
			tcbuildKeyPath = 'SOFTWARE\WOW6432Node\Beckhoff\TwinCAT3\System\';
		else
			tcbuildKeyPath = 'SOFTWARE\Beckhoff\TwinCAT3\System\';
		end
		tcbuild = winqueryreg('HKEY_LOCAL_MACHINE',tcbuildKeyPath,'Build');   
    catch
        error('No TwinCAT 3 detected. Please make sure, you installed it correctly.');
        return;
    end
    
    if (tcbuild < 4024)
        res = getenv('WINDDK7');
        if isempty(res)
            error('WINDDK7 is not setup/installed correctly. Please make sure, you installed it correctly and set up the enviroment variable.');
            return;
        end
    end
     
	% Library project settings
	libproject = [projectPath '.vcxproj'];

	% Library package copy settings
	if (nargin < 2)
		libdir = '';
	end
	libPackage = [projectPath '\LibPackage'];
    
    % Library platforms and configurations
    enablex64platform = 0;
    try
        tctVer = TctModuleGenerator('GETVERSION','TCT');
    catch
        error('TE1400 is not setup/installed correctly. Please make sure, you installed it correctly and run the SetupTwinCatTarget.p file in Matlab.');
        return;
    end    
        
    if (~isempty(tctVer.Output) && str2double(tctVer.Output)>=1.1)
        enablex64platform = 1; 
    end
    
    x64Platforms = '';
    x86Platforms = '';
    load_system(modelname);
    
    if (strcmp(get_param(bdroot, 'TCT_BUILD_TWINCAT_RT_X64'), 'on') && enablex64platform)
        x64Platforms{end+1} = 'TwinCAT RT (x64)';
    end
    if (strcmp(get_param(bdroot, 'TCT_BUILD_TWINCAT_RT_X86'), 'on'))
        x86Platforms{end+1} = 'TwinCAT RT (x86)';
    end
    if (strcmp(get_param(bdroot, 'TCT_BUILD_TWINCAT_UM_X64'), 'on') && enablex64platform)
        x64Platforms{end+1} = 'TwinCAT UM (x64)';
    end
    if (strcmp(get_param(bdroot, 'TCT_BUILD_TWINCAT_UM_X86'), 'on'))
        x86Platforms{end+1} = 'TwinCAT UM (x86)';
    end
    
    platforms = x86Platforms;
    platforms = horzcat(platforms, x64Platforms);
    platforms = horzcat(platforms, mexBuildPlatform());
    
    toolset = '';
	configurations = {'Debug' , 'Release'};

	%% Build environment
	% Path to msbuild.exe
	msbuildbinpath = '';
    % Visual Studio 2010 and Visual Studio 2012 use both msbVer 4 and the
    % Visual Studio 2015 up to Visual Studio 2019 use msbVer 14
	for msbVer = [14 12 4]
		try
			if (x64Matlab)
				msbuildKeyPath = ['SOFTWARE\Wow6432Node\Microsoft\MSBuild\ToolsVersions\' num2str(msbVer) '.0'];
			else
				msbuildKeyPath = ['SOFTWARE\Microsoft\MSBuild\ToolsVersions\' num2str(msbVer) '.0'];
			end
			msbuildToolsPath = winqueryreg('HKEY_LOCAL_MACHINE',msbuildKeyPath,'MsBuildToolsPath');
			msbuildbinpath = fullfile(msbuildToolsPath,'msbuild.exe');
			if (exist(msbuildbinpath,'file'))
				toolset = strcat('v',num2str(msbVer),'0');
                break;
			end
		catch
			%warning(['Installation of msbuild.exe ' num2str(msbVer) '.0 was not found']);
		end
	end
	if (~exist(msbuildbinpath,'file'))
		error('Sorry, no msbuild.exe was found at the predefined location. Please type the correct path into this M-File.');
	end
	
	% MEX build environment
	setenv('MATLAB_RELEASE',['R' version('-release')]);
	setenv('MATLAB_ROOT',[matlabroot '\']);

	%% Build script
	% Build for all configurations and platforms
	for pIdx = 1:length(platforms)
		for cIdx = 1:length(configurations)
			buildCmd = sprintf('"%s" "%s" /p:Configuration="%s";Platform="%s";PlatformToolset="%s"',msbuildbinpath,libproject,configurations{cIdx},platforms{pIdx},toolset);
			[status,result] = system(buildCmd);
			if (status==0)
				fprintf('Build of "%s" succeeded for "%s|%s"\n',libproject,platforms{pIdx},configurations{cIdx});
			else
				fprintf('!! Build of "%s" failed for "%s|%s"\n',libproject,platforms{pIdx},configurations{cIdx});
				error(result);
            end
		end
	end

	% Copy lib package
	if (~isempty(libdir))
		if (~isdir(libdir))
			mkdir(libdir);
		end
		disp(['Copying files to "' libdir '"...']);
		copyfile(libPackage,libdir);

		% add path (in case it has not been set previously)
		addpath([libdir '\' computer('arch') '\R' version('-release')]);
	end
end

function pltfrm = mexBuildPlatform()
	% Determine current MEX build platform
	if (strcmpi(computer('arch'),'Win64'))
		pltfrm = 'x64';
	else
		pltfrm = 'Win32';
	end
end

function devEnvDir = devEnvDir()
	% find visual studio installation folder
	devEnvDir = '';
	for vsVer = [16 15 14 12 11 10]
		if (~isempty(devEnvDir))
			break;
		end
		for vsKey={'SOFTWARE\Microsoft\VisualStudio\' 'SOFTWARE\Wow6432Node\Microsoft\VisualStudio\'}
			if (~isempty(devEnvDir))
				break;
			end
			try
				key = [vsKey{1} num2str(vsVer) '.0'];
				devEnvDir = winqueryreg('HKEY_LOCAL_MACHINE', key , 'InstallDir');
			end
		end
	end
	if isempty(devEnvDir)
		error('Could not find "VisualStudio 2010..19" on your system. Please make sure, you installed it correctly.');
	end
	setenv('DevEnvDir',devEnvDir);
end