
#include <print.h>


#include <d4tess.h>
#include <d4fan.h>






d4fan::d4fan( d4tess & _tess )
  : tess(_tess)
{
}


void d4fan::addspike()
{
  uint index = tess.vi.size();
  tess.vi.push_back( d4tri() );
  d4tri & ti(tess.vi[index]);
  d4tri const & x(tess.cpsimplex());

  virtualtetrahedron const & vs(tess.vs);

  cp = tess.cpsimplexface();

  ti.pi[0] = x.pi[ vs.v[0] ];
  ti.pi[1] = x.pi[ vs.v[2] ];
  ti.pi[2] = x.pi[ vs.v[1] ];
  ti.pi[3] = w;
  ti.ni[3] = cp.id;

  stot[cp] = index;
}


bool const d4fan::link(uint & ktni, uintc kt)
{
  cp = tess.cpsimplexface();

  // Is the cp on the boundary or already processed?
  if (dead.find(cp)!=dead.end())
    return false;

  // Does the tetrahedron already exist?
  if (stot.find(cp)==stot.end())
  {
  
    if (tess.surfaceviewable(w)==false)
    {
      dead.insert(cp);
      return false;
    }

    addspike();
  }

  // This cp must be processed at a later date.
  process.push_back(cp);


  // Get the point on the surface base opposite the central triangle.
  uint p2 = tess.vi[cp.id].pi[ tess.vs.v[2] ];

  uintc z = stot[cp];

  d4tri & x(tess.vi[z]);
  x.niFrompiInverse(p2) = kt;
  ktni = z;
   
  return true;
}


void d4fan::eval(uintc _w )
{
  w = _w;
  dead.clear();
  stot.clear();
  process.clear();

  process.push_back(cp = tess.cpsimplexface());

  // <TODO> Test if cp is viewable to w.

//  MessageGlobal mg;

//  mg() << *this << endl << endl;
//  mg() << tess << endl;

  addspike();

//  mg() << *this << endl << endl;
//  mg() << tess << endl;


  // k is the current surface face being processed.
  simplexface k;

  // kt is an index into the central tetrehedron K.
  uint kt;

  uint p[3];


  uint sz = process.size();
  for ( ; sz!=0; sz = process.size() )
  {
    k = process[ sz-1 ];   
    process.pop_back();
    dead.insert(k);

//    mg() << SHOW(k) << endl;

    // The current tetrahedron  must have vs's base viewable to w.
    tess.cp = k.id;
    tess.vs.set( k.face );
    assert(tess.surfaceviewable(w));

//    mg() << SHOW(tess.cp) << " " << SHOW(tess.vs) << endl;

    for (uint i=0; i<3; ++i)
      p[i] = tess.vi[tess.cp].pi[ tess.vs.v[i] ];


//    mg() << "p= " << p[0] << " " << p[1] << " " << p[2] << endl;

    kt = stot[k];
    d4tri & K(tess.vi[kt]);

//    mg() << SHOW(kt) << "  " << SHOW(K) << endl;

    tess.surfacedown();
    link(K.niFrompiInverse(p[2]),kt);

    tess.surfacedown();
    tess.surfaceleft();
    link(K.niFrompiInverse(p[1]),kt);

    tess.surfacedown();
    tess.surfaceleft();
    link(K.niFrompiInverse(p[0]),kt);
  }


  // Iterate over surface connecting the surface with
  //   the fan.

  simplexface sf;

  for (map<simplexface,uint>::iterator i=stot.begin();
    i!=stot.end(); ++i)
  {
    sf = i->first;    
    tess.cp = sf.id;
    tess.vs.set(sf.face);
    tess.vi[ tess.cp ].ni[ tess.vs.v[3] ] = i->second;
  }

  tess.debugcheck();

  // Apply minimization to each new tetrahedron with
  //   an already existing tetrahedron on the old surface.
  for (map<simplexface,uint>::iterator i=stot.begin();
    i!=stot.end(); ++i)
    tess.minimizer->eval( (i->first).id, i->second );

}


ostream & operator << (ostream & os, d4fan const & x)
{
  return x.print(os);
}


ostream & d4fan::print(ostream & os) const
{
  os << "w=" << w << endl;
//  os << "surf" << endl << " ";
//  for( set<simplexface>::const_iterator i = surf.begin();
//    i!=surf.end(); ++i)
//    os << *i << ":" << tess.vi[(*i).id] << endl;
//  os << endl;

  os << "dead" << endl << " ";
  for( set<simplexface>::const_iterator i = dead.begin();
    i!=dead.end(); ++i)
    os << *i << " ";
  os << endl;

  os << "stot" << endl << " ";
  for( map<simplexface,uint>::const_iterator i = stot.begin();
    i!=stot.end(); ++i)
    os << i->first << "->" << i->second << ": " << tess.vi[i->second] << endl;
  os << endl;

  os << "process" << endl << " ";
  for ( uint i=0; i<process.size(); ++i)
    os << process[i] << " ";
  os << endl;

  return os;
} 










