#pragma once

#include <alpaqa/util/problem.hpp>

#include <string>

namespace alpaqa {

/// @addtogroup grp_ExternalProblemLoaders
/// @{

#if 0
/// Load an objective function generated by CasADi.
std::function<alpaqa::Problem::f_sig>
load_CasADi_objective(const std::string &so_name,
                      const std::string &fun_name = "f");
/// Load the gradient of an objective function generated by CasADi.
std::function<alpaqa::Problem::grad_f_sig>
load_CasADi_gradient_objective(const std::string &so_name,
                               const std::string &fun_name = "grad_f");
/// Load a constraint function generated by CasADi.
std::function<alpaqa::Problem::g_sig>
load_CasADi_constraints(const std::string &so_name,
                        const std::string &fun_name = "g");
/// Load the gradient-vector product of a constraint function generated by
/// CasADi.
std::function<alpaqa::Problem::grad_g_prod_sig>
load_CasADi_gradient_constraints_prod(const std::string &so_name,
                                      const std::string &fun_name = "grad_g");
/// Load the Hessian of a Lagrangian function generated by CasADi.
std::function<alpaqa::Problem::hess_L_sig>
load_CasADi_hessian_lagrangian(const std::string &so_name,
                               const std::string &fun_name = "hess_L");
/// Load the Hessian-vector product of a Lagrangian function generated by
/// CasADi.
std::function<alpaqa::Problem::hess_L_prod_sig> load_CasADi_hessian_lagrangian_prod(
    const std::string &so_name, const std::string &fun_name = "hess_L_prod");
#endif

/// Load a problem generated by CasADi (without parameters).
///
/// @param  filename
///         Filename of the shared library to load the functions from.
/// @param  n
///         Number of decision variables (@f$ x \in \mathbb{R}^n @f$).
/// @param  m
///         Number of general constraints (@f$ g(x) \in \mathbb{R}^m @f$).
/// @param  second_order
///         Load the additional functions required for second-order PANOC.
///
/// The file should contain functions with the names `f`, `grad_f`, `g` and
/// `grad_g`. These functions evaluate the objective function, its gradient,
/// the constraints, and the constraint gradient times a vector respecitvely.
/// If @p second_order is true, additional functions `hess_L` and
/// `hess_L_prod` should be provided to evaluate the Hessian of the Lagrangian
/// and Hessian-vector products.
///
/// If any of the dimensions are zero, they are determined from the `g` function
/// in the given file.
///
/// @throws std::invalid_argument
///         The dimensions of the loaded functions do not match.
alpaqa::Problem load_CasADi_problem(const std::string &filename, unsigned n = 0,
                                unsigned m = 0, bool second_order = false);
/// Load a problem generated by CasADi (with parameters).
///
/// @param  filename
///         Filename of the shared library to load the functions from.
/// @param  n
///         Number of decision variables (@f$ x \in \mathbb{R}^n @f$).
/// @param  m
///         Number of general constraints (@f$ g(x) \in \mathbb{R}^m @f$).
/// @param  p
///         The number of parameters of the problem (second argument to all
///         CasADi functions).
/// @param  second_order
///         Load the additional functions required for second-order PANOC.
///
/// The file should contain functions with the names `f`, `grad_f`, `g` and
/// `grad_g`. These functions evaluate the objective function, its gradient,
/// the constraints, and the constraint gradient times a vector respecitvely.
/// If @p second_order is true, additional functions `hess_L` and
/// `hess_L_prod` should be provided to evaluate the Hessian of the Lagrangian
/// and Hessian-vector products.
///
/// If any of the dimensions are zero, they are determined from the `g` function
/// in the given file.
///
/// @throws std::invalid_argument
///         The dimensions of the loaded functions do not match.
/// 
ProblemWithParam load_CasADi_problem_with_param(const std::string &filename,
                                                unsigned n = 0, unsigned m = 0,
                                                unsigned p        = 0,
                                                bool second_order = false);

/// @}

} // namespace alpaqa