/**==========================================================
 *
 * \file MeshToVTKWriter.hpp
 * \brief Given an OpenMesh mesh, export it to a vtk file.
 *
 * \author Leblanc Christophe.
 * \date 08/06/2014
 * \email cleblancad@gmail.com
 *
 * DISCLAIMER:
 *
 * THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. 
 * EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 
 * PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, 
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
 * FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE 
 * OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME 
 * THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
 *
 *==========================================================*/
 	
#ifndef INTERSECTION_MESH_TO_VTK_WRITER_HPP
#define INTERSECTION_MESH_TO_VTK_WRITER_HPP
 	
#include <string>
#include <fstream>
#include <vector>
#include "openMesh/openMesh.hh"
 	
namespace intersection {
  	
/** \class MeshToVTKWriter.
  * \brief Given an OpenMesh mesh, export it to a vtk file.
  */
template<class MeshTypeT>
class MeshToVTKWriter
{
public:
  typedef MeshTypeT MeshType; //!< Type of mesh.
 	
  /// \brief Default constructor.
  MeshToVTKWriter(): m_Mesh(NULL) {}
 	
  /// \brief Constructor.
  /// \param[in] mesh mesh to write to file.
  MeshToVTKWriter(const MeshType &mesh): m_Mesh(&mesh) {}
  	
  /// \brief Destructor.
  ~MeshToVTKWriter() {}
 	
  /// \brief Copy constructor.
  /// \param[in] rhs object to copy.
  MeshToVTKWriter(const MeshToVTKWriter &rhs): m_Mesh(rhs.m_Mesh) {}
  	
  /// \brief Copy operator.
  /// \param[in] rhs object to copy.
  MeshToVTKWriter& operator=(const MeshToVTKWriter &rhs)
  {
    if(this != &rhs) {
      m_Mesh = rhs.m_Mesh;
    }
  	
    return rhs;
  }
 	
  /// \brief Write a mesh to a file in ASCII VTK format.
  /// \param[in] filename file name to write the mesh to.
  void Write(const std::string &filename) const;
 	
  /// \brief Write a mesh to an output stream in ASCII VTK format.
  /// \param[in] filename file name to write the mesh to.
  void Write(std::ofstream &s) const;
  	
  /// \brief Get current mesh.
  /// \return Current mesh.
  const MeshType* GetMesh() const
  { return m_Mesh; }
 	
  /// \brief Set current mesh.
  /// \param[in] mesh mesh to set.
  void SetMesh(const MeshType &mesh)
  { m_Mesh = &mesh; }
 	
private:
  const MeshType *m_Mesh; //!< Mesh.
 	
  /// \brief Write the header of a VTK file.
  /// \param[in] file open file stream, which is modified in return.
  void WriteHeader(std::ofstream &file) const;
 	
  /// \brief Write the points of the mesh.
  /// \param[in] file open file stream, which is modified in return.
  void WritePoints(std::ofstream &file) const;
 	
  /// \brief Write the vertices' connectivity of the mesh.
  /// \param[in] file open file stream, which is modified in return.
  void WriteConnectivity(std::ofstream &file) const;
};
 	
//
// Public functions.
//
  	
template<class MeshTypeT>
void MeshToVTKWriter<MeshTypeT>::Write(const std::string &filename) const
{
  // Open file.
  std::ofstream file;
  file.open(filename.c_str(), std::ofstream::out);
 	
  if(!file.is_open())
    throw std::runtime_error("MeshToVTKWriter: failed to create file.");
  	
  // Write file.
  Write(file);
 	
  // Close file.
  file.close();
}
  	
template<class MeshTypeT>
void MeshToVTKWriter<MeshTypeT>::Write(std::ofstream &file) const
{
  if(m_Mesh != NULL) {
    // Write header.
    WriteHeader(file);
  	
    // Write points.
    WritePoints(file);
 	
    // Write vertices' connectivity.
    WriteConnectivity(file);
  }
}
 	
//
// Private functions.
//
 	
template<class MeshTypeT>
void MeshToVTKWriter<MeshTypeT>::WriteHeader(std::ofstream &file) const
{
  file << "# vtk DataFile Version 2.0\n"
       << "OpenMesh mesh\n"
       << "ASCII\n"
       << "DATASET POLYDATA\n";
}
 	
template<class MeshTypeT>
void MeshToVTKWriter<MeshTypeT>::WritePoints(std::ofstream &file) const
{
  typename MeshType::ConstVertexIter v_it  = m_Mesh->vertices_begin();
  typename MeshType::ConstVertexIter v_ite = m_Mesh->vertices_end();
 	
  file << "POINTS " << (m_Mesh->n_vertices()) << " float\n";
 	
  for(; v_it != v_ite; ++v_it) {
    const typename MeshType::Point p = m_Mesh->point(v_it.handle());
    file << p[0] << " " << p[1] << " " << p[2] << "\n";
  }
}
  	
template<class MeshTypeT>
void MeshToVTKWriter<MeshTypeT>::WriteConnectivity(std::ofstream &file) const
{
  // For each face, count the number of vertices and sum it.
  size_t i(0), count(0);
  std::vector<size_t> vCount(m_Mesh->n_faces());
  typename MeshType::ConstFaceIter f_it  = m_Mesh->faces_begin();
  typename MeshType::ConstFaceIter f_ite = m_Mesh->faces_end();
  	
  for(; f_it != f_ite; ++f_it, i++) {
    typename MeshType::ConstFaceVertexIter fv_it = m_Mesh->cfv_iter(f_it.handle());
    vCount[i] = 0;    
 	
    for(; fv_it; ++fv_it) {
      vCount[i]++;
      count++;
    }
  }
  	
  // Write data to output stream.
  file << "POLYGONS " << (m_Mesh->n_faces()) << " " << (count + (m_Mesh->n_faces())) << "\n";
 	
  i = 0;
  f_it = m_Mesh->faces_begin();
  for(; f_it != f_ite; ++f_it, i++) {
    file << vCount[i] << " ";
 	
    typename MeshType::ConstFaceVertexIter fv_it = m_Mesh->cfv_iter(f_it.handle());
    for(; fv_it; ++fv_it) {
      file << (fv_it.handle().idx()) << " ";
    }
 	
    file << "\n";
  }
}
  	
} // namespace intersection
 	
#endif // INTERSECTION_MESH_TO_VTK_WRITER_HPP
