/*
 * Copyright (c) 2010-2015:  G-CSC, Goethe University Frankfurt
 * Author: Andreas Vogel
 * 
 * This file is part of UG4.
 * 
 * UG4 is free software: you can redistribute it and/or modify it under the
 * terms of the GNU Lesser General Public License version 3 (as published by the
 * Free Software Foundation) with the following additional attribution
 * requirements (according to LGPL/GPL v3 §7):
 * 
 * (1) The following notice must be displayed in the Appropriate Legal Notices
 * of covered and combined works: "Based on UG4 (www.ug4.org/license)".
 * 
 * (2) The following notice must be displayed at a prominent place in the
 * terminal output of covered works: "Based on UG4 (www.ug4.org/license)".
 * 
 * (3) The following bibliography is recommended for citation and must be
 * preserved in all covered files:
 * "Reiter, S., Vogel, A., Heppner, I., Rupp, M., and Wittum, G. A massively
 *   parallel geometric multigrid solver on hierarchically distributed grids.
 *   Computing and visualization in science 16, 4 (2013), 151-164"
 * "Vogel, A., Reiter, S., Rupp, M., Nägel, A., and Wittum, G. UG4 -- a novel
 *   flexible software system for simulating pde based models on high performance
 *   computers. Computing and visualization in science 16, 4 (2013), 165-179"
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 */

#ifndef __H__UG__LIB_DISC__IO__VTKOUTPUT__
#define __H__UG__LIB_DISC__IO__VTKOUTPUT__

//TODO: deduplicate code in VTUOutput - reduces vulnerability to errors and linker time 

// extern libraries
#include <string>
#include <vector>
#include <map>

// other ug modules
#include "common/util/string_util.h"
#include "common/util/base64_file_writer.h"
#include "lib_disc/common/function_group.h"
#include "lib_disc/domain.h"
#include "lib_disc/spatial_disc/user_data/user_data.h"

namespace ug{
// todo this should avoid refactoring all the signatures of VTKOutput, remove it later
typedef Base64FileWriter VTKFileWriter;

template <typename T>
struct IteratorProvider
{
	template <typename TElem>
	struct traits
	{
		typedef typename T::template traits<TElem>::iterator iterator;
		typedef typename T::template traits<TElem>::const_iterator const_iterator;
	};

	template <typename TElem>
	static typename traits<TElem>::const_iterator begin(const T& provider, int si)
	{
		if(si < 0) return provider.template begin<TElem>();
		else return provider.template begin<TElem>(si);
	}

	template <typename TElem>
	static typename traits<TElem>::const_iterator end(const T& provider, int si)
	{
		if(si < 0) return provider.template end<TElem>();
		else return provider.template end<TElem>(si);
	}
};

template <>
struct IteratorProvider<MGSubsetHandler>
{
	private:
	typedef MGSubsetHandler T;

	public:
	template <typename TElem>
	struct traits
	{
		typedef typename T::template traits<TElem>::iterator iterator;
		typedef typename T::template traits<TElem>::const_iterator const_iterator;
	};

	template <typename TElem>
	static typename traits<TElem>::const_iterator begin(const T& provider, int si)
	{
		const int lev = provider.num_levels() - 1;
		if(si < 0) return provider.multi_grid()->template begin<TElem>(lev);
		else return provider.template begin<TElem>(si, lev);
	}

	template <typename TElem>
	static typename traits<TElem>::const_iterator end(const T& provider, int si)
	{
		const int lev = provider.num_levels() - 1;
		if(si < 0) return provider.multi_grid()->template end<TElem>(lev);
		else return provider.template end<TElem>(si, lev);
	}
};


/// output writer to the VTK file format
/**
 * This class can be used to write grid and data associated with the grid to
 * the vtk file format.
 *
 * The produced files are:
 *
 * 1)) TIME DEPENDENT
 * 1a) In case of functions that are only defined for some subsets
 * - filename_pXXXX_sXXXX_tXXXX.vtu  (piece of grid for proc, subset, timestep)
 * - filename_sXXXX_tXXXX.pvtu 	     (piece of grid for subset, timestep)
 * - filename_tXXXX.pvd              (piece of grid for timestep)
 * - filename.pvd                    (group of timeseries)
 *
 * 1b) In case that all functions are defined globally
 * - filename_p0000_t0000.vtu		(piece of grid for proc, timestep)
 * - filename_t0000.pvtu			(piece of grid for timestep)
 *
 * 2)) TIME INDEPENDENT
 * 2a) In case of functions that are only defined for some subsets
 * - filename_pXXXX_sXXXX.vtu  (piece of grid for proc, subset)
 * - filename_sXXXX.pvtu 	   (piece of grid for subset)
 * - filename.pvd              (group of subsets)
 *
 * 2b) In case that all functions are defined globally
 * - filename_p0000.vtu		(piece of grid for proc)
 * - filename.pvtu			(group of procs)
 *
 * In case that the simulation is run in serial (or in parallel environment but
 * with only one process), the *.pvtu are not written and the *.vtu file
 * contains all information.
 *
 * ATTENTION: This class uses heavily the mark-function of the grid.
 * 			  Do not use any member function while having called begin_mark()
 *
 * \tparam		dim 	world dimension
 */
template <int TDim>
class VTKOutput
{
		public:
	///	clears the selected output
		void clear_selection() {m_vSymbFct.clear(); m_vSymbFctNodal.clear(); m_vSymbFctElem.clear();}

	///	clears the selected output
		void clear_data_selection()
		{
			m_vScalarNodalData.clear();
			m_vScalarElemData.clear();

			m_vVectorNodalData.clear();
			m_vVectorElemData.clear();
		}

	///	schedules that all components of the passed discrete functions will be written to file
		void select_all(bool bAll) {m_bSelectAll = bAll;}

	///	selects a value of a grid function value to be written
	/**
	 * This function schedules the component(s) passed by symbolic name(s) of an
	 * approximation space to be written to the vtk file under a specified name.
	 * The type of the data (nodal/element) will be determined based on the
	 * trial space of the components (i.e if continuous available or not)
	 *
	 * If more than one component is passed, the data will be interpreted as a
	 *  vector and #dim arguments must be passed.
	 *
	 * example: fctName = "p"; name = "pressure"
	 * example: fctNames = "u,v,w"; name = "velocity"
	 *
	 * \param[in]	fctName		symbolic name of component
	 * \param[in]	name		name that will appear in the vtk file for the data
	 */
	/// \{
		void select(const char* fctName, const char* name);
		void select(const std::vector<std::string>& vFct, const char* name);
	/// \}

	///	selects a nodal value of a grid function value to be written
	/**
	 * This function schedules the component(s) passed by symbolic name(s) of an
	 * approximation space to be
	 * written to the vtk file under a specified name. Note, that for the
	 * trial space of the component an evaluation of the data at the nodes
	 * must be available (continuous). If more than one component is passed, the
	 * data will be interpreted as a vector and #dim arguments must be passed.
	 *
	 * example: fctName = "p"; name = "pressure"
	 * example: fctNames = "u,v,w"; name = "velocity"
	 *
	 * \param[in]	fctName		symbolic name of component
	 * \param[in]	name		name that will appear in the vtk file for the data
	 */
	/// \{
		void select_nodal(const char* fctName, const char* name);
		void select_nodal(const std::vector<std::string>& vFct, const char* name);
	/// \}

	///	selects a element value of a grid function value to be written
	/**
	 * This function schedules the component(s) passed by symbolic name(s) of an
	 * approximation space to be written to the vtk file under a specified name.
	 * If more than one component is passed, the
	 * data will be interpreted as a vector and #dim arguments must be passed.
	 *
	 * example: fctName = "p"; name = "pressure"
	 * example: fctNames = "u,v,w"; name = "velocity"
	 *
	 * \param[in]	fctName		symbolic name of component
	 * \param[in]	name		name that will appear in the vtk file for the data
	 */
	/// \{
		void select_element(const char* fctName, const char* name);
		void select_element(const std::vector<std::string>& vFct, const char* name);
	/// \}

	///	selects a data value to be written
	/**
	 * This function schedules a user data to be written to the vtk file under
	 * a specified name.
	 * The type of the data (nodal/element) will be determined based on the
	 * trial space of the components (i.e if continuous available or not)
	 *
	 * \param[in]	spData		data to be written
	 * \param[in]	name		name that will appear in the vtk file for the data
	 */
	/// \{
		void select(SmartPtr<UserData<number, TDim> > spData, const char* name);
		void select(SmartPtr<UserData<MathVector<TDim>, TDim> > spData, const char* name);
		void select(SmartPtr<UserData<MathMatrix<TDim,TDim>, TDim> > spData, const char* name);
	/// \}

	///	selects a nodal data value to be written
	/**
	 * This function schedules a user data to be written to the vtk file under
	 * a specified name. Note, that for the the data at the nodes must be
	 * available (continuous).
	 *
	 * \param[in]	spData		data to be written
	 * \param[in]	name		name that will appear in the vtk file for the data
	 */
	/// \{
		void select_nodal(SmartPtr<UserData<number, TDim> > spData, const char* name);
		void select_nodal(SmartPtr<UserData<MathVector<TDim>, TDim> > spData, const char* name);
		void select_nodal(SmartPtr<UserData<MathMatrix<TDim,TDim>, TDim> > spData, const char* name);
	/// \}

	///	selects a element data value to be written
	/**
	 * This function schedules a user data to be written to the vtk file under
	 * a specified name.
	 *
	 * \param[in]	spData		data to be written
	 * \param[in]	name		name that will appear in the vtk file for the data
	 */
	/// \{
		void select_element(SmartPtr<UserData<number, TDim> > spData, const char* name);
		void select_element(SmartPtr<UserData<MathVector<TDim>, TDim> > spData, const char* name);
		void select_element(SmartPtr<UserData<MathMatrix<TDim,TDim>, TDim> > spData, const char* name);
	/// \}

	/**
	 * This function writes the grid to a *.vtu file. It calls the function
	 * print_subset for each subset if necessary and produces a grouping
	 * *.pvd file for paraview. If all subsets have to be written, then only
	 * a single file is produced containing the whole grid.
	 *
	 * \param[in]	filename		filename for produced files
	 * \param[in]	u				grid function
	 * \param[in]	step 			time step counter (-1 indicates stationary case)
	 * \param[in]	time			time point corresponding to timestep
	 * \param[in]	makeConsistent	flag if data shall be made consistent before printing
	 */
		template <typename TFunction>
		void print(const char*  filename, TFunction& u,
		           int step, number time,
				   bool makeConsistent);

	/**	Calls print with makeConsistent enabled.*/
		template <typename TFunction>
		void print(const char*  filename, TFunction& u,
		           int step, number time)
		{
			return print(filename, u, step, time, true);
		}

	/**
	 * This function simply calls 'print' using step = -1 to indicate the
	 * stationary case. It is intended to write time independent data.
	 *
	 * \param[in]	filename		filename for produced files
	 * \param[in]	u				grid function
	 * \param[in]	makeConsistent	flag if data shall be made consistent before printing
	 */
		template <typename TFunction>
		void print(const char*  filename, TFunction& u,
				   bool makeConsistent)
		{
			print(filename, u, -1, 0.0, makeConsistent);
		}

	/**	Calls print with makeConsistent enabled.*/
		template <typename TFunction>
		void print(const char*  filename, TFunction& u)
		{
			return print(filename, u, true);
		}

	///	prints the domain to file
		void print(const char* filename, Domain<TDim>& domain);

	/**
	 * This function writes the subset si of the grid (or the whole grid if
	 * si < 0) to the file "filename.vtu".
	 *
	 * If step >= 0 is passed, this indicates that a time step is written and
	 * to the filename a "*_pXXXX*.vtu" is added, indicating the timestep.
	 *
	 * If the computation is done in parallel and the number of Processes is
	 * greater than one, a "*_pXXXX*.vtu" is added, indicating the process. Then,
	 * in addition a "filename*.pvtu" file is written, grouping all *vtu files
	 * from different processes.
	 *
	 * If only a part of the grid, i.e. a subset, is written, the to the filename
	 * a "*_sXXXX*.vtu" is added, to indicate the subset.
	 *
	 * \param[in, out]	filename 		base name for output file(s)
	 * \param[in]		u				grid function
	 * \param[in]		si				Subset (si < 0 indicates whole grid)
	 * \param[in]		step			counter for timestep (-1 means stationary)
	 * \param[in]		time			time point of timestep
	 * \param[in]	makeConsistent	flag if data shall be made consistent before printing
	 */
		template <typename TFunction>
		void print_subset(const char* filename, TFunction& u,
		                  int si, int step, number time,
						  bool makeConsistent);

	/**	Calls print_subset with makeConsistent enabled.*/
		template <typename TFunction>
		void print_subset(const char* filename, TFunction& u,
		                  int si, int step = -1, number time = 0.0)
		{
			return print_subset(filename, u, si, step, time, true);
		}

	/**
	 * This function writes the given subsets ssGrp of the grid "filename.vtu".
	 *
	 * If step >= 0 is passed, this indicates that a time step is written and
	 * to the filename a "*_pXXXX*.vtu" is added, indicating the timestep.
	 *
	 * If the computation is done in parallel and the number of Processes is
	 * greater than one, a "*_pXXXX*.vtu" is added, indicating the process. Then,
	 * in addition a "filename*.pvtu" file is written, grouping all *vtu files
	 * from different processes.
	 *
	 * \param[in, out]	filename 		base name for output file(s)
	 * \param[in]		u				grid function
	 * \param[in]		ssGrp			subset group
	 * \param[in]		step			counter for timestep (-1 means stationary)
	 * \param[in]		time			time point of timestep
	 * \param[in]	makeConsistent	flag if data shall be made consistent before printing
	 */
		template <typename TFunction>
		void print_subsets(const char* filename, TFunction& u,
		                  const SubsetGroup& ssGrp, int step = -1, number time = 0.0,
						  bool makeConsistent = true);

	/**
	 * This function writes the given subsets ssGrp of the grid "filename.vtu".
	 *
	 * If step >= 0 is passed, this indicates that a time step is written and
	 * to the filename a "*_pXXXX*.vtu" is added, indicating the timestep.
	 *
	 * If the computation is done in parallel and the number of Processes is
	 * greater than one, a "*_pXXXX*.vtu" is added, indicating the process. Then,
	 * in addition a "filename*.pvtu" file is written, grouping all *vtu files
	 * from different processes.
	 *
	 * \param[in, out]	filename 		base name for output file(s)
	 * \param[in]		u				grid function
	 * \param[in]		ssNames			subset names
	 * \param[in]		step			counter for timestep (-1 means stationary)
	 * \param[in]		time			time point of timestep
	 * \param[in]	makeConsistent	flag if data shall be made consistent before printing
	 */
		template <typename TFunction>
		void print_subsets(const char* filename, TFunction& u,
		                  const char* ssNames, int step = -1, number time = 0.0,
						  bool makeConsistent = true);

	/**	Calls print_subsets with makeConsistent enabled.*/
		template <typename TFunction>
		void print_subsets(const char*  filename, TFunction& u, const char* ssNames,
		           int step, number time)
		{
			return print_subsets(filename, u, ssNames, step, time, true);
		}

	/**
	 * This function simply calls 'print_subsets' using step = -1 to indicate the
	 * stationary case. It is intended to write time independent data.
	 *
	 * \param[in]	filename		filename for produced files
	 * \param[in]	u				grid function
	 * \param[in]	ssNames			subset names
	 * \param[in]	makeConsistent	flag if data shall be made consistent before printing
	 */
		template <typename TFunction>
		void print_subsets(const char*  filename, TFunction& u, const char* ssNames,
				   bool makeConsistent)
		{
			print_subsets(filename, u, ssNames, -1, 0.0, makeConsistent);
		}

	/**	Calls print_subsets with makeConsistent enabled.*/
		template <typename TFunction>
		void print_subsets(const char*  filename, TFunction& u, const char* ssNames)
		{
			return print_subsets(filename, u, ssNames, true);
		}

	/**
	 * When a time series has been computed, this function can be used to procduce
	 * a grouping *.pvd file for paraview visualization.
	 *
	 * \param[in]		filename		filename used in time series
	 * \param[in]		u				grid function
	 */
		template <typename TFunction>
		void write_time_pvd(const char* filename, TFunction& u);

	/**
	 * When a time series has been computed, this function can be used to procduce
	 * a grouping *_processwise.pvd file for paraview visualization.
	 *
	 * \param[in]		filename		filename used in time series
	 * \param[in]		u				grid function
	 */
		template <typename TFunction>
		void write_time_processwise_pvd(const char* filename, TFunction& u);

	/**
	 * When a time series has been computed, this function can be used to procduce
	 * a grouping *.pvd file for paraview visualization.
	 *
	 * \param[in]		filename		filename used in time series
	 * \param[in]		u				grid function
	 * \param[in]		si				subset index
	 */
		template <typename TFunction>
		void write_time_pvd_subset(const char* filename, TFunction& u, int si);
protected:
	/**
	 * This function counts the number of vertices, elements and connections for
	 * given subsets.
	 *
	 * \param[in]		u			discrete function
	 * \param[in]		ssGrp		subset group of the piece
	 * \param[in]		dim			dimension of subset
	 * \param[out]		numVert		number of vertices
	 * \param[out]		numElem		number of elements
	 * \param[out]		numConn		number of connections
	 */
		template <typename T>
		void
		count_piece_sizes(Grid& grid, const T& iterContainer, const SubsetGroup& ssGrp, const int dim,
		                  int& numVert, int& numElem, int& numConn);

	/**
	 * This function counts the number of vertices, elements and connections that
	 * are in a subset of the grid (or whole grid, if and only if si < 0).
	 *
	 * NOTE: that the number of vertices that are needed to describe the subset
	 * may be more than the vertices of the subset. This happens, when elements are
	 * part of the subset, but the vertices of these elements are part of another
	 * subset. This function counts also those vertices, i.e. it counts the closure
	 * of all vertices needed to describe the subset.
	 *
	 * \param[in]		u			discrete function
	 * \param[in]		si			subset index (si < 0 indicates whole grid)
	 * \param[out]		numVert		number of vertices needed to compose subset
	 * \param[out]		numElem		number of elements in the subset
	 * \param[out]		numConn		number of connections
	 */
		template <typename TElem, typename T>
		void
		count_sizes(Grid& grid, const T& iterContainer, const int si,
		            int& numVert, int& numElem, int& numConn);

		template <typename T>
		void
		write_points_cells_piece(VTKFileWriter& File,
		                         Grid::VertexAttachmentAccessor<Attachment<int> >& aaVrtIndex,
		                         const Grid::VertexAttachmentAccessor<Attachment<MathVector<TDim> > >& aaPos,
		                         Grid& grid, const T& iterContainer, const SubsetGroup& ssGrp,
		                         const int dim, const int numVert, const int numElem, const int numConn);

		template <typename T>
		void
		write_grid_piece(VTKFileWriter& File,
		                 Grid::VertexAttachmentAccessor<Attachment<int> >& aaVrtIndex,
		                 const Grid::VertexAttachmentAccessor<Attachment<MathVector<TDim> > >& aaPos,
		                 Grid& grid, const T& iterContainer, SubsetGroup& ssGrp, int dim);

public:
		// maybe somebody wants to do this from outside
		static void write_empty_grid_piece(VTKFileWriter& File,
				bool binary = true);

		void set_user_defined_comment(const char* comment) {m_sComment = comment;};

protected:

		// writes an xml comment to a vtu file
		void write_comment(VTKFileWriter& File);

		// writes an xml comment to a pvd file
		void write_comment_printf(FILE* File);

	/**
	 * This function writes the vertices of a piece (the specified subsets) of
	 * the grid to a vtk file.
	 *
	 * \param[in,out]	File		file to write the points
	 * \param[in]		u			discrete function
	 * \param[in]		ssGrp		specified subsets
	 * \param[in]		dim			dimension of subsets
	 * \param[in]		numVert		number of vertices
	 */
		template <typename T>
		void
		write_points(VTKFileWriter& File,
		             Grid::VertexAttachmentAccessor<Attachment<int> >& aaVrtIndex,
		             const Grid::VertexAttachmentAccessor<Attachment<MathVector<TDim> > >& aaPos,
		             Grid& grid, const T& iterContainer, const SubsetGroup& ssGrp, const int dim,
		             const int numVert);

	/**
	 * This method loops all elements of a subset and writes the vertex
	 * coordinates to a file. All vertices of the element are written reguardless
	 * if the vertex itself is contained in the subset or another. Written
	 * vertices are marked and not written again.
	 *
	 * \param[in]	File		file stream
	 * \param[in]	u			grid function
	 * \param[in]	si			subset index
	 * \param[in]	n			counter for vertices
	 */
		template <typename TElem, typename T>
		void
		write_points_elementwise(VTKFileWriter& File,
		                         Grid::VertexAttachmentAccessor<Attachment<int> >& aaVrtIndex,
		                         const Grid::VertexAttachmentAccessor<Attachment<MathVector<TDim> > >& aaPos,
		                         Grid& grid, const T& iterContainer, const int si, int& n);

	/**
	 * This function writes the elements that are part of the specified subsets.
	 *
	 * \param[in,out]	File		file to write the points
	 * \param[in]		u			discrete function
	 * \param[in]		ssGrp		specified subsets
	 * \param[in]		dim			dimension of subsets
	 * \param[out]		numElem		number of elements
	 * \param[out]		numConn		number of connections
	 */
		template <typename T>
		void
		write_cells(VTKFileWriter& File,
		            Grid::VertexAttachmentAccessor<Attachment<int> >& aaVrtIndex,
		            Grid& grid, const T& iterContainer, const SubsetGroup& ssGrp,
		            const int dim, const int numElem, const int numConn);


	/**
	 * This method writes the 'connectivity' for each element of a subset. The
	 * connectivity are the indices of all vertex the element is formed of.
	 *
	 * \param[in]	File		file stream
	 * \param[in]	u			grid function
	 * \param[in]	si			subset index
	 */
		template <typename TElem, typename T>
		void
		write_cell_connectivity(VTKFileWriter& File,
		                        Grid::VertexAttachmentAccessor<Attachment<int> >& aaVrtIndex,
		                        Grid& grid, const T& iterContainer, const int si);

		template <typename T>
		void
		write_cell_connectivity(VTKFileWriter& File,
		                        Grid::VertexAttachmentAccessor<Attachment<int> >& aaVrtIndex,
		                        Grid& grid, const T& iterContainer, const SubsetGroup& ssGrp,
		                        const int dim, const int numConn);

	/**
	 * This method writes the 'offset' for each element of a subset.
	 *
	 * \param[in]	File		file stream
	 * \param[in]	u			grid function
	 * \param[in]	si			subset index
	 * \param[in]	n			counter for vertices
	 */
		template <typename TElem, typename T>
		void
		write_cell_offsets(VTKFileWriter& File, const T& iterContainer, const int si, int& n);

		template <typename T>
		void
		write_cell_offsets(VTKFileWriter& File, const T& iterContainer, const SubsetGroup& ssGrp,
		                   const int dim, const int numElem);

	/**
	 * This method writes the 'type' for each element of a subset. The type is
	 * a vtk-format specified number for a given element type.
	 *
	 * \param[in]	File		file stream
	 * \param[in]	u			grid function
	 * \param[in]	si			subset index
	 */
		template <typename TElem, typename T>
		void
		write_cell_types(VTKFileWriter& File, const T& iterContainer, const int si);

		template <typename T>
		void
		write_cell_types(VTKFileWriter& File, const T& iterContainer, const SubsetGroup& ssGrp,
		                 const int dim, const int numElem);

	/**
	 * This method writes the 'region' for each element of a subset. The region is
	 * the ug4 subset index for a given element.
	 *
	 * \param[in]	File		file stream
	 * \param[in]	u			grid function
	 * \param[in]	si			subset index
	 * \param[in]	sh			multigrid subset handler
	 */
		template <typename TElem, typename T>
		void
		write_cell_subsets(VTKFileWriter& File, const T& iterContainer, const int si, MGSubsetHandler& sh);

		template <typename T>
		void
		write_cell_subsets(VTKFileWriter& File, const T& iterContainer, const SubsetGroup& ssGrp,
		                 const int dim, const int numElem, MGSubsetHandler& sh);

	/**
	 * This method writes the subset names.
	 *
	 * \param[in]	File		file stream
	 * \param[in]	sh			multigrid subset handler
	 */
		void
		write_cell_subset_names(VTKFileWriter& File, MGSubsetHandler& sh);

	/**
	 * This method writes the proc ranks for each cell.
	 *
	 * \param[in]	File		file stream
	 * \param[in]	u			grid function
	 * \param[in]	si			subset index
	 * \param[in]	sh			multigrid subset handler
	 */
		template <typename TElem, typename T>
		void
		write_cell_proc_ranks(VTKFileWriter& File, const T& iterContainer, const int si, MGSubsetHandler& sh);

		template <typename T>
		void
		write_cell_proc_ranks(VTKFileWriter& File, const T& iterContainer, const SubsetGroup& ssGrp,
		                 const int dim, const int numElem, MGSubsetHandler& sh);

	protected:
	/**
	 * This function writes a piece of the grid to the vtk file. First the
	 * geometric data is written (points, cells, connectivity). Then the data
	 * associated to the points or cells is written.
	 *
	 * \param[in,out]	File		file to write the points
	 * \param[in]		u			discrete function
	 * \param[in]		ssGrp		subsets
	 * \param[in]		dim			dimension of subset
	 */
		template <typename TFunction>
		void
		write_grid_solution_piece(VTKFileWriter& File,
								  Grid::VertexAttachmentAccessor<Attachment<int> >& aaVrtIndex,
								  Grid& grid, TFunction& u, number time,
								  const SubsetGroup& ssGrp, const int dim);

	///////////////////////////////////////////////////////////////////////////
	// nodal data

	/**
	 * This method writes the nodal values of a function to file. If the function
	 * group consists of more than on component, than a vector of components is
	 * expected. For each function, access to the (unique) nodal value is
	 * required.
	 *
	 * \param[in]	File		file stream
	 * \param[in]	u			grid function
	 * \param[in]	vFct		components to be written
	 * \param[in]	grid		Grid
	 * \param[in]	si			subset index
	 */
		template <typename TElem, typename TFunction>
		void write_nodal_values_elementwise(VTKFileWriter& File, TFunction& u,
		                                    const std::vector<size_t>& vFct,
		                                    Grid& grid, const int si);

	/**
	 * This function writes the values of a function as a \<DataArray\> field to
	 * the vtu file.
	 *
	 * \param[in,out]	File		file to write the points
	 * \param[in]		u			discrete function
	 * \param[in]		vFct		components to be written
	 * \param[in]		name		name to appear for the component
	 * \param[in]		grid		Grid
	 * \param[in]		si			subset
	 * \param[in]		dim			dimension of subset
	 * \param[in]		numVert		number of vertices
	 */
		template <typename TFunction>
		void write_nodal_values(VTKFileWriter& File, TFunction& u,
								const std::vector<size_t>& vFct,
								const std::string& name,
								Grid& grid, const int si, const int dim,
								const int numVert);

	/**
	 * This function writes the values of a function as a \<DataArray\> field to
	 * the vtu file.
	 *
	 * \param[in,out]	File		file to write the points
	 * \param[in]		u			discrete function
	 * \param[in]		vFct		components to be written
	 * \param[in]		name		name to appear for the component
	 * \param[in]		grid		Grid
	 * \param[in]		ssGrp		subsets
	 * \param[in]		dim			dimension of subsets
	 * \param[in]		numVert		number of vertices
	 */
		template <typename TFunction>
		void write_nodal_values(VTKFileWriter& File, TFunction& u,
								const std::vector<size_t>& vFct,
								const std::string& name,
								Grid& grid, const SubsetGroup& ssGrp, const int dim,
								const int numVert);

	///	writes the nodal scalar data
	/// \{
		template <typename TElem, typename TFunction, typename TData>
		void write_nodal_data_elementwise(VTKFileWriter& File, TFunction& u,
		                                  number time,
		                                  SmartPtr<UserData<TData, TDim> > spData,
		                                  Grid& grid, const int si);
		
		template <typename TFunction, typename TData>
		void write_nodal_data(VTKFileWriter& File, TFunction& u, number time,
		                      SmartPtr<UserData<TData, TDim> > spData,
		                      const int numCmp,
		                      const std::string& name,
		                      Grid& grid, const SubsetGroup& ssGrp, const int dim,
		                      const int numVert);
	/// \}

		template <typename TFunction>
		void write_nodal_values_piece(VTKFileWriter& File, TFunction& u, number time,
		                              Grid& grid, const SubsetGroup& ssGrp, const int dim,
		                              const int numVert);

	///////////////////////////////////////////////////////////////////////////
	// cell data

	/**
	 * This method writes the cell values of a function to file. If the function
	 * group consists of more than on component, than a vector of components is
	 * expected.
	 *
	 * \param[in]	File		file stream
	 * \param[in]	u			grid function
	 * \param[in]	vFct		components to be written
	 * \param[in]	grid		Grid
	 * \param[in]	si			subset index
	 */
		template <typename TElem, typename TFunction>
		void write_cell_values_elementwise(VTKFileWriter& File, TFunction& u,
										   const std::vector<size_t>& vFct,
										   Grid& grid, const int si);

	/**
	 * This function writes the values of a function as a \<DataArray\> field to
	 * the vtu file.
	 *
	 * \param[in,out]	File		file to write the points
	 * \param[in]		u			discrete function
	 * \param[in]		vFct		components to be written
	 * \param[in]		name		name to appear for the component
	 * \param[in]		grid		Grid
	 * \param[in]		ssGrp		subset
	 * \param[in]		dim			dimension of subsets
	 * \param[in]		numVert		number of vertices
	 */
		template <typename TFunction>
		void write_cell_values(VTKFileWriter& File, TFunction& u,
								const std::vector<size_t>& vFct,
								const std::string& name,
								Grid& grid, const SubsetGroup& ssGrp, const int dim,
								const int numElem);

	///	writes the nodal cell data
	/// \{
		template <typename TElem, typename TFunction, typename TData>
		void write_cell_data_elementwise(VTKFileWriter& File, TFunction& u, number time,
										  SmartPtr<UserData<TData, TDim> > spData,
										  Grid& grid, const int si);

		template <typename TFunction, typename TData>
		void write_cell_data(VTKFileWriter& File, TFunction& u, number time,
							  SmartPtr<UserData<TData, TDim> > spData,
							  const int numCmp,
							  const std::string& name,
							  Grid& grid, const SubsetGroup& ssGrp, const int dim,
							  const int numElem);
	/// \}

		template <typename TFunction>
		void write_cell_values_piece(VTKFileWriter& File, TFunction& u, number time,
									  Grid& grid, const SubsetGroup& ssGrp, const int dim,
									  const int numElem);

	///////////////////////////////////////////////////////////////////////////
	// file names

	///	writes a grouping *.pvtu file
		template <typename TFunction>
		void write_pvtu(TFunction& u, const std::string&  filename,
		                int si, int step, number time);

	public:
	///	writes a grouping *.pvd file, grouping all data from different subsets
		static void write_subset_pvd(int numSubset, const std::string&  filename,
		                             int step = -1, number time = 0.0);

	///	creates the needed vtu file name
		static void vtu_filename(std::string& nameOut, std::string nameIn,
		                         int rank, int si, int maxSi, int step);

	///	create the needed pvtu file name
		static void pvtu_filename(std::string& nameOut, std::string nameIn,
		                          int si, int maxSi, int step);

	///	creates the needed pvd file name
		static void pvd_filename(std::string& nameOut, std::string nameIn);

	///	creates the needed pvd file name to group the time steps
		static void pvd_time_filename(std::string& nameOut, std::string nameIn,
		                              int step);

	public:
	///	default constructor
		VTKOutput()	: m_bSelectAll(true), m_bBinary(true), m_bWriteGrid(true), m_bWriteSubsetIndices(false), m_bWriteProcRanks(false) {} //TODO: maybe true?

	/// should values be printed in binary (base64 encoded way ) or plain ascii
		void set_binary(bool b) {m_bBinary = b;};

		void set_write_grid(bool b) {m_bWriteGrid = b;};

		void set_write_subset_indices(bool b) {m_bWriteSubsetIndices = b;};

		void set_write_proc_ranks(bool b) {m_bWriteProcRanks = b;};

	protected:
	///	returns true if name for vtk-component is already used
		bool vtk_name_used(const char* name) const;

	///	writes data to stream
	/**
	 * The purpose of the function is to convert a double data to binary float
	 * (the Float32-format as used in vtk) or ASCII representation. Note that
	 * the ASCII output should contain only numbers in the range of the normalized
	 * Float32 representation, i.e. with the minimum absolute value
	 * 1.1755e-38 = 2^-126. As 'float'-variables can potentially store denormalized
	 * numbers (and this is really the case in the practice) with the minimum
	 * absolute value 1.4013e-45 = 2^-149 that are not correctly read by some
	 * visualization tools (in some operating systems), these function replace
	 * those values (lying near to 0) with 0.
	 */
	/// \{
		inline void write_item_to_file(VTKFileWriter& File, float data);
		inline void write_item_to_file(VTKFileWriter& File, double data) {write_item_to_file(File, (float) data);};
		inline void write_item_to_file(VTKFileWriter& File, const ug::MathVector<1>& data);
		inline void write_item_to_file(VTKFileWriter& File, const ug::MathVector<2>& data);
		inline void write_item_to_file(VTKFileWriter& File, const ug::MathVector<3>& data);
		inline void write_item_to_file(VTKFileWriter& File, const ug::MathMatrix<1,1>& data);
		inline void write_item_to_file(VTKFileWriter& File, const ug::MathMatrix<2,2>& data);
		inline void write_item_to_file(VTKFileWriter& File, const ug::MathMatrix<3,3>& data);
	/// \}
	
	/// prints ascii representation of a float in the Float32 format (a protection against the denormalized floats)
		inline VTKFileWriter& write_asc_float(VTKFileWriter& File, float data);

	protected:
	///	scheduled components to be printed
		bool m_bSelectAll;
	/// print values in binary (base64 encoded way) or plain ascii
		bool m_bBinary;
		std::map<std::string, std::vector<std::string> > m_vSymbFct;
		std::map<std::string, std::vector<std::string> > m_vSymbFctNodal;
		std::map<std::string, std::vector<std::string> > m_vSymbFctElem;
		typedef typename std::map<std::string,
				std::vector<std::string> >::iterator ComponentsIterator;

	///	scheduled scalar data to be printed
		std::map<std::string, SmartPtr<UserData<number, TDim> > > m_vScalarNodalData;
		std::map<std::string, SmartPtr<UserData<number, TDim> > > m_vScalarElemData;
		typedef typename std::map<std::string,
				SmartPtr<UserData<number, TDim> > >::iterator ScalarDataIterator;

	///	scheduled vector data to be printed
		std::map<std::string, SmartPtr<UserData<MathVector<TDim>, TDim> > > m_vVectorNodalData;
		std::map<std::string, SmartPtr<UserData<MathVector<TDim>, TDim> > > m_vVectorElemData;
		typedef typename std::map<std::string,
				SmartPtr<UserData<MathVector<TDim>, TDim> > >::iterator VectorDataIterator;

	///	scheduled vector data to be printed
		std::map<std::string, SmartPtr<UserData<MathMatrix<TDim,TDim>, TDim> > > m_vMatrixNodalData;
		std::map<std::string, SmartPtr<UserData<MathMatrix<TDim,TDim>, TDim> > > m_vMatrixElemData;
		typedef typename std::map<std::string,
				SmartPtr<UserData<MathMatrix<TDim,TDim>, TDim> > >::iterator MatrixDataIterator;

	///	map storing the time points
		std::map<std::string, std::vector<number> > m_mTimestep;

		bool m_bWriteGrid;
		std::string m_sComment;

		bool m_bWriteSubsetIndices;
		bool m_bWriteProcRanks;
};

} // namespace ug

#include "vtkoutput_impl.h"

#endif /* __H__UG__LIB_DISC__IO__VTKOUTPUT__ */
