/****************************************************************************
** GMAF - The Geometry Modeling Algorithms Framework
**
** Created : 04012000
**
** Copyright (C) 2000 by Le-Jeng Shiue.  All rights reserved.
**
****************************************************************************/
#include <assert.h>

#include <vector>

#include "gmafQuadVertex.h"
#include "gmafQuad.h"

#include "Algorithm/PCCM/gmafPCCMQuad.h"

#include "BlitzExtension/gmafMatrixCirculator.h"

const Vertex3D& gmafQuadVertex::
sumAlphaVertices(vector<gmafQuad*>& qlist, int l) {
  QuadNeighbor& v = mNeighborList.front();
  return (qlist[v.quadidx])->getAlphaCorner(v.corner, l);
}

const Vertex3D& gmafQuadVertex::
sumGammaVertices(vector<gmafQuad*>& qlist, int l) {
  mTmpVertex = 0;
  for (vector<QuadNeighbor>::iterator itr = mNeighborList.begin();
       itr != mNeighborList.end(); itr++) {
    mTmpVertex += (qlist[itr->quadidx])->getGammaCorner(itr->corner, l);
  }
  return mTmpVertex;
}

const Vertex3D& gmafQuadVertex::
sumBetaVertices(vector<gmafQuad*>& qlist, int l) {
  mTmpVertex = 0;
  for (vector<QuadNeighbor>::iterator itr = mNeighborList.begin();
       itr != mNeighborList.end(); itr++) {
    mTmpVertex += (qlist[itr->quadidx])->getBetaCorner(itr->corner, l);
  }
  return mTmpVertex;
}

void gmafQuadVertex::
writeBackAlphaVertex(Vertex3D& v, vector<gmafQuad*>& qlist, int l) {
  for (vector<QuadNeighbor>::iterator itr = mNeighborList.begin();
       itr != mNeighborList.end(); itr++) {
    (qlist[itr->quadidx])->getAlphaCorner(itr->corner, l) = v;
  }  
}

void gmafQuadVertex::
synchronizeBetaVertex(vector<gmafQuad*>& qlist, int l) {
  int s = mNeighborList.size();
  for (int i = 0; i < s; i++) {
    qlist[mNeighborList[i].quadidx]->get4thBetaCorner(mNeighborList[i].corner, l)
      = qlist[mNeighborList[(i+2)%s].quadidx]->
          get2ndBetaCorner(mNeighborList[(i+2)%s].corner, l);
    qlist[mNeighborList[i].quadidx]->get1stBetaCorner(mNeighborList[i].corner, l)
      = qlist[mNeighborList[(i+s-2)%s].quadidx]->
          get3rdBetaCorner(mNeighborList[(i+s-2)%s].corner, l);
  }
}

void gmafQuadVertex::
writeBackPCCMAlphaVertex(Vertex3D& v, vector<gmafPCCMQuad*>& pccmqlist) {
  for (vector<QuadNeighbor>::iterator itr = mNeighborList.begin();
       itr != mNeighborList.end(); itr++) {
    (pccmqlist[itr->quadidx])->getAlphaCorner(itr->corner) = v;
  }  
}


void gmafQuadVertex::getPCCMQij(Vertex3D& q00,
				VertexMatrix1D& q10, // base = 1 !! 
				VertexMatrix1D& q20,
				VertexMatrix1D& q40,
				vector<gmafPCCMQuad*>& pccmqlist) {
  int r = mNeighborList.size();
  for (vector<QuadNeighbor>::iterator itr = mNeighborList.begin();
       itr != mNeighborList.end(); itr++, r--) { // force it traverse in CCW
    VertexMatrix2D cn = (pccmqlist[itr->quadidx])->getPCCMControlNet();
    gmafMatrixCirculator<VertexMatrix2D> _q00(cn, 0, 0), _q10(cn, 1, 0),
                                         _q20(cn, 2, 0), _q40(cn, 3, 0);

    if (r == 1) { // q00 are all the same -- so do it only once
      for (int i = 0; i < itr->corner; i++) _q00.next();
      q00 = _q00.current();
    }

    for (int i = 0; i < itr->corner; i++) {
      _q10.next(); _q20.next(); _q40.next();
    }
    q10(r) = _q10.current(); // save it in CCW
    q20(r) = _q20.current(); // save it in CCW
    q40(r) = _q40.current(); // save it in CCW
  }
}

void gmafQuadVertex::setPCCMQij(const VertexMatrix1D& q10, // base = 1 !
				const VertexMatrix1D& q20,
				const VertexMatrix1D& q11,
				const VertexMatrix1D& dq20,
				vector<gmafPCCMQuad*>& pccmqlist) {
  int r = mNeighborList.size();
  int valance = mNeighborList.size();
  for (vector<QuadNeighbor>::iterator itr = mNeighborList.begin();
       itr != mNeighborList.end(); itr++, r--) { // force it traverse in CCW
    VertexMatrix2D& cn = (pccmqlist[itr->quadidx])->getPCCMControlNet();
    gmafMatrixCirculator<VertexMatrix2D> _q11(cn, 1, 1),
                                         _q10(cn, 1, 0), _q20(cn, 2, 0),
                                         _q01(cn, 0, 1), _q02(cn, 0, 2),
                                         _q21(cn, 2, 1), _q12(cn, 1, 2);

    for (int i = 0; i < itr->corner; i++) {
      _q11.next(); 
      _q10.next(); _q20.next();
      _q01.next(); _q02.next();
      _q21.next(); _q12.next();
    }
    _q11.current() = q11(r); // save it in CCW
    _q10.current() = q10(r); // save it in CCW
    _q20.current() = q20(r); // save it in CCW
    _q21.current() += dq20(r); // save it in CCW
    
    int rv = r == valance ? 1 : r+1;
    _q12.current() += dq20(rv); // save it in CCW
    _q01.current() = q10(rv); // save it in CCW
    _q02.current() = q20(rv); // save it in CCW
  }  
}

void gmafQuadVertex::setPCCMQij(const VertexMatrix1D& q10, // base = 1 !
				       const VertexMatrix1D& q20,
				       const VertexMatrix1D& q11,
				       const VertexMatrix1D& dq20,
				       const VertexMatrix1D& dq40,
				       vector<gmafPCCMQuad*>& pccmqlist) {
  int r = mNeighborList.size();
  int valance = mNeighborList.size();
  for (vector<QuadNeighbor>::iterator itr = mNeighborList.begin();
       itr != mNeighborList.end(); itr++, r--) { // force it traverse in CCW
    VertexMatrix2D& cn = (pccmqlist[itr->quadidx])->getPCCMControlNet();
    gmafMatrixCirculator<VertexMatrix2D> _q11(cn, 1, 1),
                                         _q10(cn, 1, 0), _q20(cn, 2, 0),
                                         _q01(cn, 0, 1), _q02(cn, 0, 2),
                                         _q21(cn, 2, 1), _q12(cn, 1, 2),
                                         _q40(cn, 3, 0), _q04(cn, 0, 3),
                                         _q41(cn, 3, 1), _q14(cn, 1, 3);

    for (int i = 0; i < itr->corner; i++) {
      _q11.next(); 
      _q10.next(); _q20.next();
      _q01.next(); _q02.next();
      _q21.next(); _q12.next();
      _q40.next(); _q04.next();
      _q41.next(); _q14.next();
    }
    _q11.current() = q11(r); // save it in CCW
    _q10.current() = q10(r); // save it in CCW
    _q20.current() = q20(r); // save it in CCW
    _q21.current() += dq20(r); // save it in CCW
    _q40.current() -= dq40(r);
    _q41.current() -= dq40(r);
    _q14.current() += dq40(r); 
    
    int rv = r == valance ? 1 : r+1;
    _q01.current() = q10(rv); // save it in CCW
    _q02.current() = q20(rv); // save it in CCW
    _q12.current() += dq20(rv); // save it in CCW
    _q04.current() -= dq40(rv); 
  }  
}

void gmafQuadVertex::getVertices(VertexMatrix1D& q11,
				 VertexMatrix1D& q21, // base = 1 !! 
				 VertexMatrix1D& q22,
				 vector<gmafQuad*>& qlist,
				 int layer /*= -1*/) {
  Vertex3D _q11;
  getVertices(_q11, q21, q22, qlist, layer);
  q11 = _q11;
}

void gmafQuadVertex::getVertices(Vertex3D& q11,
				 VertexMatrix1D& q21, // base = 1 !! 
				 VertexMatrix1D& q22,
				 vector<gmafQuad*>& qlist,
				 int layer /*= -1*/) {
  int r = mNeighborList.size();
  for (vector<QuadNeighbor>::iterator itr = mNeighborList.begin();
       itr != mNeighborList.end(); itr++, r--) { // force it traverse in CCW
    if (layer < 0) layer = (qlist[itr->quadidx])->getCurLayerIdx();
    VertexMatrix2D cn = (qlist[itr->quadidx])->getQuadArray(layer);

    gmafMatrixCirculator<VertexMatrix2D> _q11(cn, 1, 1),
                                         _q21(cn, 2, 1), _q22(cn, 2, 2);

    if (r == 1) { // q00 are all the same -- so do it only once
      for (int i = 0; i < itr->corner; i++) _q11.next();
      q11 = _q11.current();
    }

    for (int i = 0; i < itr->corner; i++) {
      _q21.next(); _q22.next();
    }
    q21(r) = _q21.current(); // save it in CCW
    q22(r) = _q22.current(); // save it in CCW
  }
}

void gmafQuadVertex::setVertices(const Vertex3D& q11,
				 const VertexMatrix1D& q21, // base = 1 !
				 const VertexMatrix1D& q22,
				 vector<gmafQuad*>& qlist,
				 int layer /*= -1*/) {
  int r = mNeighborList.size();
  int valance = r;
  for (vector<QuadNeighbor>::iterator itr = mNeighborList.begin();
       itr != mNeighborList.end(); itr++, r--) { // force it traverse in CCW
    if (layer < 0) layer = (qlist[itr->quadidx])->getCurLayerIdx();
    VertexMatrix2D& cn = (qlist[itr->quadidx])->getQuadArray(layer);

    gmafMatrixCirculator<VertexMatrix2D> _q11(cn, 1, 1), _q22(cn, 2, 2),
                                         _q21(cn, 2, 1), _q12(cn, 1, 2),
                                         _q01(cn, 0, 1), _q10(cn, 1, 0),
                                         _q02(cn, 0, 2), _q20(cn, 2, 0),
                                         _q00(cn, 0, 0);

    for (int i = 0; i < itr->corner; i++) {
      _q11.next(); _q22.next(); 
      _q21.next(); _q12.next();
      _q01.next(); _q10.next();
      _q02.next(); _q20.next();
      _q00.next();
    }
    _q11.current() = q11;
    _q22.current() = q22(r); // save it in CCW
    _q21.current() = q21(r); // save it in CCW
    
    int _12, _01, _10, _02, _20, _00;
    // _12,_02 -> +1 ; _01 -> +2 ; _20,_10 -> -1 ; _00 -> -2
    if (valance >= 4) {
      _12 = _02 = r+1; _01 = r+2; _20 = _10 = r-1; _00= r-2; 
      if (r == valance) { _12 = _02 = 1; _01 = 2; }
      else if (r+1 == valance) { _12 = _02 = r+1; _01 = 1; }
      if (r == 1) { _20 = _10 = valance; _00= valance-1; }
      else if (r == 2) { _20 = _10 = 1; _00= valance; }
      if (valance == 4) _q00.current() = q22(_00); 
    } else {
      if (r == 1) { _12 = _02 = 2; _01 = _20 = _10 = 3; }
      else if (r == 2) { _12 = _02 = 3; _01 = _20 = _10 = 1; }
      else if (r == 3) { _12 = _02 = 1; _01 = _20 = _10 = 2; }
      else assert(0);
    }
    _q12.current() = q21(_12); 
    _q01.current() = q21(_01); 
    _q10.current() = q21(_10); 
    _q02.current() = q22(_02); 
    _q20.current() = q22(_20); 
  }  
}

void gmafQuadVertex::getBlendRatios(Matrix1D& brout, // CCW
				    Matrix1D& brin, // CCW
				    vector<gmafQuad*>& qlist){ 
  int r = mNeighborList.size();
  brout.resize(r+1);
  brin.resize(r+1);
  for (vector<QuadNeighbor>::iterator itr = mNeighborList.begin();
       itr != mNeighborList.end(); itr++, r--) { // force it traverse in CCW
    int i = itr->quadidx;
    int c = itr->corner;
    brout(r) = (qlist[i])->getBlendRatio(c, (c+1)%4);
    brin(r)  = (qlist[i])->getBlendRatio((c+1)%4, c);
  }
}
