/*
    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 TOPOLOGY_ENTITY_H
#define TOPOLOGY_ENTITY_H
//---------------------------------------------------------------------------


#include "mesh_const.h"
#include "comparators.h"

#include <algorithm>
#include <vector>


#include "entity.h"

using namespace std;

/**template for topology entities. This new class inherits from Entity
It creates a topolgy relationship between entities of type "A" and entities of type "B"
A and B may be of the same type. See inheritance for applications.*/
template<class A, class B> class Topology_Entity : public Entity

{
///the container used here
  typedef vector<A> Connected_A_Type;
///
  typedef vector<B> Connected_B_Type;

public:
///and some type redefinitions for general use
  typedef typename Connected_A_Type::iterator A_iterator;
///
  typedef typename Connected_B_Type::iterator B_iterator;
///
  typedef typename Connected_A_Type::const_iterator const_A_iterator;
///
  typedef typename Connected_B_Type::const_iterator const_B_iterator;


private:
///container members for each type of entities (a and b)
  Connected_A_Type as;
  Connected_B_Type bs;

///info kept if this topology is to be kept in the mesh
  bool swapable;

public:

  /**initialization of boolean variable swapable
  and reservation of some memory for the containers*/
  Topology_Entity ( void )
  {
    swapable=true;
    as.reserve ( 2 );
    bs.reserve ( 4 );
  }

///Topological entity constructor overloaded to set swapable variable
  Topology_Entity ( bool sw )
  {
    swapable=sw;
    as.reserve ( 2 );
    bs.reserve ( 4 );
  }

///returns swapable variable
  bool is_swapable ( void ) const
  {
    return swapable;
  }

///set_swapable sets the value of the bool variable if it has to be modified afterwards
  void set_swapable ( bool sw )
  {
    swapable=sw;
  }

///returns an iterator to the beginning of the container for A
  const_A_iterator A_begin ( void ) const
  {
    return as.begin();
  }

///returns an iterator to the end of the container for A
  const_A_iterator A_end ( void ) const
  {
    return as.end();
  }

///returns an iterator to the beginning of the container for B
  const_B_iterator B_begin ( void ) const
  {
    return bs.begin();
  }

///returns an iterator to the end of the container for B
  const_B_iterator B_end ( void ) const
  {
    return bs.end();
  }

///inserts an element  A
  void Add_A ( const A ele )
  {
//      as.insert(ele);
    Less_Ptr<A> pr;
    as.push_back ( ele );
    sort ( as.begin(),as.end(),pr ); //keep it sorted (for comparison)
  }

///inserts an element B
  void Add_B ( const B ele )
  {
//      bs.insert(ele);
    Less_Ptr<B> pr;
    bs.push_back ( ele );
    sort ( bs.begin(),bs.end(),pr );
  }

///Deletes an element A
  void Delete_A ( const A ele )
  {
//      as.erase(ele);
    A_iterator it = find ( as.begin(), as.end(), ele );

    if ( it!=as.end() )
    {
      as.erase ( it );
    }
  }

///Deletes an element B
  void Delete_B ( const B ele )
  {
//      bs.erase(ele);
    B_iterator it = find ( bs.begin(), bs.end(), ele );

    if ( it!=bs.end() )
    {
      bs.erase ( it );
    }
  }

///returns the number of elements A
  const int Get_Number_A ( void ) const
  {
    return as.size();
  }

///returns the number of elements B
  const int Get_Number_B ( void ) const
  {
    return bs.size();
  }

///get all elements of type A, into an user allocated array eles[]
  void Get_As ( A eles[] ) const
  {
    const_A_iterator j=as.begin();

    //j is a pointer (iterator) initialized to the first element of the container
    //Loop from beginning to the size of the container
    for ( int i=0; i<Get_Number_A(); ++i )
    {
      eles[i]=*j;
      ++j;
    }
  }

///get all elements of type B, into an user allocated array eles[]
  void Get_Bs ( B eles[] ) const
  {
    const_B_iterator j=bs.begin();

    //j is a pointer (iterator) initialized to the first element of the container
    //Loop from beginning to the size of the container
    for ( int i=0; i<Get_Number_B(); ++i )
    {
      eles[i]=*j;
      ++j;
    }
  }

///Equal_A checks if a topology entity of same kind has same elements A
  bool Equal_A ( const Topology_Entity<A,B>& T ) const
  {
    if ( Get_Number_A() !=T.Get_Number_A() )
    {
      return false;
    }

    const_A_iterator i=A_begin(),j=T.A_begin();

    //Loop over i and j with same increment as long as
    //end of A is not reached
    while ( i!=as.end() )
    {
      if ( ! ( *i==*j ) )
      {
        return false;
      }

      ++i;
      ++j;
    }

    return true;
  }


///Equal_B checks if a topology entity of same kind has same elements B
  bool Equal_B ( const Topology_Entity<A,B>& T ) const
  {

    if ( Get_Number_B() !=T.Get_Number_B() )
    {
      return false;
    }

    const_B_iterator i=B_begin(),j=T.B_begin();

    ///Loop over i and j with same increment as long as
    ///end of B is not reached
    while ( i!=bs.end() )
    {
      if ( ! ( *i==*j ) )
      {
        return false;
      }

      ++i;
      ++j;
    }

    return true;
  }

///Used to classify topology entities relatively to A (similar to operator < )
  bool Less_A ( const Topology_Entity<A,B>& T ) const
  {
    //if size < T size return true, otherwise false
    if ( Get_Number_A() !=T.Get_Number_A() )
    {
      if ( Get_Number_A() <T.Get_Number_A() )
      {
        return true;
      }

      if ( Get_Number_A() >T.Get_Number_A() )
      {
        return false;
      }
    }

    //if same size, initialize pointers i and j to the
    //the beginning of the ccontainer
    const_A_iterator i=A_begin(),j=T.A_begin();

    while ( i!=A_end() )
    {
      if ( & ( * ( *i ) ) <& ( * ( *j ) ) )
      {
        return true;  //comparing adress
      }

      //if ((*(*i)).GetID()<(*(*j)).GetID()) return true; //comparison with ID number . it's a flaw since ID numbers are not always distinct
      if ( ! ( ( *i ) == ( *j ) ) )
      {
        return false;
      }

      ++i;
      ++j;
    }

    return false;

  }

///Used to classify topology entities relatively to B (similar to operator < )
  bool Less_B ( const Topology_Entity<A,B>& T ) const
  {
    // if size < T size return true, otherwise false
    if ( Get_Number_B() !=T.Get_Number_B() )
    {
      if ( Get_Number_B() <T.Get_Number_B() )
      {
        return true;
      }

      if ( Get_Number_B() >T.Get_Number_B() )
      {
        return false;
      }
    }

    //if same size, initialize pointers i and j to the
    //the beginning of the container
    const_B_iterator i=B_begin(),j=T.B_begin();

    while ( i!=B_end() )
    {
      if ( & ( * ( *i ) ) <& ( * ( *j ) ) )
      {
        return true;  //comparing adress
      }

//          if ((*(*i)).GetID()<(*(*j)).GetID()) return true;//comparison with ID number . it's a flaw since ID numbers are not always distinct
      if ( ! ( ( *i ) == ( *j ) ) )
      {
        return false;
      }

      ++i;
      ++j;
    }

    return false;
  }

};
#endif // TOPOLOGY_ENTITY_H

 
