/* ***************************************************************** 
    MESQUITE -- The Mesh Quality Improvement Toolkit

    Copyright 2010 Sandia National Laboratories.  Developed at the
    University of Wisconsin--Madison under SNL contract number
    624796.  The U.S. Government and the University of Wisconsin
    retain certain rights to this software.

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License 
    (lgpl.txt) along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA

    (2010) kraftche@cae.wisc.edu    

  ***************************************************************** */


/** \file EdgeIterator.hpp
 *  \brief 
 *  \author Jason Kraftcheck 
 */

#ifndef MSQ_EDGE_ITERATOR_HPP
#define MSQ_EDGE_ITERATOR_HPP

#include "Mesquite.hpp"
#include "Mesquite_PatchData.hpp"
#include "Mesquite_MsqError.hpp"

namespace MESQUITE_NS {

/**\brief Iterate over all edges in a patch*/
class EdgeIterator
{
public: 
  EdgeIterator( PatchData* patch, MsqError& err );
  inline bool is_at_end() const;
  inline const Vector3D& start() const;
  inline const Vector3D& end() const;
  inline const Vector3D* mid() const;
  inline void step( MsqError& err );

  struct Edge {
    Edge( size_t vtx, size_t mid ) : otherVertex(vtx), midVertex(mid) {}
    Edge() {}
    size_t otherVertex;
    size_t midVertex;
  };
private:
  PatchData* patchPtr;
  size_t vertIdx;
  std::vector<Edge> adjList;
  std::vector<Edge>::iterator adjIter;
  void get_adjacent_vertices( MsqError& err );
};


inline bool operator<( const EdgeIterator::Edge& e1, const EdgeIterator::Edge& e2 )
  { return e1.otherVertex < e2.otherVertex || 
          (e1.otherVertex == e2.otherVertex && e1.midVertex < e2.midVertex); }

inline bool operator==( const EdgeIterator::Edge& e1, const EdgeIterator::Edge& e2 )
  { return e1.otherVertex == e2.otherVertex && e1.midVertex == e2.midVertex; }

bool EdgeIterator::is_at_end() const
{
  return vertIdx >= patchPtr->num_nodes();
}

const Vector3D& EdgeIterator::start() const
  { return patchPtr->vertex_by_index( vertIdx ); }

const Vector3D& EdgeIterator::end() const
  { return patchPtr->vertex_by_index( adjIter->otherVertex ); }

const Vector3D* EdgeIterator::mid() const
  { return adjIter->midVertex < patchPtr->num_nodes() ? 
           &patchPtr->vertex_by_index( adjIter->midVertex ) : 0; }

void EdgeIterator::step( MsqError& err )
{
  if (adjIter != adjList.end())
  {
    ++adjIter;
  }
  
  while (adjIter == adjList.end() && ++vertIdx < patchPtr->num_nodes())
  {
    get_adjacent_vertices( err );  MSQ_ERRRTN(err);
  }
}


} // namespace MESQUITE_NS

#endif
