// Copyright (c) 2018-2024 Charlie Vanaret
// Licensed under the MIT license. See LICENSE file in the project directory for details.

#include <string>
#include "AMPLModel.hpp"
#include "optimization/Result.hpp"
#include "options/DefaultOptions.hpp"
#include "options/Options.hpp"
#include "options/Presets.hpp"
#include "tools/Logger.hpp"
#include "Uno.hpp"

/*
size_t memory_allocation_amount = 0;

void* operator new(size_t size) {
   memory_allocation_amount += size;
   std::cout << "Memory: " << size << '\n';
   return malloc(size);
}
*/

namespace uno {
   void run_uno_ampl(const std::string& model_name, Options& options) {
      const AMPLModel model(model_name);
      Uno uno{};
      Result result = uno.solve(model, options);
      if (result.optimization_status == OptimizationStatus::SUCCESS) {
         // check result.solution_status
      }
      else {
         // ...
      }
      if (options.get_bool("AMPL_write_solution_to_file")) {
         model.write_solution_to_file(result);
      }
      // std::cout << "memory_allocation_amount = " << memory_allocation_amount << '\n';
   }
} // namespace

int main(int argc, char* argv[]) {
   using namespace uno;

   if (argc == 1 || (argc == 2 && std::string(argv[1]) == "--v")) {
      std::cout << "Uno " << Uno::current_version() << '\n';
   }
   else if (argc == 2 && std::string(argv[1]) == "--dump-options") {
      // Print all available options (type + default value) for automated tools
      Options::dump_default_options();
   }
   else if (argc == 2 && std::string(argv[1]) == "--strategies") {
      Uno::print_available_strategies();
   }
   else {
      // AMPL expects: ./uno_ampl model.nl [-AMPL] [option_name=option_value, ...]
      // model name
      const char* model_name = argv[1];

      // gather the options
      Options options;
      DefaultOptions::load(options);
      // the -AMPL flag indicates that the solution should be written to the AMPL solution file
      size_t offset = 2;
      if (argc > 2 && std::string(argv[2]) == "-AMPL") {
         options.set_bool("AMPL_write_solution_to_file", true);
         ++offset;
      }
      else {
         options.set_bool("AMPL_write_solution_to_file", false);
      }
      // get the command line arguments (options start at index offset)
      const Options command_line_options = Options::get_command_line_options(argc, argv, offset);
      // possibly set options from an option file
      const auto optional_option_file = command_line_options.get_string_optional("option_file");
      if (optional_option_file.has_value()) {
         Options file_options = Options::load_option_file(*optional_option_file);
         options.overwrite_with(file_options);
      }
      // possibly set a preset
      const auto optional_preset = command_line_options.get_string_optional("preset");
      const Options preset_options = Presets::get_preset_options(optional_preset);
      options.overwrite_with(preset_options);
      // overwrite the options with the command line arguments
      options.overwrite_with(command_line_options);

      // solve the model
      Logger::set_logger(options.get_string("logger"));
      run_uno_ampl(model_name, options);
   }
   return EXIT_SUCCESS;
}
