#ifndef __itkLevelTracingImageFilter_h
#define __itkLevelTracingImageFilter_h

#include "itkImage.h"
#include "itkImageToImageFilter.h"
#include "itkSimpleDataObjectDecorator.h"
#include "itkChainCodePath.h"

namespace itk{

/** /class LevelTracingImageFilter
 * \brief Trace a level curve/surface given a seed point on the level curve/surface.
 * 
 * LevelTracingImageFilter traces a level curve (or surface) from a
 * seed point.  The pixels on this level curve "boundary" are labeled
 * as 1. Does nothing if seed is in uniform area.
 *
 * LevelTracingImageFilter provides a quick method to select a point
 * on a boundary of an object in a grayscale image and retrieve the
 * entire boundary of the object.
 *
 * For 2D images, the algorithm follows the boundary using 8-connected
 * neighbors.  For ND images, the algorithm traces the boundary using
 * face connected neighbors.
 *  
 */

template <class TInputImage, class TOutputImage>
class ITK_EXPORT LevelTracingImageFilter:public ImageToImageFilter<TInputImage,TOutputImage>
{
public:
  /** Standard class typedefs. */
  typedef LevelTracingImageFilter Self;
  typedef ImageToImageFilter<TInputImage,TOutputImage> Superclass;
  typedef SmartPointer<Self> Pointer;
  typedef SmartPointer<const Self> ConstPointer;

  /** Method for creation through the object factory. */
  itkNewMacro(Self);

  /** Run-time type information (and related methods).  */
  itkTypeMacro(LevelTracingImageFilter,
               ImageToImageFilter);
 
  /** Image related typedefs. */
  itkStaticConstMacro(ImageDimension, unsigned int,
                      TInputImage::ImageDimension ) ;

  typedef TInputImage InputImageType;
  typedef typename InputImageType::Pointer InputImagePointer;
  typedef typename InputImageType::ConstPointer InputImageConstPointer;
  typedef typename InputImageType::RegionType InputImageRegionType; 
  typedef typename InputImageType::PixelType InputImagePixelType; 
  typedef typename InputImageType::IndexType IndexType;
  typedef typename InputImageType::SizeType SizeType;
  
  typedef TOutputImage OutputImageType;
  typedef typename OutputImageType::Pointer OutputImagePointer;
  typedef typename OutputImageType::RegionType OutputImageRegionType; 
  typedef typename OutputImageType::PixelType OutputImagePixelType;

  typedef ChainCodePath<ImageDimension> ChainCodePathType;
  typedef typename ChainCodePathType::Pointer ChainCodePathPointer;

  typedef typename ChainCodePathType::OffsetType OffsetType;

  /** Smart Pointer type to a DataObject. */
  typedef typename DataObject::Pointer DataObjectPointer;

  /** Image dimension constants */
  itkStaticConstMacro(InputImageDimension, unsigned int,
                      TInputImage::ImageDimension);
  itkStaticConstMacro(OutputImageDimension, unsigned int,
                      TOutputImage::ImageDimension);

  void PrintSelf ( std::ostream& os, Indent indent ) const;
  
  // Set/Get the seed
  itkSetMacro(Seed, IndexType); 
  itkGetMacro(Seed, IndexType);

  // Did we move the seed point to put in on a boundary?
  itkGetMacro(MovedSeed, bool);
  
  int GetThreshold();
  InputImagePixelType GetMaxIntensity() {return m_Max;}
  InputImagePixelType GetMinIntensity() {return m_Min;}
  
  // Get the output as a ChainCodePath.  This output is only generated in the 2D case.
  ChainCodePathType *GetPathOutput() { return static_cast<ChainCodePathType*>(this->ProcessObject::GetOutput(1)); }

protected:
  LevelTracingImageFilter();
  ~LevelTracingImageFilter(){}
   
  // Override since the filter needs all the data for the algorithm
  void GenerateInputRequestedRegion();

  // Override since the filter produces the entire dataset
  void EnlargeOutputRequestedRegion(DataObject *output);

  void GenerateData();

  DataObjectPointer MakeOutput(unsigned int output);

  // To control overloaded versions of ComputeThreshold
  struct DispatchBase {};
  template<signed int VDimension>
  struct Dispatch : DispatchBase {};
  
  /** This method traces the level curve/surface. */
  virtual void Trace( const Dispatch<2> & );
  virtual void Trace( const DispatchBase &); 

private:
  LevelTracingImageFilter(const Self&); //purposely not implemented
  void operator=(const Self&); //purposely not implemented

  IndexType m_Seed;
  InputImagePixelType m_Max, m_Min;
  bool m_MovedSeed;

};


//#ifdef ITK_USE_CONCEPT_CHECKING
//  /** Begin concept checking */
//  itkConceptMacro(OutputEqualityComparableCheck,
//    (Concept::EqualityComparable<OutputImagePixelType>));
//  itkConceptMacro(InputEqualityComparableCheck,
//    (Concept::EqualityComparable<InputImagePixelType>));
//  itkConceptMacro(SameDimensionCheck,
//    (Concept::SameDimension<InputImageDimension, OutputImageDimension>));
//  itkConceptMacro(IntConvertibleToInputCheck,
//    (Concept::Convertible<int, InputImagePixelType>));
//  itkConceptMacro(OutputOStreamWritableCheck,
//    (Concept::OStreamWritable<OutputImagePixelType>));
//  /** End concept checking */
//#endif

}

#ifndef ITK_MANUAL_INSTANTIATION
#include "itkLevelTracingImageFilter.txx"
#endif

#endif
