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

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

/**
   gmafVertexValueIterator: It will calculate the value of the vertex by 
   CC subdivision rule.
   Ex. QuadArray = 1 2 3 4 (Assume 1,4 are valid corners)
                   5 6 7 8
		   9 a b c
		   d e f g
   This itr will traverse this quad in following order: 
   v6 : return [(v1+v3+v9+vb) + 6*(v2+v5+v7+va) + 36*v6]/64 
   v7 : return [(v2+v4+va+vc) + 6*(v3+v6+v8+vb) + 36*v7]/64 
*/
class gmafVertexValueIterator {
// ENUMS
public:

// VARIABLES
/**@name Class Variables */
//@{
protected:
  gmafQuad* mpQuad; // the quad which this itr to traverse
  VertexMatrix2D mQM; // contains the whole matrix from the quad
  VertexMatrix2D mMatrix; // only contains the needed entries

  VertexMatrix2D::iterator mCurItr;
  int mSize; // total number of the fcaet vertices
  int mW; // width of the quad
  int mH; // height of the quad
  int mCurPos;
  int mStartPos;
  int mEndPos;
  Vertex3D mCurValue;
  
private:

//@}

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

//---------------------------------------------------------
inline gmafVertexValueIterator::gmafVertexValueIterator(gmafQuad* q) 
  : mQM(q->getQuadArray()), 
  mMatrix(mQM(Range(1, mQM.rows()-2), Range(1, mQM.cols()-2))),
  mCurItr(mMatrix.begin()) {
  
  mpQuad = q;
  
  mH = mMatrix.rows(); //1st dimension
  mW = mMatrix.cols(); //2rd dimension
  
  mSize = mH*mW;
  for (int c = 0; c < 4; c++)
    if (!mpQuad->isCornerValid(c)) mSize--;

  mStartPos = mpQuad->isCornerValid(gmafQuad::UPPER_LEFT) ? 0 : 1;
  if (mStartPos == 1 && mW == 2) { //corner is neighbor to corner
    mStartPos = mpQuad->isCornerValid(gmafQuad::UPPER_RIGHT) ? 1 : 2;
    if (mStartPos == 2) { //corner is neighbor to corner
      mStartPos = mpQuad->isCornerValid(gmafQuad::LOWER_LEFT) ? 2 : 3;
    }
  }
  mEndPos = mpQuad->isCornerValid(gmafQuad::LOWER_RIGHT) ? mW*mH : mW*mH-1;
  mCurPos = mStartPos;

  for (int i = 0; i < mStartPos; i++) ++mCurItr;
}

inline gmafVertexValueIterator::~gmafVertexValueIterator() {
}

inline int gmafVertexValueIterator::size() const {
  return mSize; // the number of the facets
}

inline void gmafVertexValueIterator::restart() {
  mCurPos = mStartPos;
  mCurItr = mMatrix.begin();
  for (int i = 0; i < mStartPos; i++) ++mCurItr;
}

inline bool gmafVertexValueIterator::valid() const {
  return (mCurPos < mEndPos);
}

inline void gmafVertexValueIterator::next() {
  if (mCurPos < mEndPos) {
    mCurPos++;
    ++mCurItr;
    if (mCurPos >= mEndPos) return;
    Position2D pos = mCurItr.position();
    while ((pos(0) == 0 && pos(1) == mW-1 && !mpQuad->isCornerValid(gmafQuad::UPPER_RIGHT) ) || //skip the upper-right corner if it's invalid
	   (pos(0) == mH-1 && pos(1) == 0 && !mpQuad->isCornerValid(gmafQuad::LOWER_LEFT) ) ) { //skip the lower-left corner if it's invalid
      mCurPos++;
      ++mCurItr;
      pos = mCurItr.position();
    }
  }
}

inline const Vertex3D& gmafVertexValueIterator::current() const {
  gmafVertexValueIterator* me = (gmafVertexValueIterator*)this;
  Position2D pos = mCurItr.position() + 1;
  Range r1(pos(0)-1, pos(0)+1);
  Range r2(pos(1)-1, pos(1)+1);
  VertexMatrix2D vm = mQM(r1,r2);
  Vertex3D a, b, r; 
  a = vm(1,1); // vertex-vertex
  b = vm(0,1) + vm(1,0) + vm(1,2) + vm(2,1); // edge-vertex
  r = vm(0,0) + vm(0,2) + vm(2,0) + vm(2,2); // facet-vertex

  me->mCurValue = (a*36 + b*6 + r) / 64;

  return mCurValue;
}

#endif gmafVertexValueIterator_H

