/****************************************************************************
** GMAF - The Geometry Modeling Algorithms Framework
**
** Created : 04022000
**
** Copyright (C) 2000 by Le-Jeng Shiue.  All rights reserved.
**
****************************************************************************/
#ifndef gmafEdgeVertexIterator_H
#define gmafEdgeVertexIterator_H

#include "BlitzExtension/blitzConfig.h"
#include "gmafQuad.h"

/**
   It will traverse the vertical edge vertices first and horizontal then.
   Ex. QuadArray = 1 2 3 4 5  (Assume 1,5 are valid corner 
                   6 7 8 9 a
		   b c d e f
		   g h i j k
		   l m n o p
   This itr will traverse this quad in following order: 
   2 4 c e 6 8 a i   
*/
class gmafEdgeVertexIterator {
// ENUMS
public:

// VARIABLES
/**@name Class Variables */
//@{
protected:
  gmafQuad* mpQuad; // the quad which this itr to traverse
  VertexMatrix2D mQM; // contains whole quad matrix forn the input quad
  VertexMatrix2D mHMatrix; // only contains the needed horizontal entries
  VertexMatrix2D mVMatrix; // only contains the needed vertical entries

  VertexMatrix2D::iterator mVCurItr;
  VertexMatrix2D::iterator mHCurItr;
  int mSize; // total number of the fcaet vertices
  int mVW, mHW; // width of the quad
  int mVH, mHH; // height of the quad
  int mVCurPos, mHCurPos;
  int mVStartPos, mHStartPos;
  int mVEndPos, mHEndPos;
private:
  bool mV2H;
//@}

// METHODS
/**@name Class Methods */
//@{
public:
  /**
     Constructor of gmafEdgeVertexIterator
     it will traverse the 4 corners if they are valance 4
  */    
  gmafEdgeVertexIterator(gmafQuad* q);
  /**
     Destructor of gmafEdgeVertexIterator
  */
  virtual ~gmafEdgeVertexIterator();
  
  inline virtual int size() const;
  inline virtual void restart();
  inline virtual bool valid() const;
  inline virtual void next();
  inline virtual Vertex3D& current(); // return the facet value
  
protected:
  
private:
};

//---------------------------------------------------------
inline gmafEdgeVertexIterator::gmafEdgeVertexIterator(gmafQuad* q) 
  : mQM(q->getQuadArray()), 
  mVMatrix(mQM(Range(0, mQM.rows()-1, 2), Range(1, mQM.cols()-2, 2))),
  mHMatrix(mQM(Range(1, mQM.rows()-2, 2), Range(0, mQM.cols()-1, 2))),
  mVCurItr(mVMatrix.begin()), mHCurItr(mHMatrix.begin()) {
  
  mpQuad = q;
  
  mVH = mVMatrix.rows(); //1st dimension
  mVW = mVMatrix.cols(); //2rd dimension
  mHH = mHMatrix.rows(); //1st dimension
  mHW = mHMatrix.cols(); //2rd dimension
  
  mSize = mVH*mVW + mHH*mHW;
  for (int c = 0; c < 4; c++)
    if (!mpQuad->isCornerValid(c)) mSize-=2;

  mVStartPos = mpQuad->isCornerValid(gmafQuad::UPPER_LEFT) ? 0 : 1;
  mHStartPos = mpQuad->isCornerValid(gmafQuad::UPPER_LEFT) ? 0 : 1;
  // should check start pos again :: in case start position is another corner
  if (mVStartPos == 1 && mVW == 2) // corner is neighbor to corner
    mVStartPos = mpQuad->isCornerValid(gmafQuad::UPPER_RIGHT) ? 1 : 2;
    
  mVEndPos = mpQuad->isCornerValid(gmafQuad::LOWER_RIGHT) ? mVH*mVW : mVH*mVW-1;
  mHEndPos = mpQuad->isCornerValid(gmafQuad::LOWER_RIGHT) ? mHH*mHW : mHH*mHW-1;
  mVCurPos = mVStartPos;
  mHCurPos = mHStartPos;
  for (int i = 0; i < mVStartPos; i++) ++mVCurItr;
  for (int i = 0; i < mHStartPos; i++) ++mHCurItr;
  
  mV2H = false;
}

inline gmafEdgeVertexIterator::~gmafEdgeVertexIterator() {
}

inline int gmafEdgeVertexIterator::size() const {
  return mSize; // the number of the edge vertices
}

inline void gmafEdgeVertexIterator::restart() {
  mVCurItr = mVMatrix.begin();
  mHCurItr = mHMatrix.begin();
  mVCurPos = mVStartPos;
  mHCurPos = mHStartPos;
  for (int i = 0; i < mVStartPos; i++) ++mVCurItr;
  for (int i = 0; i < mHStartPos; i++) ++mHCurItr;
}

inline bool gmafEdgeVertexIterator::valid() const {
  return (mVCurPos < mVEndPos || mHCurPos < mHEndPos); // always check vertical first
}


inline void gmafEdgeVertexIterator::next() {
  if (mVCurPos < mVEndPos) {
    mVCurPos++;
    ++mVCurItr;
    if (mVCurPos >= mVEndPos) {
      mV2H = true; next();
      return;
    }
    Position2D pos = mVCurItr.position();
    while (((pos(0) == 0 && pos(1) == mVW-1) //skip the upper-right corner if it's invalid
	    && !mpQuad->isCornerValid(gmafQuad::UPPER_RIGHT)) || 
	   ((pos(0) == mVH-1 && pos(1) == 0) //skip the lower-left corner if it's invalid
	    && !mpQuad->isCornerValid(gmafQuad::LOWER_LEFT)) ) { 
      mVCurPos++;
      ++mVCurItr;;
      pos = mVCurItr.position();
    }
    if (mVCurPos >= mVEndPos) { mV2H = true; next(); }
  } else if (mHCurPos < mHEndPos) {
    if (mV2H) 
      mV2H = false;
    else {
      mHCurPos++;
      ++mHCurItr;
    }
    if (mHCurPos >= mHEndPos) return;
    Position2D pos = mHCurItr.position();
    while (((pos(0) == 0 && pos(1) == mHW-1) //skip the upper-right corner if it's invalid
	    && !mpQuad->isCornerValid(gmafQuad::UPPER_RIGHT)) || 
	   ((pos(0) == mHH-1 && pos(1) == 0) //skip the lower-left corner if it's invalid
	    && !mpQuad->isCornerValid(gmafQuad::LOWER_LEFT)) ) { 
      mHCurPos++;
      ++mHCurItr;;
      pos = mHCurItr.position();
    }
  }
}

inline Vertex3D& gmafEdgeVertexIterator::current() {
  if (mVCurPos < mVEndPos)
    return *mVCurItr;
  else 
    return *mHCurItr;
}

#endif gmafEdgeVertexIterator_H

