% Description: Forms a mex-build-command.
% Documentation: building_timmatlab.txt
function commandSet = form_build_command(fileSet, varargin)
% Determine the bitness of the running Matlab version
% (not of the operating system or the computer).
[ignore, maxArraySize] = computer;
bits = 32;
if maxArraySize >= 2^32
    bits = 64;
end
% Add Pastel to Matlab path so that
% process_options is available.
addpath(['${PastelDirectory}', '/matlab']);
% Optional input arguments
mode = 'release';
verbose = 'off';
run = false;
defineSet = {};
librarySet = {};
outputDirectory = '.';
libraryDirectorySet = {};
includeDirectorySet = {};
outputLibraryName = '';
eval(pastelmatlab.process_options(...
    {'includeDirectorySet', 'libraryDirectorySet', ...
    'defineSet', 'outputDirectory', 'librarySet', ...
    'mode', 'verbose', 'run', 'outputLibraryName'}, ...
    varargin));
modeSet = {'debug', 'release', 'relwithdebinfo'};
if ~ismember(mode, modeSet)
    error(['MODE must be one of debug, release, or relwithdebinfo.']);
end
verboseSet = {'on', 'off'};
if ~ismember(verbose, verboseSet)
    error(['VERBOSE must be one on or off.']);
end
printOutputLibraryName = outputLibraryName;
if isempty(outputLibraryName)
    printOutputLibraryName = '<default-name>';
end
disp(' ');
disp(['Building a mex file for ', ...
    printOutputLibraryName, ...
    ' in ', ...
    num2str(bits), '-bit ', ...
    mode, ' mode.']);
disp(' ');
generatedBits = ${GENERATOR_BITS};
if bits ~= generatedBits
    error(['Build file is ', num2str(generatedBits), '-bit, but ', ...
        'Matlab is ', num2str(bits), '-bit. ', ...
        'Switch to ', num2str(bits), '-bit Matlab, or regenerate the build-file with a ', ...
        num2str(bits), '-bit CMake generator.'])
end
% Handle semicolon-separated lists
% --------------------------------
function resultSet = breakSemicolons(stringSet)
    resultSet = {};
    for i = 1 : numel(stringSet)
        string = stringSet{i};
        splitSet = regexp(string, ';', 'split');
        resultSet = [resultSet, splitSet];
    end
end
includeDirectorySet = breakSemicolons(includeDirectorySet);
libraryDirectorySet = breakSemicolons(libraryDirectorySet);
librarySet = breakSemicolons(librarySet);
% Preprocessor definitions 
% ------------------------
defineSet{end + 1} = '_ITERATOR_DEBUG_LEVEL=0';
% Form the build-command
% ----------------------
commandSet = {};
commandSet{end + 1} = 'mex';
for i = 1 : numel(fileSet)
    commandSet{end + 1} = [' ', fileSet{i}];
end
% Add preprocessor definitions.
for i = 1 : numel(defineSet)
    commandSet{end + 1} = [' -D', defineSet{i}];
end
% Add include paths.
for i = 1 : numel(includeDirectorySet)
    commandSet{end + 1} = [' -I''', includeDirectorySet{i}, ''''];
end
% Add library directories.
for i = 1 : numel(libraryDirectorySet)
    libraryDirectory = libraryDirectorySet{i};
    if isempty(libraryDirectory)
        % No directory was specified; skip it.
        continue;
    end
    [iStart, iEnd] = regexp(libraryDirectory, '\.framework$');
    if ~isempty(iStart) && ismac()
        % This is a framework directory.
        commandSet{end + 1} = [' LDFLAGS=''$LDFLAGS -F ', libraryDirectory, ''''];
    else
        % This is a normal library directory.
        commandSet{end + 1} = [' -L''', libraryDirectory, ''''];
    end
end
% Add output path.
commandSet{end + 1} = [' -outdir ''', outputDirectory, ''''];
% Add output name.
if ~isempty(outputLibraryName)
    commandSet{end + 1} = [' -output ''', outputLibraryName, ''''];
end
% Add libraries.
for i = 1 : numel(librarySet)
    library = librarySet{i};
    if isempty(library)
        % No library was specified; skip it.
        continue;
    end
    [iStart, iEnd] = regexp(library, '\.framework$');
    if ~isempty(iStart) && ismac()
        % This is a framework (Mac OS X).
        % Get the framework name by stripping out the
        % trailing '.framework'.
        frameworkName = library(1 : iStart - 1);
        % Mex does not have a direct flag to specify
        % frameworks. Instead, we embed it directly
        % into compiler flags.
        commandSet{end + 1} = [' CXXLIBS=''$CXXLIBS -framework ', frameworkName, ''''];
    else
        % This is a normal library.
        commandSet{end + 1} = [' -l', librarySet{i}];
    end
end
% Other flags.
if strcmp(mode, 'debug')
    if strcmp('${CompilerId}', 'msvc')
        % Use debug-mode C++ standard library.
        commandSet{end + 1} = ' -g COMPFLAGS="$COMPFLAGS /MDd"';
    else
        commandSet{end + 1} = ' -g';
    end
end
if strcmp(mode, 'relwithdebinfo') 
    commandSet{end + 1} = ' -g';
end
if strcmp(verbose, 'on')
    commandSet{end + 1} = ' -v';
end
% Run the build-command
% ---------------------
if run
    % Print the executed build-command in pretty form.
    for i = 1 : numel(commandSet)
        disp(commandSet{i});
    end
    % Run the command.
    buildCommand = [commandSet{:}];
    eval(buildCommand);
end
end