/* Copyright (c) 1997-2004
   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: stellar_subd_face.cc,v 1.7 2006/03/10 17:58:03 witte Exp $"

#include <Poly.h>
#include <PowerSet.h>
#include <Array.h>
#include <Rational.h>
#include <Matrix.h>
#include <Vector.h>
#include <read_int_args.h>
#include <argv_options.h>

#include <list>
#include <sstream>
#include <ext/hash_set>

namespace polymake { namespace topaz {

namespace {
   enum { v, no_labels, geom_real };
}

void stellar_subd_face(Poly& p_out, Poly& p_in, const Set<int>& F_in, const char* faces_section,
		       const argv_option *options, const std::string& comment)
{
   Array< Set<int> > C_in = p_in.give("FACETS");
   const int n_vert = p_in.give("N_VERTICES");
  
   Array< Set<int> > subd_faces(1);
   if (F_in.empty()) 
     subd_faces = p_in.give(faces_section);
   else // single face by command line input specified
     subd_faces[0] = F_in;
   
   // compute new complex
   std::list< Set<int> > C;

   for (int i=0; i<subd_faces.size(); ++i) {
     const Set<int> F = subd_faces[i];
     bool facet_found = false;
     
     for (Entire< Array< Set<int> > >::const_iterator f=entire(C_in);
	  !f.at_end(); ++f) {
       Set<int> facet = *f;
       
       if (incl(F,facet)<1) {  // F contained in the facet
	 facet_found = true;
	 const int size = facet.size();
	 facet -= F;
	 facet += n_vert+i;

	 // add new facets
	 Subsets_of_k< const Set<int> > enumerator( F, size-facet.size() );     
	 for (Entire< Subsets_of_k< const Set<int> > >::iterator s_it=entire(enumerator);
	      !s_it.at_end(); ++s_it)
	   C.push_back(facet + *s_it);
	 
       } else
	 C.push_back(facet);
     }
     
     if (!facet_found)
       throw std::runtime_error("stellar_subd_face: Input does not specify a face (of the complex generated so far).");

     C_in = Array< Set<int> >(C.size(),C.begin());
     C.clear();
   }

   p_out.take("DESCRIPTION") << comment;
   p_out.take("FACETS") << as_array(C_in);
   
   // compute new coordinates
   if (options[geom_real]) {
     Matrix<Rational> Coord = p_in.give("GEOMETRIC_REALIZATION");
     Coord.resize(n_vert+subd_faces.size(),Coord.cols());
     for (int i=0; i<subd_faces.size(); ++i)
       Coord[i+n_vert] = average( rows(Coord.minor(subd_faces[i], All)) );

     p_out.take("GEOMETRIC_REALIZATION") << Coord;
   }
   
   // compute new label
   if (!options[no_labels]) {
     Array<std::string> L = p_in.give("VERTEX_LABELS");
     std_ext::hash_set<std::string> old_L(n_vert);
     for (Entire< Array<std::string> >::const_iterator l=entire(L); !l.at_end(); ++l)
       old_L.insert(*l);

     L.resize(n_vert+subd_faces.size());
     for (int i=0; i<subd_faces.size(); ++i) {
       std::ostringstream label;
       Entire< Set<int> >::const_iterator v=entire(subd_faces[i]);
       label << "{" << *v;  ++v;
       for ( ; !v.at_end(); ++v)
	 label << "," << *v;
       label << "}";
       std::string l=label.str(), ll=l;
       
       // test if ll is unique
       int j=0;
       while (old_L.find(ll) != old_L.end()) {
	 ++j;
	 label.str("");
	 label << l << "_" << j;
	 ll=label.str();
       }
    
       L[n_vert+i] = ll;
     }

     p_out.take("VERTEX_LABELS") << L;
   }
}
  
} }

using namespace polymake;

/** @file stellar_subd_face
 *
 * Stellar subdivides either the face specified by the command line input or
 * all faces specified in the <faces_section>.
 *
 *  @synopsis stellar_subd_face <out_file> <in_file> { -v <v_1> <v_2>...<v_i> ... | <faces_section> } [ -nol ] [ -geom_real ]
 *
 *  @reading  FACETS, may read GEOMETRIC_REALIZATION, may read VERTEX_LABELS
 *  @writing  DESCRIPTION, FACETS, N_VERTICES, may write GEOMETRIC_REALIZATION, may write VERTEX_LABELS
 *
 *  @index clients Producing a new simplicial complex from others
 */


int main(int argc, const char* argv[])
{
   argv_option options[]={ {"-v"},{"-nol"},{"-geom_real"} };
   if ( !extract_options(argc,argv,2,options) || argc<4) {
      cerr << "usage: " << argv[0] << " <out_file> <in_file> { -v <v_1> <v_2>...<v_i> ... | <faces_section> } [ -nol ] [ -geom_real ]" << endl;
      return 1;
   }
   try {
      Poly p_in(argv[2], ios::in);
      Poly p_out(argv[1], ios::out | ios::trunc, p_in.type());
    
      Set<int> F_in;
      if (options[0])
	F_in = topaz::read_int_args_as_set(argc, argv, 3);
      
      std::ostringstream comment;
      wrap(comment) << "Obtained from " << argv[2] << " by stellar subdivision of the ";
      if (F_in.empty())
	wrap(comment) << "faces in " << argv[3] << ".";
      else
	wrap(comment) << "face " << F_in << ".";
      
      topaz::stellar_subd_face(p_out, p_in, F_in, argv[3], options, comment.str());
   }
   catch (const std::exception& e) {
      cerr << e.what() << endl;
      return 1;
   }
   return 0;
}
