////////////////////////////////////////////////////////////////////////////////
// 
// Incidences.cc
//
//    produced: 19/04/98 jr
// 
////////////////////////////////////////////////////////////////////////////////
#include <iostream>
#include <ctype.h>
#include <string.h>

#include "VertexFacetTable.hh"

#include "Field.hh"
#include "Chirotope.hh"
#include "Permutation.hh"
#include "Incidences.hh"

namespace topcom {

  Incidences::Incidences(const Chirotope& chiro, const Facets& chirofacets) :
    _chiroptr(&chiro),
    _intfacets(),
    _conffacets(),
    _intcofacets(),
    _confcofacets() {
    size_type count(0);
    const parameter_type no(_chiroptr->no());
    const parameter_type rank(_chiroptr->rank());
    Permutation perm(no, rank);
    MessageStreams::debug() << message::lock
			    << "computing interior/exterior incidences ..." << '\n'
			    << "computing interior/exterior facets ..." << std::endl
			    << message::unlock;

    // store the maps simplex |-> interior/exterior facets:
    do {
      const Simplex simp(perm);
      if (chiro(simp) == FieldConstants::ZERO) {

	// ignore non full-dimensional simplices:
	continue;
      }
      MessageStreams::debug() << message::lock
			      << "classifying facets of " << simp << " in " << chirofacets << " ..." << std::endl
			      << message::unlock;
      _process_simplex(no, rank, simp, chirofacets);
      if (++count % CommandlineOptions::report_frequency() == 0) {
	MessageStreams::verbose() << message::lock
				  << count << " simplices processed so far." << std::endl
				  << message::unlock;
      }
    } while (perm.lexnext());
    MessageStreams::debug() << message::lock
			    << "... done computing interior/exterior facets" << std::endl
			    << message::unlock;
    _generate_reverse_tables();
  }

  Incidences::Incidences(const Chirotope& chiro, const Facets& chirofacets, const SimplicialComplex& relevant_simps) :
    _chiroptr(&chiro),
    _intfacets(),
    _conffacets(),
    _intcofacets(),
    _confcofacets() {
    size_type count(0);
    const parameter_type no(_chiroptr->no());
    const parameter_type rank(_chiroptr->rank());
    MessageStreams::debug() << message::lock
			    << "computing interior/exterior incidences ..." << '\n'
			    << "computing interior/exterior facets ..." << std::endl
			    << message::unlock;
    
    // store the maps simplex |-> interior/exterior facets:
    for (SimplicialComplex::const_iterator sciter = relevant_simps.begin();
	 sciter != relevant_simps.end();
	 ++sciter) {
      const Simplex& simp(*sciter);
      MessageStreams::debug() << message::lock
			      << "classifying facets of " << simp << " in " << chirofacets << " ..." << std::endl
			      << message::unlock;
      _process_simplex(no, rank, simp, chirofacets);
      if (++count % CommandlineOptions::report_frequency() == 0) {
	MessageStreams::debug() << message::lock
				<< count << " simplices processed so far" << std::endl
				<< message::unlock;
      }
    }
    MessageStreams::debug() << message::lock
			    << "... done computing interior/exterior facets" << std::endl
			    << message::unlock;
    _generate_reverse_tables();
  }

  void Incidences::_process_simplex(const parameter_type no,
				    const parameter_type rank,
				    const Simplex& simp,
				    const Facets& chirofacets) {
    SimplicialComplex interior_facets;
    facets_data config_facets;
    Simplex facet(simp);
    for (Simplex::iterator iter = simp.begin(); iter != simp.end(); ++iter) {
      facet -= *iter;
      MessageStreams::debug() << message::lock
			      << "checking facet " << facet << " ..." << std::endl
			      << message::unlock;
      bool is_interior(true);
      facet_type config_facet;
      for (Facets::const_iterator facetsiter = chirofacets.begin();
	   facetsiter != chirofacets.end();
	   ++facetsiter) {
	if (facetsiter->superset(facet)) {
	  
	  // facet is not interior:
	  is_interior = false;
	  config_facet = *facetsiter;
	  break;
	}
      }
      if (is_interior) {
	MessageStreams::debug() << message::lock
				<< "... " << facet << " is an interior facet" << std::endl
				<< message::unlock;
	interior_facets += facet;
      }
      else {
	
	// add the facet of the simplex to interior facets:
	config_facets.insert(config_facet);
	MessageStreams::debug() << message::lock
				<< "... " << facet << " is in a boundary facet" << std::endl
				<< message::unlock;
      }
      MessageStreams::debug() << message::lock
			      << "... done." << std::endl
			      << message::unlock;
      facet += *iter;
    }
#ifdef COMPUTATIONS_DEBUG
    if (interior_facets.empty()) {
      MessageStreams::debug() << message::lock
			      << "Incidences::Incidences(const Facets&): "
			      << "no interior facet for " << simp << std::endl
			      << message::unlock;
    }
    if (config_facets.empty()) {
      MessageStreams::debug() << message::lock
			      << "Incidences::Incidences(const Facets&): "
			      << "no facet containing a facet of " << simp << std::endl
			      << message::unlock;
    }
#endif
    _intfacets[simp]  = interior_facets;
    _conffacets[simp] = config_facets;
  }

  void Incidences::_generate_reverse_tables() {

    // store the reverse maps interior/exterior facet |-> simplex in _intcofacets/_confcofacets:
    for (simpfacets_incidences_data::const_iterator ifiter = _intfacets.begin();
	 ifiter != _intfacets.end();
	 ++ifiter) {
#ifdef TOPCOM_CONTAINERS
      const Simplex& simp(ifiter->key());
      const SimplicialComplex& sc(ifiter->data());
#else
      const Simplex simp(ifiter->first);
      const SimplicialComplex sc(ifiter->second);
#endif
      for (SimplicialComplex::const_iterator sciter = sc.begin();
	   sciter != sc.end();
	   ++sciter) {
	const Simplex facet(*sciter);
	simpcofacets_incidences_data::iterator finditer = _intcofacets.find(facet);
	if (CommandlineOptions::debug()) {
	  MessageStreams::debug() << message::lock
				  << "mapping interior facet " << facet << " to simplex " << simp << std::endl
				  << message::unlock;
	}
	if (finditer == _intcofacets.end()) {
#ifdef TOPCOM_CONTAINERS
	  _intcofacets.insert(facet, simp);
#else
	  _intcofacets.insert(std::pair<Simplex, Simplex>(facet, simp));
#endif
	}
	else {
#ifdef TOPCOM_CONTAINERS
	  finditer->data() += simp;
#else
	  finditer->second += simp;
#endif
	}
      }
    }
    for (conffacets_incidences_data::const_iterator efiter = _conffacets.begin();
	 efiter != _conffacets.end();
	 ++efiter) {
#ifdef TOPCOM_CONTAINERS
      const Simplex& simp(efiter->key());
      const facets_data& facets(efiter->data());
#else
      const Simplex& simp(efiter->first);
      const facets_data& facets(efiter->second);
#endif
      for (facets_data::const_iterator fiter = facets.begin();
	   fiter != facets.end();
	   ++fiter) {
	const facet_type facet(*fiter);
	confcofacets_incidences_data::iterator finditer = _confcofacets.find(facet);
	MessageStreams::debug() << message::lock
				<< "mapping configuration facet " << facet << " to simplex " << simp << std::endl
				<< message::unlock;
	if (finditer == _confcofacets.end()) {
#ifdef TOPCOM_CONTAINERS
	  _confcofacets.insert(facet, simp);
#else
	  _confcofacets.insert(std::pair<facet_type, Simplex>(facet, simp));
#endif
	}
	else {
#ifdef TOPCOM_CONTAINERS
	  finditer->data() += simp;
#else
	  finditer->second += simp;
#endif
	}
      }
    }
    MessageStreams::debug() << message::lock
			    << "... done computing interior/exterior cofacets" << '\n'
			    << "... done; table: " << *this << std::endl
			    << message::unlock;
  }
}; // namespace topcom

// eof Incidences.cc
