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

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

/**
   gmafEdgeValueIterator: It will calculate the value of the edge by 
   CC subdivision rule. It will traverse the vertical edge vertices first 
   and horizontal then.
   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: 
   e26 : return [(v1+v5+v3+v7) + 6*(v2+v6)]/16
   e37 : ...
   e59 : ...
   e6a :
   e7b :
   e8c :
*/
class gmafEdgeValueIterator {
// 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 mVMatrix; // only contains the needed entries
  VertexMatrix2D mHMatrix; // only contains the needed entries

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

//@}

// METHODS
/**@name Class Methods */
//@{
public:
  /**
     Constructor of gmafEdgeValueIterator
     it will traverse the 4 corners if they are valance 4
  */    
  gmafEdgeValueIterator(gmafQuad* q);
  /**
     Destructor of gmafEdgeValueIterator
  */
  virtual ~gmafEdgeValueIterator();
  
  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 gmafEdgeValueIterator::gmafEdgeValueIterator(gmafQuad* q) 
  : mQM(q->getQuadArray()), 
  mVMatrix(mQM(Range(0, mQM.rows()-2), Range(1, mQM.cols()-2))),
  mHMatrix(mQM(Range(1, mQM.rows()-2), Range(0, mQM.cols()-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 + mHW*mHH;
  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 3 is upper-right 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) ? mVW*mVH : mVW*mVH-1;
  mHEndPos = mpQuad->isCornerValid(gmafQuad::LOWER_RIGHT) ? mHW*mHH : mHW*mHH-1;
  mVCurPos = mVStartPos;
  mHCurPos = mHStartPos;
  for (int i = 0; i < mVStartPos; i++) ++mVCurItr; 
  for (int i = 0; i < mHStartPos; i++) ++mHCurItr;

  mV2H = false;
}

inline gmafEdgeValueIterator::~gmafEdgeValueIterator() {
}

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

inline void gmafEdgeValueIterator::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 gmafEdgeValueIterator::valid() const {
  return (mVCurPos < mVEndPos || mHCurPos < mHEndPos); // always check vertical first
}

inline void gmafEdgeValueIterator::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 const Vertex3D& gmafEdgeValueIterator::current() const {
  gmafEdgeValueIterator* me = (gmafEdgeValueIterator*)this;
  Vertex3D f, e; 
  if (mVCurPos < mVEndPos) {
    Position2D pos = mVCurItr.position();
    pos(1) += 1;
    Range r1(pos(0), pos(0)+1);
    Range r2(pos(1)-1, pos(1)+1);
    VertexMatrix2D vm = mQM(r1,r2);
    e = vm(0,1) + vm(1,1);
    f = vm(0,0) + vm(0,2) + vm(1,0) + vm(1,2);
  } else {
    Position2D pos = mHCurItr.position();
    pos(0) += 1;
    Range r1(pos(0)-1, pos(0)+1);
    Range r2(pos(1), pos(1)+1);
    VertexMatrix2D vm = mQM(r1,r2);
    e = vm(1,0) + vm(1,1);
    f = vm(0,0) + vm(0,1) + vm(2,0) + vm(2,1);
  }
  me->mCurValue = (e*6 + f) / 16;
  return mCurValue;
}

#endif gmafEdgeValueIterator_H

