########################################################################
##
## Copyright (C) 2026 The Octave Project Developers
##
## See the file COPYRIGHT.md in the top-level directory of this
## distribution or <https://octave.org/copyright/>.
##
## This file is part of Octave.
##
## Octave is free software: you can redistribute it and/or modify it
## under the terms of the GNU General Public License as published by
## the Free Software Foundation, either version 3 of the License, or
## (at your option) any later version.
##
## Octave is distributed in the hope that it will be useful, but
## WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with Octave; see the file COPYING.  If not, see
## <https://www.gnu.org/licenses/>.
##
########################################################################

## -*- texinfo -*-
## @deftypefn {} {@var{cpp_file} =} __mcc_generate_main__ (@var{main_file}, @var{deps}, @var{output_name})
## Generate C++ wrapper code for standalone executable.
##
## This is an internal function used by @code{mcc}.
## @end deftypefn

function cpp_file = __mcc_generate_main__ (main_file, deps, output_name)

  [~, main_func, ~] = fileparts (main_file);
  
  ## Create temporary C++ file
  [fid, cpp_file] = mkstemp (fullfile (tempdir, "octave-mcc-XXXXXX"), true);
  if (fid < 0)
    error ("__mcc_generate_main__: could not create temporary C++ file");
  endif
  ## Add .cpp extension
  cpp_file = [cpp_file, ".cpp"];
  fclose (fid);
  ## Reopen for writing
  fid = fopen (cpp_file, "w");
  if (fid < 0)
    error ("__mcc_generate_main__: could not open temporary C++ file for writing");
  endif

  ## Generate C++ code
  ## Use direct includes for build tree compatibility
  cpp_code = sprintf (['// Auto-generated C++ wrapper for MCC standalone executable\n', ...
                       '// Main file: %s\n', ...
                       '// Generated by Octave MCC\n', ...
                       '\n', ...
                       '#include "oct.h"\n', ...
                       '#include "interpreter.h"\n', ...
                       '#include <iostream>\n', ...
                       '#include <string>\n', ...
                       '#include <vector>\n', ...
                       '\n', ...
                       'int main(int argc, char *argv[])\n', ...
                       '{\n', ...
                       '    // Initialize Octave interpreter\n', ...
                       '    string_vector octave_argv(2);\n', ...
                       '    octave_argv(0) = "%s";\n', ...
                       '    octave_argv(1) = "--no-gui";\n', ...
                       '    \n', ...
                       '    octave::interpreter interpreter;\n', ...
                       '    \n', ...
                       '    try {\n', ...
                       '        // Initialize Octave\n', ...
                       '        interpreter.initialize_history(false);\n', ...
                       '        interpreter.initialize_load_path(false);\n', ...
                       '        \n', ...
                       '        interpreter.initialize();\n', ...
                       '        \n', ...
                       '        // Load dependency files\n'], ...
                       main_file, output_name);

  ## Add code to load each dependency file
  for i = 1:length (deps)
    dep_file = deps{i};
    ## Escape single quotes in file path for C++ string
    dep_file_escaped = strrep (dep_file, "'", "''");
    dep_file_escaped = strrep (dep_file_escaped, "\\", "\\\\");
    [~, dep_func, ~] = fileparts (dep_file);
    ## Build the code string piece by piece to avoid sprintf issues
    cpp_code = [cpp_code, sprintf('        // Load: %s%c', dep_file, char(10))];
    cpp_code = [cpp_code, sprintf('        {%c', char(10))];
    cpp_code = [cpp_code, sprintf('            std::string code = "run(''%s'');";%c', dep_file_escaped, char(10))];
    cpp_code = [cpp_code, sprintf('            int parse_status = 0;%c', char(10))];
    cpp_code = [cpp_code, sprintf('            interpreter.eval_string(code, false, parse_status, 0);%c', char(10))];
    cpp_code = [cpp_code, sprintf('            if (parse_status != 0) {%c', char(10))];
    cpp_code = [cpp_code, sprintf('                std::cerr << "Warning: could not load %s" << std::endl;%c', dep_file, char(10))];
    cpp_code = [cpp_code, sprintf('            }%c', char(10))];
    cpp_code = [cpp_code, sprintf('        }%c', char(10))];
  endfor

  ## Add main function call
  cpp_code = [cpp_code, char(10)];
  cpp_code = [cpp_code, sprintf('        // Call main function%c', char(10))];
  cpp_code = [cpp_code, sprintf('        octave_value_list args;%c', char(10))];
  cpp_code = [cpp_code, sprintf('        %c', char(10))];
  cpp_code = [cpp_code, sprintf('        // Convert command-line arguments to Octave cell array%c', char(10))];
  cpp_code = [cpp_code, sprintf('        if (argc > 1) {%c', char(10))];
  cpp_code = [cpp_code, sprintf('            Cell argv_cell(argc - 1);%c', char(10))];
  cpp_code = [cpp_code, sprintf('            for (int i = 1; i < argc; i++) {%c', char(10))];
  cpp_code = [cpp_code, sprintf('                argv_cell(i-1) = octave_value(std::string(argv[i]));%c', char(10))];
  cpp_code = [cpp_code, sprintf('            }%c', char(10))];
  cpp_code = [cpp_code, sprintf('            args.append(octave_value(argv_cell));%c', char(10))];
  cpp_code = [cpp_code, sprintf('        }%c', char(10))];
  cpp_code = [cpp_code, sprintf('        %c', char(10))];
  cpp_code = [cpp_code, sprintf('        // Call the main function%c', char(10))];
  cpp_code = [cpp_code, sprintf('        octave_value_list result = interpreter.feval("%s", args, 0);%c', main_func, char(10))];
  cpp_code = [cpp_code, sprintf('        %c', char(10))];
  cpp_code = [cpp_code, sprintf('        // Exit status%c', char(10))];
  cpp_code = [cpp_code, sprintf('        int exit_status = 0;%c', char(10))];
  cpp_code = [cpp_code, sprintf('        if (result.length() > 0 && result(0).is_scalar_type()) {%c', char(10))];
  cpp_code = [cpp_code, sprintf('            exit_status = result(0).int_value();%c', char(10))];
  cpp_code = [cpp_code, sprintf('        }%c', char(10))];
  cpp_code = [cpp_code, sprintf('        %c', char(10))];
  cpp_code = [cpp_code, sprintf('        return exit_status;%c', char(10))];
  cpp_code = [cpp_code, sprintf('        %c', char(10))];

  ## Add error handling and closing
  cpp_code = [cpp_code, sprintf('    } catch (const octave::execution_exception& e) {%c', char(10))];
  cpp_code = [cpp_code, sprintf('        std::cerr << "Octave execution error: " << e.message() << std::endl;%c', char(10))];
  cpp_code = [cpp_code, sprintf('        return 1;%c', char(10))];
  cpp_code = [cpp_code, sprintf('    } catch (const std::exception& e) {%c', char(10))];
  cpp_code = [cpp_code, sprintf('        std::cerr << "Error: " << e.what() << std::endl;%c', char(10))];
  cpp_code = [cpp_code, sprintf('        return 1;%c', char(10))];
  cpp_code = [cpp_code, sprintf('    }%c', char(10))];
  cpp_code = [cpp_code, sprintf('    %c', char(10))];
  cpp_code = [cpp_code, sprintf('    return 0;%c', char(10))];
  cpp_code = [cpp_code, sprintf('}%c', char(10))];

  ## Write to file
  fprintf (fid, "%s", cpp_code);
  fclose (fid);

endfunction

