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

  Program:   Insight Segmentation & Registration Toolkit
  Module:    $RCSfile: itkConnectedRegionsMeshFilter.h,v $
  Language:  C++
  Date:      $Date: 2009-04-23 03:53:34 $
  Version:   $Revision: 1.27 $

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

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.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 __itkConnectedRegionsMeshFilter_h
#define __itkConnectedRegionsMeshFilter_h

#include "itkMeshToMeshFilter.h"

namespace itk
{
  
/** \class ConnectedRegionsMeshFilter
 * \brief Extract portions of a mesh that are connected at vertices.
 *
 * ConnectedRegionsMeshFilter will extract portions of a mesh that
 * are connected at vertices. (Such connected portions of the mesh
 * are referred to as a region.) Options exist to extract the largest
 * region, a particular region, a region containing a specified
 * point, or a region containing a specified cell.
 *
 * \ingroup MeshFilters 
 */

template <class TInputMesh, class TOutputMesh>
class ITK_EXPORT ConnectedRegionsMeshFilter 
: public MeshToMeshFilter<TInputMesh, TOutputMesh> 
{
public:
  /**
   * Standard class typedefs.
   */
  typedef ConnectedRegionsMeshFilter               Self;

  /**
   * Standard "Superclass" typedef.
   */
  typedef MeshToMeshFilter<TInputMesh, TOutputMesh> Superclass;

  /** 
   * Smart pointer typedef support 
   */
  typedef SmartPointer<Self>                       Pointer;
  typedef SmartPointer<const Self>                 ConstPointer;

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

  /**
   * Convenient typedefs for this filter.
   */
  typedef TInputMesh                               InputMeshType;
  typedef TOutputMesh                              OutputMeshType;
  typedef typename TInputMesh::Pointer             InputMeshPointer;
  typedef typename TOutputMesh::Pointer            OutputMeshPointer;

  itkStaticConstMacro( PointDimension, unsigned int,
                       TInputMesh::PointDimension );

  typedef typename TInputMesh::PointType           InputMeshPointType;
  typedef typename TInputMesh::PointIdentifier     InputMeshPointIdentifier;
  typedef typename TInputMesh::PointsContainerPointer 
                                                   InputMeshPointsContainerPointer;
  typedef typename TInputMesh::CellsContainer      InputMeshCellsContainer;
  typedef typename TInputMesh::CellsContainerPointer 
                                                   InputMeshCellsContainerPointer;
  typedef typename TInputMesh::CellDataContainer   InputMeshCellDataContainer;
  typedef typename TInputMesh::CellDataContainerPointer 
                                                   InputMeshCellDataContainerPointer;
  typedef typename InputMeshType::PointsContainer::ConstIterator 
                                                   PointsContainerConstIterator;
  typedef typename InputMeshType::CellsContainer::ConstIterator
                                                   CellsContainerConstIterator;
  typedef typename InputMeshType::CellDataContainer::ConstIterator
                                                   CellDataContainerConstIterator;
  typedef typename TInputMesh::CellAutoPointer     InputMeshCellPointer;
  typedef typename TInputMesh::CellTraits::PointIdConstIterator 
                                                   InputMeshPointIdConstIterator;
  typedef typename TInputMesh::CellLinksContainerPointer
                                                   InputMeshCellLinksContainerPointer;
  typedef typename TInputMesh::PointCellLinksContainer
                                                   InputMeshCellLinksContainer;
  typedef typename TInputMesh::CellIdentifier      InputMeshCellIdentifier;

  /**
   * Different modes of operation. Use these to specify
   * how to extract the regions.
   */
  enum { PointSeededRegions = 0,
         CellSeededRegions = 1,
         SpecifiedRegions = 2,
         LargestRegion = 3,
         AllRegions = 4,
         ClosestPointRegion = 5 };
  
  /**
   * Methods specify mode of operation for the filter. Note that
   * some modes require additional information. For example, 
   * SetExtractionModeToClosestPointRegion() also requires that
   * a point be defined.
   */
  itkSetMacro( ExtractionMode, int );
  itkGetConstMacro( ExtractionMode, int );

  void SetExtractionModeToPointSeededRegions( void )
    {
    this->SetExtractionMode( Self::PointSeededRegions );
    }

  void SetExtractionModeToCellSeededRegions( void )
    {
    this->SetExtractionMode( Self::CellSeededRegions );
    }

  void SetExtractionModeToSpecifiedRegions( void )
    {
    this->SetExtractionMode( Self::SpecifiedRegions );
    }

  void SetExtractionModeToLargestRegion( void )
    {
    this->SetExtractionMode( Self::LargestRegion );
    }

  void SetExtractionModeToAllRegions( void )
    {
    this->SetExtractionMode( Self::AllRegions );
    }

  void SetExtractionModeToClosestPointRegion( void )
    {
    this->SetExtractionMode( Self::ClosestPointRegion );
    }

  /**
   * Initialize list of point ids/cell ids used to seed regions.
   */
  void InitializeSeedList( void )
    {
    this->Modified();
    m_SeedList.clear();
    }

  /**
   * Add a seed id (point or cell id). Note: ids are 0-offset.
   */
  void AddSeed( unsigned long id )
    {
    this->Modified();
    m_SeedList.push_back(id);
    }

  /**
   * Delete a seed id (point or cell id). Note: ids are 0-offset.
   */
  void DeleteSeed( unsigned long id );

  /**
   * Initialize list of region ids to extract.
   */
  void InitializeSpecifiedRegionList( void )
    {
    this->Modified();
    m_RegionList.clear();
    }

  /**
   * Add a region id to extract. Note: ids are 0-offset.
   */
  void AddSpecifiedRegion( unsigned long id )
    {
    this->Modified();
    m_RegionList.push_back(id);
    }

  /**
   * Delete a region id to extract. Note: ids are 0-offset.
   */
  void DeleteSpecifiedRegion( unsigned long id );

  /**
   * Use to specify x-y-z point coordinates when extracting the region 
   * closest to a specified point.
   */
  void SetClosestPoint( InputMeshPointType& p )
    {
    if( m_ClosestPoint != p )
      {
      m_ClosestPoint = p;
      this->Modified();
      }
    }

  InputMeshPointType& GetClosestPoint( InputMeshPointType& p )
    {
    return m_ClosestPoint;
    }

  /**
   * Obtain the number of connected regions.
   */
  unsigned long GetNumberOfExtractedRegions()
    {
    return m_RegionList.size();
    }

protected:

  ConnectedRegionsMeshFilter( void );
  virtual ~ConnectedRegionsMeshFilter( void ) {}

  void PrintSelf( std::ostream& os, Indent indent ) const;

  virtual void GenerateData( void );

  void PropagateConnectedWave( void );

private:  

  ConnectedRegionsMeshFilter( const Self& ); //purposely not implemented
  void operator=( const Self& ); //purposely not implemented

  int                         m_ExtractionMode;
  InputMeshPointType          m_ClosestPoint;
  std::vector<unsigned long>  m_SeedList;
  std::vector<unsigned long>  m_RegionList;
  std::vector<unsigned long>  m_RegionSizes;
  
  std::vector<long>           m_Visited;
  unsigned long               m_NumberOfCellsInRegion;
  unsigned long               m_RegionNumber;
  std::vector<unsigned long> *m_Wave;
  std::vector<unsigned long> *m_Wave2;
  
}; // class declaration

} // end namespace itk

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

#endif
