/* Copyright (c) 1997-2005
   Ewgenij Gawrilow, Michael Joswig (Technische Universitaet Berlin, Germany)
   http://www.math.tu-berlin.de/polymake,  mailto:polymake@math.tu-berlin.de

   This program is free software; you can redistribute it and/or modify it
   under the terms of the GNU General Public License as published by the
   Free Software Foundation; either version 2, or (at your option) any
   later version: http://www.gnu.org/licenses/gpl.txt.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
*/

#ident "$Project: polymake $$Id: complex_tools.cc,v 1.35 2005/09/22 17:12:10 gawrilow Exp $"

#if defined(__GNUC__) && __GNUC__==3 && __GNUC_MINOR__<3 && !defined(__APPLE__) && !defined(__COMO__)
#pragma implementation
#endif

#include <complex_tools.h>

namespace polymake { namespace topaz {

void remove_vertex_star(HasseDiagram<>& HD, const int v)
{
  // search the vertices of the HD for v
  int start_node;
#ifdef POLY_DEBUG
  bool node_found=false;
#endif
  for (Entire<sequence>::iterator it=entire(HD.nodes_of_dim(0)); !it.at_end(); ++it) {
    if (HD.node(*it).front()==v) {
      start_node=*it;
#ifdef POLY_DEBUG
      node_found=true;
#endif
      break;
    }
  }

#ifdef POLY_DEBUG
  if (!node_found)
    throw std::runtime_error("remove_vertex_star: v is not a vertex.\ninvalid input");
#endif
  
  // remove all nodes of the HD that can be reached from start_node
  Bitset visited(HD.nodes());
  std::list<int> node_queue;
  Set<int> empty_nodes;
  
  node_queue.push_back(start_node);
  visited+=start_node;
  empty_nodes+=start_node;
  
  while (!node_queue.empty()) {
    const int n=node_queue.front();      // remove first node from the queue
    node_queue.pop_front();
    
    for (Entire<HasseDiagram<>::out_edge_list>::const_iterator e=entire(HD.out_edges(n)); !e.at_end(); ++e) {
      const int nn=e.to_node();

      if (!visited.contains(nn) && nn!=HD.top_node()) {      // nn not been visited yet and nn != top node
	visited+=nn;                                         // -> add nn to the queue.
	empty_nodes+=nn;
	node_queue.push_back(nn);
      }
    }
    
    // repair hasse diagram if necessary
    for (Entire<HasseDiagram<>::in_edge_list>::const_iterator e=entire(HD.in_edges(n)); !e.at_end(); ++e) {
      const int nn=e.from_node();
      if (HD.out_degree(nn)==1)
	HD.edge(nn,HD.top_node());
    }
    
    // remove all out and in edges of n
    HD.out_edges(n).clear();
    HD.in_edges(n).clear();
  }  // end while
  
  // remove empty nodes
  HD.delete_nodes(empty_nodes);
}
  
bool is_closed_pseudo_manifold (const HasseDiagram<>& HD)
{
  const int dim=HD.dim()-1;
  if (dim==0)
     return true;

  for (Entire<HasseDiagram<>::in_edge_list>::const_iterator it=entire(HD.in_edges(HD.top_node())); !it.at_end(); ++it) {
    const int n = it.from_node();

    if ( HD.node(n).size()-1 != dim ) {  // complex is not pure   
      //      cout << "is_closed_pseudo_manifold: comples is not PURE." << endl;
      return false;
    }
  }

  for (Entire<sequence>::const_iterator it=entire(HD.nodes_of_dim(-2)); !it.at_end(); ++it)
    if ( HD.out_degree(*it) != 2 ) {     // ridge contained in one facet only
      //      cout << "is_closed_pseudo_manifold: " << *it << " is contained in " << HD.out_degree(*it) << " facets." << endl;
      return false;
    }
  
  return true;
}

Array< Set<int> > torus()
{
  static const int Torus[14][3]= { {0, 1, 2},
				   {0, 1, 3},
				   {0, 3, 4},
				   {1, 2, 5},
				   {0, 4, 5},
				   {1, 4, 5},
				   {2, 3, 4},
				   {2, 3, 5},
				   {0, 5, 6},
				   {1, 4, 6},
				   {3, 5, 6},
				   {2, 4, 6},
				   {1, 3, 6},
				   {0, 2, 6} };

  return Array< Set<int> >(Torus);
}

// the projective plane
Array< Set<int> > projective_plane() {
   static const int Proj_plane[10][3]={ { 0, 1, 4 },
					{ 0, 1, 5 },
					{ 0, 2, 3 },
					{ 0, 2, 4 },
					{ 0, 3, 5 },
					{ 1, 2, 3 },
					{ 1, 2, 5 },
					{ 1, 3, 4 },
					{ 2, 4, 5 },
					{ 3, 4, 5 } };
   return Array< Set<int> >(Proj_plane);
}

} }

// Local Variables:
// mode:C++
// c-basic-offset:3
// End:
