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


#include "mesh_const.h"

#ifdef USE_HASH_TABLE
#include <hash_set>
#endif

#include <list>
#include <algorithm>
#include <vector>

#include "linear_algebra.h"
#include "entity.h"
#include "mesh_globals.h"
#include "comparators.h"

using namespace std;

/**Vertex_Base used to store coordinates for a node of any dimension
Note that the dimension is passed as an argument "N" in the template*/
template<int N> class Vertex_Base : public Entity
{
protected:
///array of coordinates
  double coord[N];

///mandatory for hash tables (type definition for the hash function)
  union hsh_base
  {
    double coords[N];
    size_t machin[ ( N*sizeof ( double ) ) /sizeof ( size_t )];
  };

public:
///gets the dimension of a previously declared vertex if needed
  enum {Dimension=N};


///mandatory for hash tables (hash function)
  size_t hash() const
  {
    const hsh_base *toto;
    toto= ( hsh_base* ) coord;
    size_t hsh=0x0;

    for ( int i=0; i< ( N*sizeof ( double ) ) /sizeof ( size_t ); ++i )
    {
      hsh=hsh^toto->machin[i];
    }

    return hsh;
  }

///returns a pointer to the first element coord[0]
  const double* GetPos() const
  {
    return coord;
  }

///returns the current dimension
  static int GetDimension()
  {
    return Dimension;
  }

///initializes the coordinates to zero
  virtual void Zero ( void )
  {
    for ( int i=0; i<N; ++i )
    {
      coord[i]=0.0;
    }
  }

  /**passes a -pointer to a double array x- and sets coordinates of coord
  those of *x */
  virtual void SetPos ( double *x )
  {
    for ( int i=0; i<N; ++i )
    {
      coord[i]=x[i];
    }
  }


  /**SetPos is overloaded to set a position coordinates between two Vertex_Base entities
  using is weighted by the Ratio parameter */
  virtual void SetPos ( const Vertex_Base<N> &V1,const Vertex_Base<N> &V2,double Ratio )
  {
    double Rratio=1-Ratio;

    for ( int i=0; i<N; ++i )
    {
      coord[i]=V1.coord[i]*Ratio+V2.coord[i]*Rratio;
    }
  }


/// operator [] overloaded to return coordinate i (const version)
  const double & operator [] ( int i ) const
  {
    return coord[i];
  }

/// operator [] overloaded to return coordinate i (mutable version)
  double& operator [] ( int i )
  {
    return coord[i];
  }

  /**operator - overloaded to return difference between coordinates
  of Other which is passed as a reference to a Vertex_Base entity and the
  coordinates of the instanciated Vertex_Base entity */
  Vertex_Base<N> operator - ( const Vertex_Base & Other ) const
  {
    Vertex_Base<N> Buff;

    for ( int i=0; i<N; ++i )
    {
      Buff.coord[i]=coord[i]-Other.coord[i];
    }

    return Buff;
  }

  /**operator - overloaded to return the sum of the coordinates
  of Other which is passed as a reference to a const Vertex_Base entity and the
  coordinates of the instanciated Vertex_Base entity*/
  Vertex_Base<N> operator + ( const Vertex_Base & Other ) const
  {
    Vertex_Base<N> Buff;

    for ( int i=0; i<N; ++i )
    {
      Buff.coord[i]=coord[i]+Other.coord[i];  ///EB changed"-"to"+" (bug 31072002)
    }

    return Buff;
  }

  /**operator += oveloaded to change Vertex_Base coordinates
  to coord[i]+V.coord[i] with V passed as a reference to a Vertex_Base entity*/
  void operator += ( const Vertex_Base<N> & V )
  {
    for ( int i=0; i<N; ++i )
    {
      coord[i]+=V.coord[i];
    }
  }

  /**operator -= oveloaded to change Vertex_Base coordinates
  to coord[i]-V.coord[i] with V passed as a reference to a Vertex_Base entity*/
  void operator -= ( const Vertex_Base<N> & V )
  {
    for ( int i=0; i<N; ++i )
    {
      coord[i]-=V.coord[i];
    }
  }

  /**operator /= oveloaded to change Vertex_Base coordinates
  to coord[i]/ratio with ratio passed as a double */
  void operator /= ( double ratio )
  {
    for ( int i=0; i<N; ++i )
    {
      coord[i]/=ratio;
    }
  }

  /**operator *= oveloaded to change Vertex_Base coordinates
  to coord[i]*mpy with mpy passed as a double */
  void operator *= ( double mpy )
  {
    for ( int i=0; i<N; ++i )
    {
      coord[i]*=mpy;
    }
  }


  /**boolean operator == oveloaded to check if two Vertex_Base entities
  have the same coordinates (within a given accuracy - See mesh_calc.h)
  returns false if coordinates are not equal within accuracy
  need to check accuracy definition and validity of chosen values*/
  bool operator == ( const Vertex_Base<N>& V ) const
  {
    for ( int i=0; i<N; ++i )
      if ( !IsEqual<double> ( coord[i],V.coord[i] ) )
      {
        return ( false );
      }

    return true;
  }

  /**boolean operator < overloaded to compare coodinates of a Vertex_base
  entity and a V passed as a reference to a Vertex_Base entity
  this operator is used to classify nodes following their coordinates by comparing
  x then y if needed then z (if x same and y same within accuracy)*/
  bool operator < ( const Vertex_Base<N>& V ) const
  {
    for ( int i=0; i<N; ++i )
    {

      if ( !IsEqual<double> ( coord[i],V.coord[i] ) )
      {
        if ( coord[i]<V.coord[i] )
        {
          return true;
        }
        else
        {
          return false;
        }
      }

    }

    return false;
  }

/// displays ID and coordinates of a Vertex_Base entity
  void Display ( void )
  {
    cout << "Ve " << GetID() << " : ";

    for ( int i=0; i<N; ++i )
    {
      cout << coord[i] << " " ;
    }

    cout << endl;
  }
};


///init of the static member "dimension" to the template parameter
//template<int N> const int Vertex_Base<N>::Dimension=N;

#endif // VERTEX_BASE_H

 
