#ifndef XTK_BOX
#define XTK_BOX

#include "vtkImageExport.h"
#include "vtkImageImport.h"
#include "itkVTKImageImport.h"
#include "itkVTKImageExport.h"

#include "vtkImageData.h"
//ETX
#include "itkImage.h"
//BTX
template <typename ImageType>
class XTKBox {
    protected:
	//BTX
	typedef itk::VTKImageImport<ImageType> ImageImportType;
	typedef itk::VTKImageExport<ImageType> ImageExportType;
	typename ImageImportType::Pointer	itkImporter;
	typename ImageExportType::Pointer	itkExporter;
	
	vtkImageImport*		vtkImporter;
	vtkImageExport*		vtkExporter;
	
	ImageType*	itkImage;
	vtkImageData*	vtkImage;
	//ETX
    public:
	XTKBox() {};
	XTKBox(vtkImageData*);
	
	//get/set ITK Image Data
	void setITKImage(ImageType*);
	ImageType* getITKFromVTKImage();
	//get/set VTK Image Data
	void setVTKImage(vtkImageData*);
	vtkImageData* getVTKFromITKImage();
	vtkImageData* getVTKImage();
};

///Two macros that have to be called in all ivkt Filters.
///vtkITKFilter_CXX_Macro(ClassName) and vtkITKFilter_H_Macro
///(they construct the proper ITK ImageType according to the input vtkImageData)
#define vtkITKFilter_H_Macro \
	virtual void StartTypeGeneration(vtkImageData*); \
	template<unsigned int DIM> \
	void FinalizeImageType(vtkImageData* vtkInput); \
	template<unsigned int DIM, unsigned int COMP> \
	void CreateType(vtkImageData* vtkInput);

#define vtkITKFilter_CXX_Macro(thisClass) \
/** \
 * Step 1) Initialize TypeCreation by getting the dimensionality of the vtkInput. \
 */ \
void thisClass:: \
StartTypeGeneration(vtkImageData* vtkInput) \
{ \
    unsigned int dimensionality = vtkInput->GetDataDimension(); \
    switch(dimensionality) { \
	case 1: FinalizeImageType<1>(vtkInput); \
	        break; \
	case 2: FinalizeImageType<2>(vtkInput); \
	        break; \
	case 3: FinalizeImageType<3>(vtkInput); \
	        break; \
	default: \
	    vtkErrorMacro(<<"vtkSimpleImageToImageITKFilter: ApplyITKFilter Error" \
	    << "\ndimensionality of vtk input image is " << dimensionality); \
    } \
} \
/** \
 * Step 2) Get the number of scalar components and setup the final image type. \
 */ \
template<unsigned int DIM> \
void thisClass:: \
FinalizeImageType(vtkImageData* vtkInput) \
{ \
    unsigned int components = vtkInput->GetNumberOfScalarComponents(); \
    \
    switch(components) { \
	case 1: return CreateType<DIM, 1>(vtkInput); \
		break; \
	case 2: return CreateType<DIM, 2>(vtkInput); \
		break; \
	case 3: return CreateType<DIM, 3>(vtkInput); \
		break; \
	default: \
	    vtkErrorMacro(<<"vtkSimpleImageToImageITKFilter: SetupImageType Error" \
	    << "\nnumber of components of vtk input image is " << components); \
    } \
} \
/** \
 * Step 3) Setup the appropriate itk::Image data type. \
 */ \
template<unsigned int DIM, unsigned int COMP> \
void thisClass:: \
CreateType(vtkImageData* vtkInput) \
{ \
    const int scalarType = vtkInput->GetScalarType(); \
    if (scalarType == VTK_CHAR) { \
	typedef itk::Vector< char, COMP >	PixelType; \
	typedef itk::Image< PixelType, DIM >	ImageType; \
	ApplyFilter<ImageType>( vtkInput ); \
    } else if (scalarType == VTK_UNSIGNED_CHAR) { \
	typedef itk::Vector< unsigned char, COMP >	PixelType; \
	typedef itk::Image< PixelType, DIM >		ImageType; \
	ApplyFilter<ImageType>( vtkInput ); \
    } else if (scalarType == VTK_SHORT) { \
	typedef itk::Vector< short, COMP >	PixelType; \
	typedef itk::Image< PixelType, DIM >	ImageType; \
	ApplyFilter<ImageType>( vtkInput ); \
    } else if (scalarType == VTK_UNSIGNED_SHORT) { \
	typedef itk::Vector< unsigned short, COMP >	PixelType; \
	typedef itk::Image< PixelType, DIM >		ImageType; \
	ApplyFilter<ImageType>( vtkInput ); \
    } else if (scalarType == VTK_INT) { \
	typedef itk::Vector< int, COMP >	PixelType; \
	typedef itk::Image< PixelType, DIM >	ImageType; \
	ApplyFilter<ImageType>( vtkInput ); \
    } else if (scalarType == VTK_UNSIGNED_INT) { \
	typedef itk::Vector< unsigned int, COMP >	PixelType; \
	typedef itk::Image< PixelType, DIM >		ImageType; \
	ApplyFilter<ImageType>( vtkInput ); \
    } else if (scalarType == VTK_LONG) { \
	typedef itk::Vector< long, COMP >	PixelType; \
	typedef itk::Image< PixelType, DIM >	ImageType; \
	ApplyFilter<ImageType>( vtkInput ); \
    } else if (scalarType == VTK_UNSIGNED_LONG) { \
	typedef itk::Vector< unsigned long, COMP >	PixelType; \
	typedef itk::Image< PixelType, DIM >		ImageType; \
	ApplyFilter<ImageType>( vtkInput ); \
    } else if (scalarType == VTK_FLOAT) { \
	typedef itk::Vector< float, COMP >	PixelType; \
	typedef itk::Image< PixelType, DIM >	ImageType; \
	ApplyFilter<ImageType>( vtkInput ); \
    } else if (scalarType == VTK_DOUBLE) { \
	typedef itk::Vector< double, COMP >	PixelType; \
	typedef itk::Image< PixelType, DIM >	ImageType; \
	ApplyFilter<ImageType>( vtkInput ); \
    } else { \
	const char* scalarTypeString = vtkInput->GetScalarTypeAsString(); \
	vtkErrorMacro(<<"vtkSimpleImageToImageITKFilter: CreateType Error" \
	    << "\nscalar type of vtk input image is " << scalarTypeString \
	    << "(" << scalarType << ")"); \
    } \
}
#endif

