/* -*- mia-c++  -*-
 *
 * This file is part of MIA - a toolbox for medical image analysis 
 * Copyright (c) Leipzig, Madrid 1999-2017 Gert Wollny
 *
 * MIA is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with MIA; if not, see <http://www.gnu.org/licenses/>.
 *
 */

#ifndef mia_2d_cstkernel_hh
#define mia_2d_cstkernel_hh

#include <complex>
#include <fftw3.h>

#include <mia/core/defines.hh>
#include <mia/core/factory.hh>
#include <mia/core/spacial_kernel.hh>
#include <mia/core/cstplan.hh>
#include <mia/2d/datafield.hh>
#include <mia/2d/image.hh>

NS_MIA_BEGIN

/// plugin-helper structure 
struct EXPORT_2D cst2d_kernel {
	/// plugin path helper value 
	static const char *type_descr;
};

/**
   @ingroup filtering
   @brief Base class for cos/sin transformation filters 

   This class defines the interface for filter that uses cosinus and sinus transforms to move 
   the data into a dual space, runs some filter there and then transforms the data back. 
   This class may be used for gray scale image data and vector data. 
   
   @tparam The actual data type to run the filter on 
   @remark why is this called a kernel? 
*/

template <typename T>
class EXPORT_2D TCST2DKernel :public CProductBase {
public:
	/// some helper typedef for the plug-in handler 
	typedef typename plugin_data_type<T>::type plugin_data; 

	/// define the plugin-type helper to get the search path 
	typedef cst2d_kernel plugin_type; 

	/// define the type of the FFTW plan used 
	typedef TCSTPlan<T> CPlan;
	
	/**
	   Consruct the filter as either forward or backward 
	   @remark why is this? 
	 */
	TCST2DKernel(fftwf_r2r_kind forward);
	
	virtual ~TCST2DKernel();

	/**
	   Apply the transform 
	   @param[in] in 
	   @param[out] out 
	 */
	void apply(const T& in, T& out) const;

	/**
	   Prepare the transform based on the size of the data field to be transformed 
	   @param size 
	 */
	void prepare(const C2DBounds& size);

private:
        virtual CPlan *do_prepare(fftwf_r2r_kind fw_kind, const std::vector<int>& size) = 0;

	fftwf_r2r_kind m_forward;
	std::unique_ptr<CPlan> m_plan;
};

/**
  \cond NEEDS_REHAUL 
*/
typedef TCST2DKernel<C2DFVectorfield> CCST2DVectorKernel;
typedef TCST2DKernel<C2DFImage>       CCST2DImageKernel;

typedef std::shared_ptr<CCST2DImageKernel > PCST2DImageKernel;
typedef std::shared_ptr<CCST2DVectorKernel > PCST2DVectorKernel;

typedef TFactory<CCST2DVectorKernel> CCST2DVectorKernelPlugin;
typedef TFactory<CCST2DImageKernel> CCST2DImgKernelPlugin;

typedef THandlerSingleton<TFactoryPluginHandler<CCST2DVectorKernelPlugin> > CCST2DVectorKernelPluginHandler;
typedef THandlerSingleton<TFactoryPluginHandler<CCST2DImgKernelPlugin> > CCST2DImgKernelPluginHandler;

template <> const char *  const 
TPluginHandler<TFactory<CCST2DImageKernel>>::m_help;

template <> const char *  const 
TPluginHandler<TFactory<CCST2DVectorKernel>>::m_help;


extern template class EXPORT_2D TCST2DKernel<C2DFVectorfield>; 
extern template class EXPORT_2D TFactory<CCST2DVectorKernel>; 
extern template class EXPORT_2D TFactoryPluginHandler<CCST2DVectorKernelPlugin>; 
extern template class EXPORT_2D THandlerSingleton<TFactoryPluginHandler<CCST2DVectorKernelPlugin> >; 


extern template class EXPORT_2D TCST2DKernel<C2DFImage>;
extern template class EXPORT_2D TFactory<CCST2DImageKernel>; 
extern template class EXPORT_2D TFactoryPluginHandler<CCST2DImgKernelPlugin>; 
extern template class EXPORT_2D THandlerSingleton<TFactoryPluginHandler<CCST2DImgKernelPlugin> >; 

/// \endcond 

NS_MIA_END

#endif

