/*
    C++ Mesh Generation Library
    Copyright (c) 2000echet <eric at bechet dot ca>

    This file is part of the C++ Mesh Generation Library.

    See the NOTICE & LICENSE files for conditions.
*/

//---------------------------------------------------------------------------
#ifndef BIPOINT_H
#define BIPOINT_H
//---------------------------------------------------------------------------


#include "mesh_const.h"

#ifdef USE_HASH_TABLE
#include <hash_set>
#endif

#include <list>
#include <set>

#include "topology_entity.h"
#include "metric_field.h"


using namespace std;


///class used to formalize the concept of segment between 2 vertices
template<class V,class E> class Bipoint : public Topology_Entity<V,E>
{
public :

///Container type
  typedef list<Bipoint<V,E> > Container_Type;
///Container type iterator
  typedef typename Container_Type::iterator Iterator;


///1st type of classification (ordered vertices)
#ifndef USE_HASH_TABLE
  typedef set<Iterator,Less_Ptr_Type<Iterator> > Classification_A_Type;
#endif

#ifdef USE_HASH_TABLE
  typedef hash_set<Iterator,Hash_Ptr_Type<Iterator>,Equ_Ptr_Type<Iterator> > Classification_A_Type;
#endif
///1st Classification iterator
  typedef typename Classification_A_Type::iterator Classification_A_Iterator;

///2nd Type of classification (length of the segment)
  typedef multiset<Iterator,Less_Ptr_Size<Iterator> > Classification_B_Type;

///2nd Classification iterator
  typedef typename Classification_B_Type::iterator Classification_B_Iterator;


///general use iterators
  typedef typename Topology_Entity<V,E>::A_iterator TVertex_iterator;
///
  typedef typename Topology_Entity<V,E>::B_iterator TElement_iterator;
///
  typedef typename Topology_Entity<V,E>::const_A_iterator const_TVertex_iterator;
///
  typedef typename Topology_Entity<V,E>::const_B_iterator const_TElement_iterator;

private :
///back link to classifications (fast erase)
  Classification_A_Iterator IA;
///back link to classifications (fast erase)
  Classification_B_Iterator IB;

///size in the metric considered
  double metric_size;

public :

/// mandatory for hash_tables
  size_t hash() const
  {

    size_t hsh=0x0;
    const_TVertex_iterator it=Vertex_begin();
    const_TVertex_iterator itend=Vertex_end();

    while ( it!=itend )
    {
      hsh=hsh^ ( size_t ) & ( * ( *it ) );
      ++it;
    }

    return hsh;
  }

///Sets 1st class. iterator to It
  void Set_Classification_A_Iterator ( Classification_A_Iterator It )
  {
    IA=It;
  }

///Returns 1st cless. iterator
  Classification_A_Iterator Get_Classification_A_Iterator() const
  {
    return IA;
  }

///set 2nd class. iterator
  void Set_Classification_B_Iterator ( Classification_B_Iterator It )
  {
    IB=It;
  }

///returns 2nd class. iterator
  Classification_B_Iterator Get_Classification_B_Iterator() const
  {
    return IB;
  }

///Bipoint Class constructor initializes the metric_size to zero
  Bipoint()
  {
    metric_size=0.;
  }

  /**Bipoint constructor is overloaded to pass 2 Vertices iterators to initialize
  Then initializes metric_size to 0 */
  Bipoint ( V v1,V v2 )
  {
    ///Adds v1 and v2 into the set
    this->Add_A ( v1 );
    this->Add_A ( v2 );
    metric_size=0.;
  }

///sets the metrix size relatively to the metric field
  double Set_Metric_Size ( Metric_Field<typename V::value_type> &Field )
  {


    if ( this->Get_Number_A() ==2 )
    {
      const_TVertex_iterator i1=Vertex_begin();
      const_TVertex_iterator i2=i1;
      ++i2;
      metric_size=Field.Metric_Distance ( * ( *i1 ),* ( *i2 ) );
    }
    else
    {
      metric_size=0;
    }

    return metric_size;

  }

///returns an iterator pointing to the beginning of the container for vertices
  const_TVertex_iterator Vertex_begin ( void ) const
  {
    return this->A_begin();
  }

///returns an iterator pointing to the end of the container for vertices
  const_TVertex_iterator Vertex_end ( void ) const
  {
    return this->A_end();
  }

///returns an iterator pointing to the beginning of the container for elements
  const_TElement_iterator Element_begin ( void ) const
  {
    return this->B_begin();
  }

///returns an iterator pointing to the end of the container for elements
  const_TElement_iterator Element_end ( void ) const
  {
    return this->B_end();
  }

///Adds a vertex
  void Add_Vertex ( V const Ver )
  {
    this->Add_A ( Ver );
  }

///Adds an element
  void Add_Element ( E const Ele )
  {
    this->Add_B ( Ele );
  }

///Deletes an element
  void Delete_Element ( E const Ele )
  {
    this->Delete_B ( Ele );
  }

///returns the number of vertices
  const int Get_Number_Vertices ( void ) const
  {
    return this->Get_Number_A();
  }


///returns the number of elements
  const int Get_Number_Elements ( void ) const
  {
    return this->Get_Number_B();
  }

///Gets vertices into Ver[], user allocated array
  void Get_Vertices ( V Ver[] ) const
  {
    this->Get_As ( Ver );
  }

///Gets elements into Ele[], user allocated array
  void Get_Elements ( E Ele[] ) const
  {
    this->Get_Bs ( Ele );
  }


  /**operator == overloaded to check if two Bipoints are equivalent
  based on vertices*/
  bool operator == ( const Bipoint<V,E>& F ) const
  {
    return this->Equal_A ( F );
  }

  /**operator < overloaded to compare two Bipoints
  based on vertices*/
  bool operator < ( const Bipoint<V,E>& F ) const
  {
    return this->Less_A ( F );
  }


///returns the metric size
  const double Get_Metric_Size ( void ) const
  {
    return this->metric_size;
  }
};
#endif // BIPOINT_H

