/*=========================================================================

  Program:   Insight Segmentation & Registration Toolkit
  Module:    $RCSfile: itkShapedNeighborhoodIterator.h,v $
  Language:  C++
  Date:      $Date: 2005/10/20 13:25:26 $
  Version:   $Revision: 1.12 $

  Copyright (c) Insight Software Consortium. All rights reserved.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
#ifndef __itkShapedNeighborhoodIterator_h
#define __itkShapedNeighborhoodIterator_h

#include <vector>
#include <list>
#include "itkConstShapedNeighborhoodIterator.h"

namespace itk {

/** \class ShapedNeighborhoodIterator
 *
 * \brief  A neighborhood iterator which can take on an arbitrary shape.
 *
 * \par General Information
 * The ShapedNeighborhoodIterator is a refinement of NeighborhoodIterator which
 * allows the user to specify which of the neighborhood elements are active and
 * which will be ignored.  This is useful for applications which only need to
 * work with a subset of the neighborhood around a pixel such as morphological
 * operations or cellular automata.  This iterator can also be used, for
 * example, to specify "cross-shaped" neighborhood where only elements along a
 * spatial axes are significant.
 *
 *\par Constructing a shaped neighborhood iterator
 * A shaped neighborhood iterator is constructed by constructing a list of
 * active neighbor locations.  The list is called the ActiveIndexList.  The
 * methods ActivateOffset, DeactivateOffset, and ClearActiveList are used to
 * construct the ActiveIndexList.  The argument to Activate/DeactivateOffset is
 * an itk::Offset which represents the ND spatial offset from the center of the
 * neighborhood.  For example, to activate the center pixel in the neighborhood,
 * you would do the following:
 *
 * \code
 * typedef Image<float, 3> ImageType;
 * ShapedNeighborhoodIterator<ImageType> it(radius, image, region);
 * ShapedNeighborhoodIterator<ImageType>::OffsetType offset = {{0,0,0}};
 * it.ActivateOffset(offset);
 * \endcode
 *
 * where radius, image, and region are as described in NeighborhoodIterator.
 *
 * Once a neighborhood location has been activated, iteration (operator++,
 * operator--, operator+=, operator-=) will update the value at the active
 * location.  Note that values at inactive locations will NOT be valid if
 * queried.
 *
 *\par Accessing elements in a shaped neighborhood.
 * To access the value at an active neighborhood location, you can use the
 * standard GetPixel, SetPixel methods.  SetPixel is not defined for
 * ConstShapedNeighborhoodIterator.   The class will not complain if you
 * attempt to access a value at a non-active location, but be aware that the
 * result will be undefined.  Error checking is not done in this case for the
 * sake of efficiency.
 *
 * A second way to access active shaped neighborhood values is through a
 * ShapedNeighborhoodIterator::Iterator or
 * ConstShapedNeighborhoodIterator::ConstIterator.  The following example
 * demonstrates the use of these iterators.
 *
 * \code
 * typedef Image<float, 3> ImageType;
 * ShapedNeighborhoodIterator<ImageType> it(radius, image, region);
 * .
 * .
 * .
 * it.ActivateOffset(offset1);
 * it.ActivateOffset(offset2);
 * it.ActivateOffset(offset3);
 * etc..
 * .
 * .
 * .
 * ShapedNeighborhoodIterator<ImageType>::Iterator i;
 * for (i = it.Begin(); ! i.IsAtEnd(); i++)
 * { i.Set(i.Get() + 1.0); }
 * \\ you may also use i != i.End(), but IsAtEnd() may be slightly faster.
 * \endcode
 *
 * You can also iterate backward through the neighbohood active list.
 *
 * \code
 * i = it.End();
 * i--;
 * while (i != it.Begin())
 * {
 *   i.Set(i.Get() + 1.0);
 *   i--;
 * }
 *  i.Set(i.Get() + 1.0);
 * \endcode
 *
 * The Get() Set() syntax was chosen versus defining operator* for these
 * iterators because lvalue vs. rvalue context information is needed to
 * determine whether bounds checking must take place.
 *
 * \sa Neighborhood
  *
 * \par MORE INFORMATION
 * For a complete description of the ITK Image Iterators and their API, please
 * see the Iterators chapter in the ITK Software Guide.  The ITK Software Guide
 * is available in print and as a free .pdf download from http://www.itk.org.
 *
 * \ingroup ImageIterators
 *
 * \sa ImageConstIterator \sa ConditionalConstIterator
 * \sa ConstNeighborhoodIterator \sa ConstShapedNeighborhoodIterator
 * \sa ConstSliceIterator  \sa CorrespondenceDataStructureIterator
 * \sa FloodFilledFunctionConditionalConstIterator
 * \sa FloodFilledImageFunctionConditionalConstIterator
 * \sa FloodFilledImageFunctionConditionalIterator
 * \sa FloodFilledSpatialFunctionConditionalConstIterator
 * \sa FloodFilledSpatialFunctionConditionalIterator
 * \sa ImageConstIterator \sa ImageConstIteratorWithIndex
 * \sa ImageIterator \sa ImageIteratorWithIndex
 * \sa ImageLinearConstIteratorWithIndex  \sa ImageLinearIteratorWithIndex
 * \sa ImageRandomConstIteratorWithIndex  \sa ImageRandomIteratorWithIndex
 * \sa ImageRegionConstIterator \sa ImageRegionConstIteratorWithIndex
 * \sa ImageRegionExclusionConstIteratorWithIndex
 * \sa ImageRegionExclusionIteratorWithIndex
 * \sa ImageRegionIterator  \sa ImageRegionIteratorWithIndex
 * \sa ImageRegionReverseConstIterator  \sa ImageRegionReverseIterator
 * \sa ImageReverseConstIterator  \sa ImageReverseIterator
 * \sa ImageSliceConstIteratorWithIndex  \sa ImageSliceIteratorWithIndex
 * \sa NeighborhoodIterator \sa PathConstIterator  \sa PathIterator
 * \sa ShapedNeighborhoodIterator  \sa SliceIterator
 * \sa ImageConstIteratorWithIndex */
template<class TImage,  class TBoundaryCondition
                       = ZeroFluxNeumannBoundaryCondition<TImage> >
class ITK_EXPORT ShapedNeighborhoodIterator
  :  public ConstShapedNeighborhoodIterator<TImage, TBoundaryCondition>
{
public:
  /** Extract image type information. */
  typedef typename TImage::InternalPixelType InternalPixelType;
  typedef typename TImage::PixelType PixelType;

  /** Save the image dimension. */
  itkStaticConstMacro(Dimension, unsigned int, TImage::ImageDimension);

  /** Standard class typedefs. */
  typedef ShapedNeighborhoodIterator Self;
  typedef ConstShapedNeighborhoodIterator<TImage, TBoundaryCondition> Superclass;
  
  /** Inherit typedefs from superclass */
  typedef typename Superclass::OffsetType OffsetType;
  typedef typename OffsetType::OffsetValueType OffsetValueType;
  typedef typename Superclass::RadiusType RadiusType;
  typedef typename Superclass::SizeType SizeType;
  typedef typename Superclass::SizeValueType SizeValueType;
  typedef typename Superclass::ConstIterator ConstIterator;
  typedef typename Superclass::IndexListType  IndexListType;
  typedef typename Superclass::BoundaryConditionType BoundaryConditionType;
  typedef typename Superclass::ImageBoundaryConditionPointerType ImageBoundaryConditionPointerType;
  typedef typename Superclass::NeighborhoodType NeighborhoodType;
  typedef typename Superclass::IndexType IndexType;
  typedef typename Superclass::ImageType ImageType;
  typedef typename Superclass::RegionType RegionType;
  typedef typename Superclass::IndexValueType IndexValueType;

  /** An  iterator for the ShapedNeighborhood classes.*/
  struct Iterator : public ConstIterator
  {
    Iterator() {}
    Iterator(Self *s) : ConstIterator(s) {}

    ~Iterator() {}
    const Iterator &operator=(const Iterator &o)
    {
      ConstIterator::operator=(o);
      return *this;
    }

    // Promote to public
    void Set(const PixelType &v) const
    { ConstIterator::ProtectedSet(v); }

  };

  /** Default constructor */
  ShapedNeighborhoodIterator()
  {
    m_BeginIterator = Iterator(this);
    m_EndIterator = Iterator(this);
    m_EndIterator.GoToEnd();
  }

  /** Virtual destructor */
  virtual ~ShapedNeighborhoodIterator() {}

  /** Constructor which establishes the region size, neighborhood, and image
   * over which to walk. */
  ShapedNeighborhoodIterator(const SizeType &radius,
                             const ImageType * ptr,
                             const RegionType &region
    ) : Superclass(radius, const_cast<ImageType*>(ptr),
                   region)
  {
    m_BeginIterator = Iterator(this);
    m_EndIterator = Iterator(this);
    m_EndIterator.GoToEnd();
  }

  // Expose the following methods from the superclass.  This is a restricted
  // subset of the methods available for NeighborhoodIterator.
  Superclass::SetPixel;
  Superclass::SetCenterPixel;

  /** Assignment operator */
  Self &operator=(const Self& orig)
  {
    Superclass::operator=(orig);

    // Reset begin and end pointer locations
    m_BeginIterator.GoToBegin();
    m_EndIterator.GoToEnd();
    return *this;
  }

  /** Standard itk print method */
  virtual void PrintSelf(std::ostream &, Indent) const;

  /** Returns a const iterator for the neighborhood which points to the first
   * pixel in the neighborhood. */
  Iterator &Begin() {    return m_BeginIterator;  }
  Iterator &End()   {   return m_EndIterator;     }

  /** Returns a const iterator for the neighborhood which points to the last
   * pixel in the neighborhood. */
  const ConstIterator &End() const
  {    return this->m_ConstEndIterator;  }

  void ClearActiveList()
  {
    Superclass::ClearActiveList();
    m_EndIterator.GoToEnd();
    m_BeginIterator.GoToBegin();
  }

protected:

   /** Copy constructor */
  ShapedNeighborhoodIterator( const ShapedNeighborhoodIterator & o);
  // purposely not implemented


  void ActivateIndex(const unsigned int n)
  {
    Superclass::ActivateIndex(n);
    m_EndIterator.GoToEnd();
    m_BeginIterator.GoToBegin();
  }

  void DeactivateIndex(const unsigned int n)
  {
    Superclass::DeactivateIndex(n);
    m_EndIterator.GoToEnd();
    m_BeginIterator.GoToBegin();
  }


  Iterator m_EndIterator;
  Iterator m_BeginIterator;
};

} // namespace itk


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

#endif

