/**============================================================================
 *
 * \file   filter.hpp
 * \brief  Apply a module filter to an image.
 *
 * \author Leblanc Christophe.
 * \date   07/11/2012
 * \email cleblancad@gmail.com
 *
 * Code inspired from:
 * 'Getting Started with ITK + VTK'
 * L. Ibanez, W. Schroeder, Insight Software Consortium.
 *
 *
 *===========================================================================*/

#ifndef TOMOPROCESS_FILTER_FILTER_HPP
#define TOMOPROCESS_FILTER_FILTER_HPP

#include "generic_filter.hpp"
#include "itkSimpleFilterWatcher.h"
#include <boost/assert.hpp>

TOMOPROCESS_OPEN_GLOBAL_NAMESPACE
TOMOPROCESS_OPEN_FILTER_NAMESPACE

/** \class Filter
 * \brief Apply a filter to an image.
 * 
 * Filter<ITKFilterType, ImageType>
 * 
 * Uses ITK.
 * 
 * \ingroup GenericFilter<ImageType>
 */
template<class ITKFilterT, class ImageT>
class Filter: public GenericFilter<ImageT>
{
public:
  //
  // Typedefs.
  //
  
  /// \brief Parent class.
  typedef GenericFilter<ImageT>		SuperClass;
  
  /// \brief Self type.
  typedef Filter 			Self;
  
  /// \brief ITK filter type.
  typedef ITKFilterT 			ITKFilterType;
  
  /// \brief ITK filter pointer type.
  typedef typename ITKFilterType::Pointer ITKFilterPtrType;
  
  /// \brief Image type.
  typedef ImageT 			ImageType;
  
  /// \brief Input image type.
  typedef typename ImageType::InputImageType  InputImageType;
  
  /// \brief Output image type.
  typedef typename ImageType::OutputImageType OutputImageType;
  
  /// \brief Input image pointer type.
  typedef typename ImageType::InputImagePtrType  InputImagePtrType;
  
  /// \brief Output image pointer type.
  typedef typename ImageType::OutputImagePtrType OutputImagePtrType;
  
  /// \brief Pointer object type returned by the filter.
  typedef typename SuperClass::ProcessObjectPtrType ProcessObjectPtrType;
  
  //
  // Functions.
  //
  
  /// \brief Default constructor;
  Filter();
  
  /// \brief Copy constructor.
  /// \param[in] rhs object to copy.
  Filter(const Filter &rhs);
  
  /// \brief Destructor.
  virtual ~Filter() {}
  
  /// \brief Copy operator.
  /// \param[in] rhs object to copy.
  /// \return Copied object.
  virtual Filter& operator=(const Filter &rhs);
  
  /// \brief Clone the data.
  /// \return Pointer on copied data.
  virtual Filter* Clone() const;
  
  /// \brief Sets the first filter input.
  /// \param[in] inputImage input image.
  virtual void SetInput(const InputImageType* inputImage)
  { m_Filter->SetInput(inputImage); }
  
  /// \brief Sets the filter's nth input.
  /// \param[in] n input number.
  /// \param[in] inputImage input image.
  virtual void SetInput(unsigned int n, const InputImageType* inputImage)
  { m_Filter->SetInput(n, inputImage); }
  
  /// \brief Returns the first filtered image.
  /// \return Output image.
  virtual OutputImageType* GetOutput()
  { return m_Filter->GetOutput(); }
  
  /// \brief Returns the nth filtered image.
  /// \param[in] n output image number.
  /// \return nth output image.
  virtual OutputImageType* GetOutput(unsigned int n)
  { return m_Filter->GetOutput(n); }
  
  /// \brief Updates the filter.
  virtual void Update();
  
  /// \brief Resets the pipeline.
  virtual void ResetPipeline()
  { m_Filter->ResetPipeline(); }
  
  /// \brief gets a pointer to the internal filter.
  virtual ProcessObjectPtrType GetFilter()
  { return m_Filter; }
  
  /// \brief Sets the release data flag on.
  virtual void ReleaseDataFlagOn()
  { m_Filter->ReleaseDataFlagOn(); }
  
  /// \brief Sets the release data flaf off.
  virtual void ReleaseDataFlagOff()
  { m_Filter->ReleaseDataFlagOff(); }
  
  /// \brief Sets the release data flag.
  /// \param[in] flag flag value.
  virtual void SetReleaseDataFlag(bool flag)
  { m_Filter->SetReleaseDataFlag(flag); }
  
  /// \brief Gets the release data flag.
  /// \return Flag.
  virtual bool GetReleaseDataFlag() const
  { return m_Filter->GetReleaseDataFlag(); }
  
  /// \brief Sets the verbose mode flag on.
  virtual void SetVerboseOn()
  { m_Verbose = true; }
  
  /// \brief Sets the verbose mode flag off.
  virtual void SetVerboseOff()
  { m_Verbose = false; }
  
  /// \brief Sets the verbose mode flag.
  /// \param[in] flag flag value.
  virtual void SetVerbose(bool flag)
  { m_Verbose = flag; }
  
  /// \brief Gets the verbose mode flag.
  /// \return Flag.
  virtual bool GetVerbose() const
  { return m_Verbose; }
  
  /// \brief Sets the draw mode flag on.
  virtual void SetDrawOn()
  { m_Draw = true; }
  
  /// \brief Sets the draw mode flag off.
  virtual void SetDrawOff()
  { m_Draw = false; }
  
  /// \brief Sets the draw mode flag.
  /// \param[in] flag flag value.
  virtual void SetDraw(bool flag)
  { m_Draw = flag; }
  
  /// \brief Gets the draw mode flag.
  /// \return Flag.
  virtual bool GetDraw() const
  { return m_Draw; }
  
protected:
  bool m_Draw;    ///< Flag for draw mode.
  bool m_Verbose; ///< Flag for verbose mode.
  ITKFilterPtrType m_Filter; ///< ITK filter.
};

//============================================================================
//=========================== Template Specialization ========================
//============================================================================

template<class ImageT>
class Filter<itk::SimpleFilterWatcher, ImageT>: public GenericFilter<ImageT>
{
public:
  //
  // Typedefs.
  //
  
  /// \brief Parent class.
  typedef GenericFilter<ImageT>		SuperClass;
  
  /// \brief Self type.
  typedef Filter 			Self;
  
  /// \brief ITK filter type.
  typedef itk::SimpleFilterWatcher	ITKFilterType;
  
  /// \brief ITK filter pointer type.
  typedef ITKFilterType*	        ITKFilterPtrType;
  
  /// \brief Image type.
  typedef ImageT 			ImageType;
  
  /// \brief Input image type.
  typedef typename ImageType::InputImageType  InputImageType;
  
  /// \brief Output image type.
  typedef typename ImageType::OutputImageType OutputImageType;
  
  /// \brief Input image pointer type.
  typedef typename ImageType::InputImagePtrType  InputImagePtrType;
  
  /// \brief Output image pointer type.
  typedef typename ImageType::OutputImagePtrType OutputImagePtrType;
  
  /// \brief Pointer object type returned by the filter.
  typedef typename SuperClass::ProcessObjectPtrType ProcessObjectPtrType;
  
  /// \brief Filter to watch pointer type.
  typedef ProcessObjectPtrType FilterToWatchPtrType;
  
  //
  // Functions.
  //
  
  /// \brief Default constructor;
  Filter();
  
  /// \brief Copy constructor.
  /// \param[in] rhs object to copy.
  Filter(const Filter &rhs);
  
  /// \brief Destructor.
  virtual ~Filter() { delete m_Filter; }
 
  /// \brief Copy operator.
  /// \param[in] rhs object to copy.
  /// \return Copied object.
  virtual Filter& operator=(const Filter &rhs);
  
  /// \brief Clone the data.
  /// \return Pointer on copied data.
  virtual Filter* Clone() const;
  
  /// \brief Sets the filter's parameters
  /// \param[in] filterToWatch filter to watch.
  /// \param[in] filterName filter name.
  inline void SetParameters(FilterToWatchPtrType filterToWatch,
			    const std::string &filterName);
  
  /// \brief Sets the first filter input.
  /// \param[in] inputImage input image.
  virtual void SetInput(const InputImageType* inputImage)
  {}
  
  /// \brief Sets the filter's nth input.
  /// \param[in] n input number.
  /// \param[in] inputImage input image.
  virtual void SetInput(unsigned int n, const InputImageType* inputImage)
  {}
  
  /// \brief Returns the first filtered image.
  /// \return Output image.
  virtual OutputImageType* GetOutput()
  { BOOST_ASSERT_MSG(false, "This function can not be used."); return OutputImagePtrType(); }
  
  /// \brief Returns the nth filtered image.
  /// \param[in] n output image number.
  /// \return nth output image.
  virtual OutputImageType* GetOutput(unsigned int n)
  { BOOST_ASSERT_MSG(false, "This function can not be used"); return OutputImagePtrType(); }
  
  /// \brief Updates the filter.
  virtual void Update() {}
  
    /// \brief Resets the pipeline.
  virtual void ResetPipeline()
  { BOOST_ASSERT_MSG(false, "This function can not be used"); }
  
  /// \brief gets a pointer to the internal filter.
  virtual ProcessObjectPtrType GetFilter()
  { BOOST_ASSERT_MSG(false, "This function can not be used"); return ProcessObjectPtrType(); }
  
    /// \brief gets a pointer to the internal filter.
  virtual ITKFilterPtrType GetWatchFilter()
  { return m_Filter; }
  
  /// \brief Sets the release data flag on.
  virtual void ReleaseDataFlagOn() {}
  
  /// \brief Sets the release data flaf off.
  virtual void ReleaseDataFlagOff() {}
  
  /// \brief Sets the release data flag.
  /// \param[in] flag flag value.
  virtual void SetReleaseDataFlag(bool flag) {}
  
  /// \brief Gets the release data flag.
  /// \return Flag.
  virtual bool GetReleaseDataFlag() const
  { return false; }
  
  /// \brief Sets the verbose mode flag on.
  virtual void SetVerboseOn()
  { m_Verbose = true; }
  
  /// \brief Sets the verbose mode flag off.
  virtual void SetVerboseOff()
  { m_Verbose = false; }
  
  /// \brief Sets the verbose mode flag.
  /// \param[in] flag flag value.
  virtual void SetVerbose(bool flag)
  { m_Verbose = flag; }
  
  /// \brief Gets the verbose mode flag.
  /// \return Flag.
  virtual bool GetVerbose() const
  { return m_Verbose; }
  
  /// \brief Sets the draw mode flag on.
  virtual void SetDrawOn()
  { m_Draw = true; }
  
  /// \brief Sets the draw mode flag off.
  virtual void SetDrawOff()
  { m_Draw = false; }
  
  /// \brief Sets the draw mode flag.
  /// \param[in] flag flag value.
  virtual void SetDraw(bool flag)
  { m_Draw = flag; }
  
  /// \brief Gets the draw mode flag.
  /// \return Flag.
  virtual bool GetDraw() const
  { return m_Draw; }
  
protected:
  bool m_Draw;    ///< Flag for draw mode.
  bool m_Verbose; ///< Flag for verbose mode.
  ITKFilterPtrType m_Filter; ///< ITK filter.
};

// Convenience struct.
template<class ImageT>
struct WatchFilter
{
  typedef Filter<itk::SimpleFilterWatcher, ImageT> type;
};

TOMOPROCESS_CLOSE_FILTER_NAMESPACE
TOMOPROCESS_CLOSE_GLOBAL_NAMESPACE

#include "filter.hxx"

#endif // TOMOPROCESS_FILTER_FILTER_HPP