// Copyright (C) 2025 EDF
// All Rights Reserved
// This code is published under the GNU Lesser General Public License (GNU LGPL)
#ifndef  MESH1D_H
#define  MESH1D_H
#include <memory>
#include <vector>
#include <array>
#include <math.h>
#include <iostream>
#include <Eigen/Dense>
#include "StOpt/core/utils/constant.h"

/** \file Mesh1D.h
 * \brief Defines a 1D mesh used in a 1 dimensional adaptive grid
 * \author  Pierre Gruet
 */

namespace StOpt
{
  /// \class Mesh1D.h Mesh1D.h
  /// defines a class for a 1D mesh
  class Mesh1D
  {
  private:
    
    double m_xL ; // Left coordinate
    double m_xR; // right coordinate

    int m_verticeL; // vertices left -> point number
    int m_verticeR; // vertices right -> point number

  public:

    /// \param p_xL left  x coordinate
    /// \param p_xR right x coordinate
    /// \param  p_verticeL point number in grid of vertice left
    /// \param  p_verticeR point number in grid of vertice right
    Mesh1D( const double & p_xL,    const double & p_xR, const int & p_verticeL , const int & p_verticeR): m_xL(p_xL), m_xR( p_xR), m_verticeL( p_verticeL), m_verticeR( p_verticeR)
      {
      }

    /// \brief  split a mesh in 2 meshes of equal size
    /// \param  list of existing points
    /// \return 2 new mesh, coordinates of the new point with increasing number in above grid
    inline std::pair< std::array< std::shared_ptr< Mesh1D > ,2 > , std::vector<Eigen::ArrayXd > > split(const std::vector< Eigen::ArrayXd > & p_vertices) const
      {
	int idec =p_vertices.size();
	std::vector<Eigen::ArrayXd > ptToAdd;
	ptToAdd.reserve(1);
	// add middle point
	int iptLR= idec++;
	ptToAdd.push_back({{0.5*(m_xL+m_xR)}});
	
	std::array< std::shared_ptr< Mesh1D > ,2 > mesh =  {std::make_shared<Mesh1D>(m_xL, 0.5*(m_xL+m_xR), m_verticeL, iptLR),
	      std::make_shared<Mesh1D>(0.5*(m_xL+m_xR), m_xR, iptLR, m_verticeR)};
	// std::cout << " SPLI PT TO ADD " ;
	// for (const auto  & pt :ptToAdd)
	//   std::cout << " pt " << pt[0] ;
	// std::cout << std::endl ;
	return std::make_pair( mesh, ptToAdd);	      
      }

    
    inline double getXL() const { return m_xL;}
    inline double getXR() const { return m_xR;}
    inline int getVerticeL() const { return   m_verticeL;}
    inline int getVerticeR() const { return   m_verticeR;}

    
  };
}
#endif
