//                                               -*- C++ -*-
/**
 *  @brief IpoptProblem implements the Ipopt::TNLP interface
 *
 *  Copyright 2005-2026 Airbus-EDF-IMACS-ONERA-Phimeca
 *
 *  This library is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This library 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 Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with this library.  If not, see <http://www.gnu.org/licenses/>.
 *
 */
#ifndef OPENTURNS_IPOPTPROBLEM_HXX
#define OPENTURNS_IPOPTPROBLEM_HXX

#include "openturns/OTprivate.hxx"
#include "openturns/OptimizationAlgorithmImplementation.hxx"

#define HAVE_CSTDDEF // for 3.11 in debian
#include <IpTNLP.hpp>

BEGIN_NAMESPACE_OPENTURNS

typedef ::Ipopt::TNLP::LinearityType * LinearityTypeTable;

class IpoptProblem
  : public ::Ipopt::TNLP
{

public:

  /** Constructor with parameters */
  IpoptProblem( const OptimizationProblem & optimProblem,
                const Point & startingPoint,
                const UnsignedInteger maximumCallsNumber);

  /** Retrieving objective function input.output history */
  Sample getInputHistory() const;
  Sample getOutputHistory() const;

  // n: number of variables
  // m: number of constraints

  bool get_nlp_info(int & n,
                    int & m,
                    int & nnz_jac_g, // Number of non-zero components in the Jacobian of g
                    int & nnz_h_lag, // Number of non-zero components in Hessian of Lagrangean
                    ::Ipopt::TNLP::IndexStyleEnum & index_style) override;

  bool get_variables_linearity( int n,
                                LinearityTypeTable var_types) override;

  bool get_constraints_linearity( int m,
                                  LinearityTypeTable const_types) override;

  bool get_bounds_info( int n,
                        double* x_l,  // Lower bounds
                        double* x_u,  // Upper bounds
                        int m,
                        double* g_l,  // Lower bounds
                        double* g_u) override; // Upper bounds

  bool get_starting_point(int n,
                          bool init_x,
                          double* x,
                          bool init_z,
                          double* z_L,
                          double* z_U,
                          int m,
                          bool init_lambda,
                          double* lambda) override;

  bool eval_f(int n,
              const double* x,
              bool new_x,
              double& obj_value) override;

  bool eval_grad_f( int n,
                    const double* x,
                    bool new_x,
                    double* grad_f) override;

  bool eval_g(int n,
              const double* x,
              bool new_x,
              int m,
              double* g) override;

  bool eval_jac_g(int n,
                  const double* x,
                  bool new_x,
                  int m,
                  int nele_jac,
                  int* iRow,
                  int *jCol,
                  double* values) override;

  bool eval_h(int n,
              const double* x,
              bool new_x,
              double obj_factor,
              int m,
              const double* lambda,
              bool new_lambda,
              int nele_hess,
              int* iRow,
              int* jCol,
              double* values) override;

  virtual void finalize_solution(::Ipopt::SolverReturn status, ::Ipopt::Index n,
                                 const ::Ipopt::Number* x, const ::Ipopt::Number* z_L,
                                 const ::Ipopt::Number* z_U, ::Ipopt::Index m, const ::Ipopt::Number* g,
                                 const ::Ipopt::Number* lambda, ::Ipopt::Number obj_value,
                                 const ::Ipopt::IpoptData* ip_data,
                                 ::Ipopt::IpoptCalculatedQuantities* ip_cq) override;

  virtual void setProgressCallback(OptimizationAlgorithmImplementation::ProgressCallback callBack, void * state = nullptr)
  {
    progressCallback_ = std::pair<OptimizationAlgorithmImplementation::ProgressCallback, void *>(callBack, state);
  }

  virtual void setStopCallback(OptimizationAlgorithmImplementation::StopCallback callBack, void * state = nullptr)
  {
    stopCallback_ = std::pair<OptimizationAlgorithmImplementation::StopCallback, void *>(callBack, state);
  }

private:
  // Clip point wrt problem bounds
  void clip(Point & xPoint) const;

  const OptimizationProblem optimProblem_;
  const Point startingPoint_;
  Sample evaluationInputHistory_;
  Sample evaluationOutputHistory_;

  // Callbacks
  UnsignedInteger maximumCallsNumber_ = 0;
  std::pair< OptimizationAlgorithmImplementation::ProgressCallback, void *> progressCallback_;
  std::pair< OptimizationAlgorithmImplementation::StopCallback, void *> stopCallback_;
};

END_NAMESPACE_OPENTURNS

#endif
