// 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 _BREP_CUTMESH_H_
#define _BREP_CUTMESH_H_

#include "common.h"

class BRepEntity
{
  protected:
    std::vector<int> _surf;
    std::vector<int> _adj;
    int _index;
    int _flag;
  public:
    BRepEntity ( int index )
    {
      _index = index;
      _flag = -1;
    }
    inline void add_surf ( int s )
    {
      for ( int i = 0; i < _surf.size(); i++ )
        if ( _surf[i] == s )
          return;
      _surf.push_back ( s );
    }
    inline int get_surf ( int i )
    {
      assert ( i < _surf.size() );
      return _surf[i];
    }
    inline int surf_size()
    {
      return _surf.size();
    }
    inline int equal ( std::vector<int> surf )
    {
      if ( surf_size() == surf.size() )
      {
        for ( int i = 0; i < surf.size(); i++ )
          if ( get_surf ( i ) != surf[i] )
            return 0;
        return 1;
      }
      return 0;
    }
    inline int equal ( BRepEntity *be )
    {
      if ( surf_size() == be->surf_size() )
      {
        for ( int i = 0; i < be->surf_size(); i++ )
          if ( get_surf ( i ) != be->get_surf ( i ) )
            return 0;
        return 1;
      }
      return 0;
    }
    inline void add_adj ( int a )
    {
      for ( int i = 0; i < _adj.size(); i++ )
        if ( _adj[i] == a )
          return;
      _adj.push_back ( a );
    }
    inline int get_adj ( int i )
    {
      assert ( i < _adj.size() );
      return _adj[i];
    }
    inline int adj_size()
    {
      return _adj.size();
    }
    inline int index()
    {
      return _index;
    }
    inline void setFlag ( int f )
    {
      _flag = f;
    }
    inline void incFlag ()
    {
      _flag++;
    }
    inline void decFlag ()
    {
      _flag--;
    }
    inline int getFlag()
    {
      return _flag;
    }
};

class BRepModel
{
  protected:
    std::vector<BRepEntity*> _vertices;
    std::vector<BRepEntity*> _edges;
    std::vector<BRepEntity*> _faces;
    std::vector<BRepEntity*> _volumes;

    std::multimap<int, BRepEntity*> _occurence;
    std::map<int, BRepEntity*> _vertex_map;
    std::map<int, BRepEntity*> _edge_map;
    std::map<int, BRepEntity*> _face_map;
    std::map<int, BRepEntity*> _volume_map;

  public:
    inline void add_vertex ( BRepEntity* bev )
    {
      _vertices.push_back ( bev );
      map_insert ( bev );
      _vertex_map.insert ( std::pair<int, BRepEntity*> ( bev->index(), bev ) );
    }
    inline void add_edge ( BRepEntity* bee )
    {
      _edges.push_back ( bee );
      map_insert ( bee );
      _edge_map.insert ( std::pair<int, BRepEntity*> ( bee->index(), bee ) );
    }
    inline void add_face ( BRepEntity* bef )
    {
      _faces.push_back ( bef );
      map_insert ( bef );
      _face_map.insert ( std::pair<int, BRepEntity*> ( bef->index(), bef ) );
    }
    inline void add_volume ( BRepEntity* bef )
    {
      _volumes.push_back ( bef );
      map_insert ( bef );
      _volume_map.insert ( std::pair<int, BRepEntity*> ( bef->index(), bef ) );
    }
    inline int vertex_size()
    {
      return _vertices.size();
    }
    inline BRepEntity *get_vertex ( int i )
    {
      assert ( i < _vertices.size() );
      return _vertices[i];
    }
    inline BRepEntity *get_vertex_by_index ( int index )
    {
      std::map<int, BRepEntity*>:: iterator it = _vertex_map.find ( index );
      if ( it != _vertex_map.end() )
        return it->second;
      return NULL;
    }
    inline int edge_size()
    {
      return _edges.size();
    }
    inline BRepEntity *get_edge ( int i )
    {
      assert ( i < _edges.size() );
      return _edges[i];
    }
    inline BRepEntity *get_edge_by_index ( int index )
    {
      std::map<int, BRepEntity*>:: iterator it = _edge_map.find ( index );
      if ( it != _edge_map.end() )
        return it->second;
      return NULL;
    }
    inline int face_size()
    {
      return _faces.size();
    }
    inline BRepEntity *get_face ( int i )
    {
      assert ( i < _faces.size() );
      return _faces[i];
    }
    inline int volume_size()
    {
      return _volumes.size();
    }
    inline BRepEntity *get_volume ( int i )
    {
      assert ( i < _volumes.size() );
      return _volumes[i];
    }
    inline BRepEntity *get_volume_by_index ( int index )
    {
      std::map<int, BRepEntity*>:: iterator it = _volume_map.find ( index );
      if ( it != _volume_map.end() )
        return it->second;
      return NULL;
    }
    void map_insert ( BRepEntity* be );
    void map_remove ( BRepEntity* be );
    void query ( BRepEntity* be, std::vector<BRepEntity*> &result );
    void query ( std::vector<int> surf, std::vector<BRepEntity*> &result );
    void set_associated ( BRepEntity* be );
};

#endif
