// Cutmesh - Copyright (C) 2010-2018 T. Mouton, E. Bechet 
//
// See the LICENSE file for license information and contributions.
// bugs and problems to <thibaud.mouton@gmail.com>.

#ifndef _CADLEVELSET_CUTMESH_H_
#define _CADLEVELSET_CUTMESH_H_

#include "GModel.h"
#include "discreteSurface.h"
#include "mesh.h"
#include "brep.h"


class cadLevelset
{
  private:
    GModel *_pModel;
    GModel *_pModelCut;
    Mesh *_m;
    options *_opts;

    LVertex *_min;
    LVertex *_max;

    std::vector<DiscreteSurface *> _lsurf;
    std::map<GVertex*, int> _gvertex_map;
    std::map<GEdge*, int> _gedge_map;
    std::map<GFace*, int> _gface_map;

    std::vector<double> _d;
    std::vector<double> _projd;
  public:

    cadLevelset ( options *opt, Mesh *m )
    {
      _pModel = new GModel;
      _m = m;
      _opts = opt;
    }
    ~cadLevelset() {if(_pModel) delete _pModel;}

    inline void init_dist()
    {
      _projd.clear();
      _projd.resize ( _m->vertex_size(), INFINITY );
      _d.clear();
      _d.resize ( _m->vertex_size(), INFINITY );
    }

    inline double get_dist ( LVertex *v )
    {
      int i = v->getIndex();
      assert ( i<_m->vertex_size() );
      return _d[i];
    }

    inline void set_dist ( LVertex *v, double d )
    {
      int i = v->getIndex();
      assert ( i<_m->vertex_size() );
      _d[i] = d;
    }

    inline double get_proj_dist ( LVertex *v )
    {
      int i = v->getIndex();
      assert ( i<_m->vertex_size() );
      return _projd[i];
    }

    inline void set_proj_dist ( LVertex *v, double d )
    {
      int i = v->getIndex();
      assert ( i<_m->vertex_size() );
      _projd[i] = d;
    }

    void readLsnFile();

    void compute_bounds();

    void build_surfaces();
    void build_mesh_box();

    void refine_mesh();
    void process();

    inline void read_step()
    {
      char filename[100];
      sprintf ( filename, "%s.step", _opts->basename );
      _pModel->readOCCSTEP ( filename );
    }

    GModel *get_gmodel()
    {
      return _pModel;
    }

    int intersected ( DiscreteSurface *surf, LTetra *t, int *out );
    LTetra* init_intersected ( DiscreteSurface *surf, LTetra *init );
    LTetra* search_intersected ( DiscreteSurface *surf, LTetra *init );
    void build_support ( DiscreteSurface *surf/*, std::vector<LTetra *> &support*/ );
    void compute_edge_lenght ( GEdge *edge, double tol, std::list<LVertex>& vlist, std::list<double>& plist );
    DiscreteSurface *add_levelset_if_tangetial_edge ( GEdge *edge, double curv_tol, double dotmin, int max_step );

};

#endif
