/*=========================================================================
 *
 *  Copyright Insight Software Consortium
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0.txt
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *=========================================================================*/
#ifndef __itkQuadEdgeMeshFrontIterator_h
#define __itkQuadEdgeMeshFrontIterator_h

#include "itkMapContainer.h"

// -------------------------------------------------------------------------
#define itkQEDefineFrontIteratorMethodsMacro(MeshTypeArg)                       \
  /* Dual definition placed before others because of .NET that cannot */        \
  /* cope with definition of FrontIterator (that further hides the    */        \
  /* definition of the template).                                      */        \
  typedef typename MeshTypeArg::QEDual   QEDualType;                            \
  typedef typename MeshTypeArg::QEPrimal QEPrimalType;                          \
  typedef QuadEdgeMeshFrontIterator< MeshTypeArg,                               \
                                     QEDualType > FrontDualIterator;            \
  typedef QuadEdgeMeshConstFrontIterator< MeshTypeArg,                          \
                                          QEDualType >                          \
  ConstFrontDualIterator;                                                       \
  typedef QuadEdgeMeshFrontIterator< MeshTypeArg,                               \
                                     QEPrimalType >   FrontIterator;            \
  typedef QuadEdgeMeshConstFrontIterator< MeshTypeArg,                          \
                                          QEPrimalType >                        \
  ConstFrontIterator;                                                           \
                                                                                \
  virtual FrontIterator BeginFront(QEPrimalType * seed = (QEPrimalType *)0)     \
    {                                                                           \
    return ( FrontIterator(this, true, seed) );                                 \
    }                                                                           \
                                                                                \
  virtual ConstFrontIterator BeginFront(QEPrimalType * seed) const              \
        { return ( ConstFrontIterator(this, true, seed) ); }                    \
                                                                                \
  virtual FrontIterator EndFront()                                              \
    {                                                                           \
    return ( FrontIterator(this, false) );                                      \
    }                                                                           \
                                                                                \
  virtual ConstFrontIterator EndFront() const                                   \
        { return ( ConstFrontIterator(this, false) ); }                         \
                                                                                \
  virtual FrontDualIterator BeginDualFront(QEDualType * seed = (QEDualType *)0) \
    {                                                                           \
    return ( FrontDualIterator(this, true, seed) );                             \
    }                                                                           \
                                                                                \
  virtual ConstFrontDualIterator BeginDualFront(QEDualType * seed) const        \
        { return ( ConstFrontDualIterator(this, true, seed) ); }                \
                                                                                \
  virtual FrontDualIterator EndDualFront()                                      \
    {                                                                           \
    return ( FrontDualIterator(this, false) );                                  \
    }                                                                           \
                                                                                \
  virtual ConstFrontDualIterator EndDualFront() const                           \
        { return ( ConstFrontDualIterator(this, false) ); }

namespace itk
{
/**
 * \class QuadEdgeMeshFrontBaseIterator
 *
 * \brief Front iterator on Mesh class
 *
 * Like topological and geometrical operators, it iterates on edges.
 * Unlike them, this iterator is not local, nor cyclic. Starting from a
 * given seed, it will create a front that propagates on the surface.
 * Depending on the weight associated which each edge, and on the type of the
 * seed (primal or dual) it can be used for frint propagation algorithm,
 * distance tree computation or other Djikstra like algorithms.
 * \ingroup ITKQuadEdgeMesh
 */
template< typename TMesh, typename TQE >
class QuadEdgeMeshFrontBaseIterator
{
public:
  // Hierarchy typedefs & values.
  typedef QuadEdgeMeshFrontBaseIterator Self;

  // Template types
  typedef TMesh MeshType;
  typedef TQE   QEType;

protected:
  // Mesh types
  typedef typename MeshType::CoordRepType CoordRepType;
  // QE types
  typedef typename QEType::OriginRefType QEOriginType;

  /**
   * \class FrontAtom
   *
   * \brief Atomic information associated to each edge of the front.
   *
   * Note that when sorting this list, the sorting criteria is the
   * Cost attribute.
   * \ingroup ITKQuadEdgeMesh
   */
  class FrontAtom
  {
public:
    FrontAtom(QEType *e = (QEType *)0, const CoordRepType c = 0):
      m_Edge(e), m_Cost(c)
    {}
    virtual ~FrontAtom() {}
    FrontAtom & operator=(const FrontAtom & r)
    { m_Edge = r.m_Edge; m_Cost = r.m_Cost; return *this; }
    bool operator==(const FrontAtom & r) const
    { return ( m_Edge == r.m_Edge ); }
    bool operator!=(const FrontAtom & r) const
    { return ( m_Edge != r.m_Edge ); }
    bool operator<(const FrontAtom & r) const
    { return ( m_Cost < r.m_Cost ); }

public:
    QEType *     m_Edge;
    CoordRepType m_Cost;
  };

  /** The active front is simply a list of edges that can be sorted on
   *  the sort attribute FrontAtom
   */
  typedef std::list< FrontAtom >       FrontType;
  typedef typename FrontType::iterator FrontTypeIterator;
  typedef FrontType *                  FrontTypePointer;

  /** Whether an Origin (i.e. a vertex or a face since we either deal with
   *  primal or dual edges) was already visited.
   */
  typedef MapContainer< QEOriginType, bool >       IsVisitedContainerType;
  typedef typename IsVisitedContainerType::Pointer IsVisitedPointerType;

public:
  /** Object creation methods. */
  QuadEdgeMeshFrontBaseIterator(MeshType *mesh  = (MeshType *)0,
                                bool start = true,
                                QEType *seed  = (QEType *)0);
  virtual ~QuadEdgeMeshFrontBaseIterator();

  Self & operator=(const Self & r)
  {
    if(this != &r)
      {
      m_Mesh  = r.m_Mesh;
      m_Start = r.m_Start;
      m_Seed  = r.m_Seed;
      m_Front = r.m_Front;
      m_IsPointVisited = r.m_IsPointVisited;
      m_CurrentEdge = r.m_CurrentEdge;
      }
    return ( *this );
  }

  // Iteration methods.
  bool operator==(Self & r)
  {
    return ( m_Start == r.m_Start );
  }

  bool operator==(const Self & r) const
  {
    return ( m_Start == r.m_Start );
  }

  bool operator!=(Self & r)
  {
    return ( !( this->operator==(r) ) );
  }

  bool operator!=(const Self & r) const
  {
    return ( !( this->operator==(r) ) );
  }

  Self & operator++();

  Self & operator++(int) { return ( this->operator++() ); }

  MeshType * GetMesh() const { return this->m_Mesh; }

protected:
  /** Find a default seed by taking any edge (with proper type) in
   *  the current mesh.
   */
  QEType * FindDefaultSeed();

  /** The default cost associated to an edge is simply 1. This corresponds
   *  to the "topological metric" i.e. all edges have unit length.
   */
  virtual CoordRepType GetCost(QEType *edge){ (void)edge; return ( 1 ); }

protected:
  /** Mesh on which we propagate the front */
  MeshType *m_Mesh;
  /** Initial seed of the front */
  QEType *m_Seed;
  /** Whether the iterator is active */
  bool m_Start;
  /** The active front */
  FrontTypePointer m_Front;
  /** The already visited points */
  IsVisitedPointerType m_IsPointVisited;
  /** The current edge at this stage of iteration */
  QEType *m_CurrentEdge;
};

/**
 * \class QuadEdgeMeshFrontIterator
 *
 * \brief Non const quad edge front iterator.
 * \ingroup ITKQuadEdgeMesh
 */
template< typename TMesh, typename TQE >
class QuadEdgeMeshFrontIterator:
  public QuadEdgeMeshFrontBaseIterator< TMesh, TQE  >
{
public:
  /** Hierarchy typedefs and values. */
  typedef QuadEdgeMeshFrontIterator                   Self;
  typedef QuadEdgeMeshFrontBaseIterator< TMesh, TQE > Superclass;
  typedef typename Superclass::MeshType               MeshType;
  typedef typename Superclass::QEType                 QEType;

public:
  /** Object creation methods. */
  QuadEdgeMeshFrontIterator(MeshType *mesh = (MeshType *)0,
                            bool start = true,
                            QEType *seed  = (QEType *)0):
    Superclass(mesh, start, seed) {}
  virtual ~QuadEdgeMeshFrontIterator() {}
  QEType * Value() { return ( this->m_CurrentEdge ); }
};

/**
 * \class QuadEdgeMeshConstFrontIterator
 *
 * \brief Const quad edge mesh front iterator.
 * \ingroup ITKQuadEdgeMesh
 */
template< typename TMesh, typename TQE = typename TMesh::QEType >
class QuadEdgeMeshConstFrontIterator:
  public QuadEdgeMeshFrontBaseIterator< TMesh, TQE >
{
public:
  /** Hierarchy typedefs & values. */
  typedef QuadEdgeMeshConstFrontIterator                Self;
  typedef QuadEdgeMeshFrontBaseIterator< TMesh, TQE >   Superclass;
  typedef typename Superclass::QEType                   QEType;
  typedef typename Superclass::MeshType                 MeshType;
  typedef QuadEdgeMeshFrontIterator< MeshType, QEType > NoConstType;

public:
  /** Object creation methods. */
  QuadEdgeMeshConstFrontIterator(const MeshType *mesh = (MeshType *)0,
                                 bool start = true,
                                 QEType *seed  = (QEType *)0)
  {
    (void)mesh;
    (void)start;
    (void)seed;
  }

  /** \todo do we need here a    : Superclass( mesh, start, seed ) { } */
  virtual ~QuadEdgeMeshConstFrontIterator() {}
  Self & operator=(const NoConstType & r)
  {
    this->m_Mesh  = r.GetMesh();
    return ( *this );
  }

  const QEType * Value() const { return ( this->m_CurrentEdge ); }
};
}

#include "itkQuadEdgeMeshFrontIterator.hxx"

#endif
