/* 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: barycentric_subdivision_impl.cc,v 1.6 2005/11/11 10:38:25 gawrilow Exp $"

#include <barycentric_subdivision.h>

#include <sstream>
#include <list>

namespace polymake { namespace topaz {

   Array< Set<int> > bs(const HasseDiagram<>& HD) {
      const int dim=HD.dim()-1;
      int d=dim+1;
      for (int i=2; i<=dim; ++i) d*=i;	// each old facet is divided in (dim+1)! cells
      Array< Set<int> > F(HD.nodes_of_dim(-1).size() * d);
      Array< Set<int> >::iterator f=F.begin();
    
      typedef HasseDiagram<>::out_edge_list::const_iterator out_edge;
      typedef std::list<out_edge> stack_type;
      stack_type stack;
    
      // start with the "empty set" node - just for convenience
      stack.push_back(HD.out_edges(HD.bottom_node()).begin());

      d=0; // dimension of the facet accumulated in stack so far
      do {
	 // complete the facet
	 while (d<dim) {
	    const int n=stack.back().to_node();
	    stack.push_back(HD.out_edges(n).begin());
	    ++d;
	 }
      
	 // copy the facet
	 for (Entire<stack_type>::const_iterator s=entire(stack);  !s.at_end();  ++s)
	    *f += s->to_node() - 1;	// account for the top or bottom node which does not contribute to the new complex
      
	 ++f;
      
	 // depth-first search to the next facet
	 do {
	    if (!(++stack.back()).at_end()) break;
	    stack.pop_back();
	 } while (--d>=0);
      } while (d>=0);

      return F;
   }
  
   Array<std::string> bs_labels(const HasseDiagram<>& HD) {
      Array<std::string> L(HD.nodes()-2);
      Nodes< HasseDiagram<> >::const_iterator f=nodes(HD).begin(); ++f;  // skip the top(bottom) node
      std::ostringstream label;
      for (Entire< Array<std::string> >::iterator l=entire(L); !l.at_end(); ++l, ++f) {
	 wrap(label) << *f;
	 *l=label.str();
	 label.str("");
      
	 // convert spaces to commas
	 size_t blank=0;
	 while ((blank=l->find(' ',blank)) != std::string::npos)
	    (*l)[blank++]=',';
      }
    
      return L;
   }
  
   Matrix<Rational> bs_geom_real(const Matrix<Rational>& old_coord,
				 const HasseDiagram<>& HD)
   {
      const int amb_dim = old_coord.cols();
      const int n_nodes = HD.nodes()-2;
      Matrix<Rational> new_coord(n_nodes,amb_dim);
    
      Nodes< HasseDiagram<> >::const_iterator n_it=nodes(HD).begin();  ++n_it;
      for (Entire< Rows< Matrix<Rational> > >::iterator r=entire(rows(new_coord));  !r.at_end();  ++r, ++n_it) {
	 accumulate_in( entire(select(rows(old_coord), *n_it)), operations::add(), *r ) /= n_it->size();
      }

      return new_coord;
   }
  
} }
