////////////////////////////////////////////////////////////////////////////////
// 
// TriangFlips.cc
//
//    produced: 27/05/98 jr
// 
////////////////////////////////////////////////////////////////////////////////
#include <iostream>

#include <set>

#include "Flip.hh"
#include "TriangFlips.hh"

namespace topcom {

  // internal algorithms:

  void TriangFlips::_remove_destroyed_flips(const TriangNode& tn, 
					    const Flip& flip) {
    static MarkedFlips old_flips;
    old_flips = _flips;
    for (MarkedFlips::const_iterator iter = old_flips.begin(); iter != old_flips.end(); ++iter) {
#ifdef TOPCOM_FLIPS
      const FlipRep fliprep(iter->key());
#else
      const FlipRep fliprep((*iter).first);
#endif
      const Flip old_flip = Flip(tn, fliprep);
      if (!(old_flip.first * flip.first).empty()) {
	_flips.erase(fliprep);
      }
    }
  }

  void TriangFlips::_add_new_flips(const Chirotope&            chiro,
				   const Incidences*           inctableptr,      
				   const TriangNode&           tn,
				   const SimplicialComplex&    restriction,
				   const symmetryptr_datapair& tn_symmetryptrs,
				   const bool                  forbid_vertex_removal,
				   const bool                  forbid_card_change) {

    std::set<dependent_set_type> dependent_sets;
    std::set<Simplex>            done_set;

    MessageStreams::debug() << "adding flips in " << tn << " restricted to " << restriction << " ..." << std::endl;
    const Simplex tn_support(tn.support());
    const Simplex groundset(Permutation(_no, _no));
    const Simplex missing_vertices(groundset - tn_support);

    // any new flip in tn must contain one of the flipped-in simplices:
    size_type countdown(restriction.card());
    for (SimplicialComplex::const_iterator iter1 = restriction.begin();
	 iter1 != restriction.end();
	 ++iter1) {
      --countdown;
      const Simplex& simp1(*iter1);
      MessageStreams::debug() << "processing flips containing " << simp1 << " ..." << std::endl;
#ifdef TOPCOM_CONTAINERS
      if (done_set.contains(simp1, _rank)) {
#else
	if (done_set.find(simp1) != done_set.end()) {
#endif
	  // processed already:
	  continue;
#ifdef TOPCOM_CONTAINERS
	}
#else
      }
#endif
#ifdef TOPCOM_CONTAINERS
      done_set.insert(simp1, _rank);
#else
      done_set.insert(simp1);
#endif
      for (symmetryptr_iterdata::const_iterator sym_iter = tn_symmetryptrs.first.begin();
	   sym_iter != tn_symmetryptrs.first.end();
	   ++sym_iter) {
	const Symmetry& g(**sym_iter);
#ifdef TOPCOM_CONTAINERS
	done_set.insert(g.map(simp1), _rank);
#else
	done_set.insert(g.map(simp1));
#endif
      }
      if (_no > 50) {
	MessageStreams::debug() << "... still " << countdown << " simplices to check for flips ..." << std::endl;
      }
      
      // search for missing interior points:
      for (Simplex::const_iterator missing_iter = missing_vertices.begin();
	   missing_iter != missing_vertices.end();
	   ++missing_iter) {
	dependent_set_type dependent_set(simp1 + *missing_iter);
	if (dependent_sets.find(dependent_set) != dependent_sets.end()) {

	  // processed already:
	  continue;
	}
	// try to build a flip from dependent_set:
	const FlipRep fliprep(chiro, dependent_set, tn);
	if (fliprep) {
	  
	  // succeeded:
	  if (forbid_vertex_removal && fliprep.kills_vertex()) {
	    continue;
	  }
	  if (forbid_card_change && !fliprep.is_balanced()) {
	    continue;
	  }
	  _flips[fliprep] = false;
	  dependent_sets.insert(dependent_set);
	  for (symmetryptr_iterdata::const_iterator sym_iter = tn_symmetryptrs.first.begin();
	       sym_iter != tn_symmetryptrs.first.end();
	       ++sym_iter) {
	    
	    // insert all equivalent flips:
	    const Symmetry& g(**sym_iter);
	    _flips[g.map(fliprep)] = false;
	    dependent_sets.insert(g.map(dependent_set));
	  }
	}
	else {
	  
	  // save processed dependent set:
	  dependent_sets.insert(dependent_set);
	  for (symmetryptr_iterdata::const_iterator sym_iter = tn_symmetryptrs.first.begin();
	       sym_iter != tn_symmetryptrs.first.end();
	       ++sym_iter) {
	    // save equivalent dependent sets:
	    const Symmetry& g(**sym_iter);
	    dependent_sets.insert(g.map(dependent_set));
	  }
	}      
      }
      int count(0);
      
      // search for adjacent simplices:
      if (inctableptr) {
	
	// we can use preprocessed incidences:
	const SimplicialComplex intfacets(inctableptr->intfacets(simp1));
	for (SimplicialComplex::const_iterator intiter = intfacets.begin();
	     intiter!= intfacets.end();
	     ++intiter) {
	  const SimplicialComplex simppair(tn * inctableptr->intcofacets(*intiter));
	  if (simppair.card() < 2) {
	    
	    // facet is not interior in tn, thus, not supporting a flip:
	    continue;
	  }
	  dependent_set_type dependent_set(simppair.support());
	  MessageStreams::debug() << "dependent_set = " << dependent_set << std::endl;
	  _process_dependent_set(dependent_set,
				 chiro,
				 tn,
				 tn_symmetryptrs,
				 dependent_sets,
				 done_set,
				 forbid_vertex_removal,
				 forbid_card_change);
	  if (++count > _rank) {
	    
	    // we have all neighbors already:
	    break;
	  }   
	}
      }
      else {
	
	// here, we do not have the preprocessed incidences:
	for (SimplicialComplex::const_iterator iter2 = tn.begin();
	     iter2 != tn.end();
	     ++iter2) {
	  const Simplex& simp2(*iter2);
	  dependent_set_type dependent_set(simp1 + simp2);
	  if (dependent_set.card() != _rank + 1) {
	    continue;
	  }
	  MessageStreams::debug() << "\t processing adjacent simplex " << simp2 << " ..." << std::endl;
	  _process_dependent_set(dependent_set,
				 chiro,
				 tn,
				 tn_symmetryptrs,
				 dependent_sets,
				 done_set,
				 forbid_vertex_removal,
				 forbid_card_change);
	  if (++count > _rank) {
	    
	    // we have all neighbors already:
	    break;
	  }   
	}
      }
    }

    // report on flip-deficiency, if requested:
    if (!forbid_vertex_removal
	&& CommandlineOptions::neighborcount() 
	&& (_flips.size() < _no - _rank)) {
      MessageStreams::debug() << "triangulation" << std::endl
			      << tn << std::endl;
#ifdef TOPCOM_FLIPS
      MessageStreams::debug() << "has only " << _flips.size() << " flips." << std::endl;
#else
      MessageStreams::debug() << "has only " << _flips.size() << " flips." << std::endl;
#endif
    }
    MessageStreams::debug() << "... done." << std::endl;
  }

  void TriangFlips::_process_dependent_set(const dependent_set_type&     dependent_set,
					   const Chirotope&              chiro,
					   const TriangNode&             tn,
					   const symmetryptr_datapair&   tn_symmetryptrs,
					   std::set<dependent_set_type>& dependent_sets,
					   std::set<Simplex>&            done_set,
					   const bool                    forbid_vertex_removal,
					   const bool                    forbid_card_change) {
      
    if (dependent_sets.find(dependent_set) != dependent_sets.end()) {

      // dependent_set contains has been processed already:
      MessageStreams::debug() << "\t ... already processed - continue" << std::endl;	  
      return;
    }
	
    // try to build a flip from dependent_set:
    const FlipRep fliprep(chiro, dependent_set, tn);
    MessageStreams::debug() << "\t ... induces flip supported on circuit " << fliprep << " ..." << std::endl;
    if (fliprep) {

      // succeeded:
      if (forbid_vertex_removal && fliprep.kills_vertex()) {

	// not a feasible flip:
	return;
      }
      else if (CommandlineOptions::dont_add_points() && fliprep.adds_vertex()) {

	// not a feasible flip:
	return;
      }
	  
      // insert flip:
      _flips[fliprep] = false;
      dependent_sets.insert(dependent_set);
      for (symmetryptr_iterdata::const_iterator sym_iter = tn_symmetryptrs.first.begin();
	   sym_iter != tn_symmetryptrs.first.end();
	   ++sym_iter) {

	// insert all equivalent flips:
	const Symmetry& g(**sym_iter);
	_flips[g.map(fliprep)] = false;
	dependent_sets.insert(g.map(dependent_set));
      }
    }
    else {

      // save processed dependent set:
      dependent_sets.insert(dependent_set);
      for (symmetryptr_iterdata::const_iterator sym_iter = tn_symmetryptrs.first.begin();
	   sym_iter != tn_symmetryptrs.first.end();
	   ++sym_iter) {

	// save equivalent dependent sets:
	const Symmetry& g(**sym_iter);
	dependent_sets.insert(g.map(dependent_set));
      }
    }
  }



}; // namespace topcom
  
// eof TriangFlips.cc
