// Copyright (c) 2003-2007  INRIA Sophia-Antipolis (France).
// Copyright (c) 2008       GeometryFactory (France)
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org); you may redistribute it under
// the terms of the Q Public License version 1.0.
// See the file LICENSE.QPL distributed with CGAL.
//
// Licensees holding a valid commercial license may use this file in
// accordance with the commercial license agreement provided with the software.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// $URL: svn+ssh://scm.gforge.inria.fr/svn/cgal/branches/CGAL-3.5-branch/Surface_mesher/include/CGAL/IO/Complex_2_in_triangulation_3_polyhedron_builder.h $
// $Id: Complex_2_in_triangulation_3_polyhedron_builder.h 48774 2009-04-14 15:24:57Z lsaboret $
//
//
// Author(s)     : Laurent Rineau

#ifndef CGAL_IO_COMPLEX_2_IN_TRIANGULATION_3_POLYHEDRON_BUILDER_H
#define CGAL_IO_COMPLEX_2_IN_TRIANGULATION_3_POLYHEDRON_BUILDER_H

#include <CGAL/Modifier_base.h>
#include <CGAL/Polyhedron_incremental_builder_3.h>

namespace CGAL {

template <class C2T3, class Polyhedron_>
class Complex_2_in_triangulation_3_polyhedron_builder
  : public CGAL::Modifier_base<typename Polyhedron_::HalfedgeDS>
{
public:
  typedef C2T3 C2t3;
  typedef Polyhedron_ Polyhedron;
  typedef typename Polyhedron::HalfedgeDS HDS;

private:
  typedef typename C2T3::Triangulation Tr;

  const C2t3& c2t3;
  typedef CGAL::Modifier_base<typename Polyhedron::HalfedgeDS> Base;

public:
  Complex_2_in_triangulation_3_polyhedron_builder(const C2t3& c2t3)
    : Base(), c2t3(c2t3)
  {
  }

  void operator()(HDS& hds) {
    typedef typename Tr::Vertex_handle Vertex_handle;
    typedef typename Tr::Point Point;
    typedef typename Tr::Edge Edge;
    typedef typename Tr::Facet Facet;
    typedef typename Tr::Finite_vertices_iterator Finite_vertices_iterator;
    typedef typename Tr::Finite_facets_iterator Finite_facets_iterator;

    const Tr& tr = c2t3.triangulation();
    CGAL::Polyhedron_incremental_builder_3<HDS> builder(hds, true);
    const typename Tr::size_type number_of_facets = c2t3.number_of_facets();
    builder.begin_surface(tr.number_of_vertices(),
			  number_of_facets);
    {
      // Finite vertices coordinates.
      std::map<Vertex_handle, int> V;
      int inum = 0;
      for(Finite_vertices_iterator vit = tr.finite_vertices_begin();
	  vit != tr.finite_vertices_end();
	  ++vit)
      {
	V[vit] = inum++;
	Point p = static_cast<Point>(vit->point());
	builder.add_vertex(p);
      }
      Finite_facets_iterator fit = tr.finite_facets_begin();
      std::set<Facet> oriented_set;
      std::stack<Facet> stack;

      CGAL_assertion_code(typename Tr::size_type nb_facets = 0; )

	while (oriented_set.size() != number_of_facets) {
	  while ( fit->first->is_facet_on_surface(fit->second) == false ||
		  oriented_set.find(*fit) != oriented_set.end() ||

		  oriented_set.find(c2t3.opposite_facet(*fit)) !=
		  oriented_set.end() ) {
	    ++fit;
	  }
	  oriented_set.insert(*fit);
	  stack.push(*fit);
	  while(! stack.empty() ) {
	    Facet f = stack.top();
	    stack.pop();
	    for(int ih = 0 ; ih < 3 ; ++ih) {
	      const int i1  = tr.vertex_triple_index(f.second, tr. cw(ih));
	      const int i2  = tr.vertex_triple_index(f.second, tr.ccw(ih));
	      if( c2t3.face_status(Edge(f.first, i1, i2)) == C2t3::REGULAR ) {
		Facet fn = c2t3.neighbor(f, ih);
		if (oriented_set.find(fn) == oriented_set.end() &&
		    oriented_set.find(c2t3.opposite_facet(fn)) == oriented_set.end())
		{
		  oriented_set.insert(fn);
		  stack.push(fn);
		}
	      } // end "if the edge is regular"
	    } // end "for each neighbor of f"
	  } // end "stack non empty"
	} // end "oriented_set not full"

      for(typename std::set<Facet>::const_iterator fit =
	    oriented_set.begin();
	  fit != oriented_set.end();
	  ++fit)
      {
	int indices[3];
	int index = 0;
	for (int i=0; i<3; i++)
	  indices[index++] =
	    V[fit->first->vertex(tr.vertex_triple_index(fit->second, i))];
	builder.add_facet(indices+0, indices+3);
	CGAL_assertion_code(++nb_facets);
      }
      CGAL_assertion(nb_facets == number_of_facets);
      // 	for( Finite_facets_iterator fit = tr.finite_facets_begin();
      // 	     fit != tr.finite_facets_end(); ++fit)
      // 	  if ((*fit).first->is_facet_on_surface((*fit).second)==true)
      // 	  {
      // 	    int indices[3];
      // 	    int index = 0;
      // 	    for (int i=0; i<3; i++)
      // 	      std::cerr << ( indices[index++] = V[(*fit).first->vertex(tr.vertex_triple_index(fit->second, i))] ) << ", ";
      // 	    std::cerr << "\n";
      // 	    if( builder.test_facet(indices+0, indices+3) )
      // 	      builder.add_facet(indices+0, indices+3);
      // 	    else
      // 	    {
      // 	      builder.begin_facet();
      // 	      builder.add_vertex_to_facet(indices[2]);
      // 	      builder.add_vertex_to_facet(indices[1]);
      // 	      builder.add_vertex_to_facet(indices[0]);
      // 	      builder.end_facet();
      // 	    }
      // 	    CGAL_assertion_code(++nb_facets);
      // 	  }
    }
    builder.end_surface();
  } // end operator()
}; // end Complex_2_in_triangulation_3_polyhedron_builder

} // end namespace CGAL

#endif  // CGAL_IO_COMPLEX_2_IN_TRIANGULATION_3_POLYHEDRON_BUILDER_H

