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




#include "mesh_const.h"
#include "simplex.h"
#include "metric_field.h"

#include "simple_mesh.h"
#include "size_function.h"
#include "integrators.h"
#include "discrete_surface_geometry.h"

using namespace std;



class STL_Wrapper : public Simple_Mesh<3,3>
{

public :
  typedef Simple_Mesh<3,3>::Vertex_Type Vertex_Type;
  typedef Simple_Mesh<3,3>::Element_Type Element_Type;
  typedef Simple_Mesh<3,3>::Bipoint_Type Bipoint_Type;
  typedef Simple_Mesh<3,3>::Topological_Face_Type Topological_Face_Type;
  typedef Simple_Mesh<3,3>::Vertex_Iterator Vertex_Iterator;
  typedef Simple_Mesh<3,3>::Element_Iterator Element_Iterator;
  typedef Simple_Mesh<3,3>::Bipoint_Iterator Bipoint_Iterator;
  typedef Simple_Mesh<3,3>::Topological_Face_Iterator Topological_Face_Iterator;
  typedef Discrete_Surface_Geometry::Patch_Type Patch_Type;
  typedef Discrete_Surface_Geometry::Vertex_Type Geometry_Vertex_Type;
  typedef Discrete_Surface_Geometry::Vertex_Iterator Geometry_Vertex_Iterator;


  /// without metric
  STL_Wrapper() :Simple_Mesh<3,3>()
  {
  }

  virtual ~STL_Wrapper()
  {
  }

  /// constructor with a metric
  STL_Wrapper ( Metric_Field<Simple_Mesh<3,3>::Vertex_Type> &M ) :Simple_Mesh<3,3> ( M )
  {
  }

  virtual Geometry_Vertex_Iterator Add_Geometry_Vertex ( Geometry_Vertex_Type &V )
  {
    return Geo.Add_Vertex ( V );
  }

  virtual Patch_Type* Add_Patch ( Patch_Type &E )
  {
    return Geo.Add_Patch ( E );
  }

  virtual void Tessellate ( void )
  {
    Geo.Tessellate ( *this );
  }

  virtual void Accept_Geometry ( void )
  {
    Geo.Create_Topology();
  }

  virtual void Read_STL_File ( char* filename )
  {
    Geo.Read_STL_File ( filename );
  }

private :
  Discrete_Surface_Geometry Geo;

};



class Metric_Callback : public Metric_Field<STL_Wrapper::Vertex_Type>
{
public:
  typedef STL_Wrapper::Vertex_Type Vertex_Type;
  typedef Metric_Tensor Metric_Tensor_Type;

  Metric_Callback() :Metric_Field<Vertex_Type>()
  {
    callback=NULL;
  }
  virtual ~Metric_Callback() {}

  void SetCallBack ( void ( *func ) ( Vertex_Type *t,Metric_Tensor_Type *m ) )
  {
    callback=func;
  }

  virtual void operator () ( Vertex_Type& Ver,Metric_Tensor_Type& MM );
  virtual double Metric_Distance ( Vertex_Type& V1,Vertex_Type& V2 );


private:
  void ( *callback ) ( Vertex_Type *t,Metric_Tensor_Type *m );

};


void Metric_Callback::operator() ( Vertex_Type& Ver,Metric_Tensor_Type& MM )
{
  ( *callback ) ( &Ver,&MM );
}


double Metric_Callback::Metric_Distance ( Metric_Callback::Vertex_Type& V1,Metric_Callback::Vertex_Type& V2 )
{
  Size_Function<Vertex_Type> F ( V1,V2,*this );

  switch ( prec )
  {
    case 0 :
    {
      Super_Simple_Integrator<Size_Function<Vertex_Type> > S ( F );
      return S ( 0.,1. );
      break;
    }

    case 1 :
    {
      Simple_Integrator<Size_Function<Vertex_Type> > S ( F );
      return S ( 0.,1. );
      break;
    }

    default :
    {
      Simpson_Integrator<Size_Function<Vertex_Type> > S ( F );
      return S ( 0.,1.,prec );
      break;
    }
  }
}




class Metric_Callback_F : public Metric_Field<STL_Wrapper::Vertex_Type>
{
public:
  typedef STL_Wrapper::Vertex_Type Vertex_Type;
  typedef Metric_Tensor Metric_Tensor_Type;

  class Metric_Functor
  {
  public :
    virtual void operator() ( Vertex_Type& Ver,Metric_Tensor_Type& MM ) =0;
  };


  Metric_Callback_F ( Metric_Functor & ftor ) :Metric_Field<Vertex_Type>()
  {
    functor=&ftor;
  }
  virtual ~Metric_Callback_F() {}



  virtual void operator () ( Vertex_Type& Ver,Metric_Tensor_Type& MM )
  {
    ( *functor ) ( Ver,MM );
  }

  virtual double Metric_Distance ( Vertex_Type& V1,Vertex_Type& V2 );


private:
  Metric_Functor* functor;

};



double Metric_Callback_F::Metric_Distance ( Metric_Callback_F::Vertex_Type& V1,Metric_Callback_F::Vertex_Type& V2 )
{
  Size_Function<Vertex_Type> F ( V1,V2,*this );

  switch ( prec )
  {
    case 0 :
    {
      Super_Simple_Integrator<Size_Function<Vertex_Type> > S ( F );
      return S ( 0.,1. );
      break;
    }

    case 1 :
    {
      Simple_Integrator<Size_Function<Vertex_Type> > S ( F );
      return S ( 0.,1. );
      break;
    }

    default :
    {
      Simpson_Integrator<Size_Function<Vertex_Type> > S ( F );
      return S ( 0.,1.,prec );
      break;
    }
  }
}






#endif
 
