// elastic_genTerm_Cutmesh_Xfem - A linear solver for elastic problems using X-FEM
// Copyright (C) 2010-2026 Eric Bechet, Frederic Duboeuf
//
// See the LICENSE file for license information and contributions.
// Please report all bugs and problems to <bechet@cadxfem.org>.

#ifndef _SPACEREDUCERFORSTABLEMULTIPLIERS_H_
#define _SPACEREDUCERFORSTABLEMULTIPLIERS_H_


#include "simpleFunction.h"
#include "GModel.h"
#include "genGroupOfElements.h"
#include "gmshLevelset.h"
#include "dofManager.h"
// #include "OS.h"

class SpaceReducerForStableMultipliers
{
  private :
    typedef MVertex* NodeType;
    typedef std::pair<NodeType,NodeType> EdgeType;
    typedef std::pair<EdgeType,double> EdgeScoreType;

  private :
//     groupOfLagMultElements* _LevelSetElements;
    genGroupOfElements* _LevelSetElements;
    std::map<NodeType,EdgeType> _NodeToEdgeMap;
    std::set<EdgeType> _AllEdges; // set of all edges
    std::set<NodeType> _winner_nodes;
    std::set<NodeType> _looser_nodes;
    std::set<int> _PhysicalVertices; // set of edge'nodes of vital vertices
//     gLevelset* _ls;

  private :
    // field tag
    int _FieldTag;
    // decimation algorithm result in _winner_nodes set
    void SortNodes(void);
    // initialisation of needed sets
    void fillNodeToEdgeMap(std::set<EdgeType> &Se , std::set<NodeType> &Sn) ;
    // find edge in the element associate with node
    EdgeType findEdge(NodeType v, MElement* e);
    // verify if node belong to edge  // ...normaly has to be done when cutting model ...
    bool NodeBelongToEdge(NodeType v, EdgeType edge);
    // compute score
    void ComputeScore(std::set<EdgeType> &Se, std::set<NodeType> &Sn, std::map <NodeType , int> &NodesScore);
    // compute number of incident edges in Se to node v
    int ComputeIncidentEdges(std::set<EdgeType> &Se, NodeType &v);
    // compute number of incident edges in Se to node v
    int ComputeIncidentEdges(std::set<EdgeType> &Se, NodeType &v, std::set<NodeType> &Nr);
    // get lowest  (no need to sort just get the lowest)
    NodeType getNodeWithLowestScore(std::map <NodeType , int> &NodesScore);
    // kill connected edges
    void killConnectedEdges (std::set<EdgeType> &Se , std::set<NodeType> &Sn, NodeType v);
    void killConnectedEdges (std::set<EdgeType> &Se , std::set<NodeType> &Sn, NodeType v, std::map<NodeType, int> &NodesScore);

    // printing information
    int orig_stdout;
    fpos_t pos_stdout;
    void enablePrintInfo(bool enable) { /*fflush(stdout); fgetpos(stdout, &pos_stdout); orig_stdout=dup(fileno(stdout));  if (!enable) freopen("stdout.out", "w", stdout);*/ }
    void rebootPrintInfo() { /* fflush(stdout); dup2(orig_stdout, fileno(stdout)); close(orig_stdout); clearerr(stdout); fsetpos(stdout, &pos_stdout);*/ }

  public :
//     SpaceReducerForStableMultipliers(groupOfLagMultElements* LevelSetElements, int FieldTag) :  _FieldTag(FieldTag)
    SpaceReducerForStableMultipliers(genGroupOfElements* LevelSetElements, int FieldTag, bool enable=false) :  _FieldTag(FieldTag)
    {
      _LevelSetElements = LevelSetElements;
//      double t1 = Cpu();
//      printf("### SpaceReducerForStableMultipliers Algorithm Start t=0\n");
//      enablePrintInfo(enable);

      SortNodes();

//      rebootPrintInfo();
//      double t2 = Cpu();
//      printf("### SpaceReducerForStableMultipliers Algorithm Complete t=%gs\n", t2-t1);
    }
//     virtual void BuildLinearConstraints(dofManager<double>* pAssembler, const FilterDof &filter);
    virtual void BuildLinearConstraints( std::vector<int> &comps, dofManager<double>* pAssembler, bool enable=false);
    virtual void getWinnerNodes(std::set<MVertex*>* listHangingNodes)
    {
      listHangingNodes->clear();
      std::set<NodeType>::iterator it;
      for (it = _winner_nodes.begin(); it != _winner_nodes.end(); it++ )
      {
        MVertex* p = *it;
        listHangingNodes->insert(p);
      }
    }
};

#endif
