/* 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: connected_sum.cc,v 1.12 2004/11/17 13:10:20 witte Exp $"

#include <Poly.h>
#include <connected_sum.h>
#include <read_int_args.h>

namespace polymake { namespace topaz {

void connected_sum(Poly& p_out, Poly& p_in1, Poly& p_in2, const int f1, const int f2,
		   const std::list<int> P,
		   const bool no_labels, const std::string& comment)
{
   const Array< Set<int> > C1 = p_in1.give("FACETS");
   Array<std::string> L1;  // connected_sum interprets empty labels as no labels
   if (!no_labels) L1 = p_in1.give("VERTEX_LABELS");

   const Array< Set<int> > C2 = p_in2.give("FACETS");
   Array<std::string> L2;
   if (!no_labels) L2 = p_in2.give("VERTEX_LABELS");
   
   if (f1 >= C1.size()) {
      std::ostringstream e;
      e << "connected_sum: " << f1 << " is not a facet.";
      throw std::runtime_error(e.str());
   }

   if (f2 >= C2.size()) {
      std::ostringstream e;
      e << "connected_sum: " << f2 << " is not a facet.";
      throw std::runtime_error(e.str());
   }

   if (C1[f1].size() != C2[f2].size()) {
      std::ostringstream e;
      e << "connected_sum: " << f1 << " and " << f2
	<< " do not have the same dimension.";
      throw std::runtime_error(e.str());
   }

   // testing P
   if (!P.empty()) {  // permutation specified
      Set<int> V;
      accumulate_in(entire(P), operations::add(), V);
      
      if ( incl(V,C1[f1])!=0 ) {
	 std::ostringstream e;
	 e << "connected_sum: Specified permutation does not match facets " << f1 << ".";
	 throw std::runtime_error(e.str());
      }
   }
   
   // set permutation: connected_sum interprets empty permutation as trivial
   std_ext::hash_map<int, int> Perm;
   
   if (!P.empty()) {  // permutation specified
      Perm.resize((C1[f1].size()));
      Set<int>::const_iterator v= C1[f1].begin();
      for (Entire< std::list<int> >::const_iterator p=entire(P);
	   !p.at_end(); ++p, ++v)
	 Perm[*v] = *p;
   }
   
   p_out.take("DESCRIPTION") << comment;
   p_out.take("FACETS") << as_array(connected_sum(C1, C2, f1, f2, L1, L2, Perm));

   if (!no_labels)
      p_out.take("VERTEX_LABELS") << L1; 
}

} }

using namespace polymake;

/** @file connected_sum
 *
 *  Compute the connected sum of two complexes.
 *
 *  Parameters @i f_1 and @i f_2 specify which facet of the first and second complex correspondingly are glued together.
 *  Default is the 0-th facet of both.
 *
 *  The vertices in the selected facets are identified with each other according to their order in the facet
 *  (that is, in icreasing index order).  The option @c -p allows to get an alternative identification. It should specify a
 *  permutation of the vertices of the second facet.  If the permutation contains contiguous sequences, they can be shortened
 *  as @i n_1 ... @i n_2 (perl lovers might use just two points.)  For example, (7 2 ... 4 12) = (7 2 3 4 12).
 *
 *  The vertices of the new complex get the original labels with @i _1 or @i _2 appended, according to the input complex
 *  they came from.  If you specify the @c -nol flag, the label generation will be omitted.
 *
 *  @synopsis connected_sum <out_file> <in_file_1> <in_file_2> [ <f_1> [ <f_2> ] ] [ -p <p_1> ... <p_n> ] [ -nol ]
 *
 *  @reading  FACETS, may read VERTEX_LABELS
 *  @writing  DESCRIPTION, FACETS, may write VERTEX_LABELS
 *
 *  @index clients Producing a new simplicial complex from others
 */

int main(int argc, const char* argv[])
{
   if (argc<4) {
      cerr << "usage: " << argv[0] << " <out_file> <in_file_1> <in_file_2> [ <f_1> [ <f_2> ] ] [ -p <p_1> ... <p_n> ] [ -nol ]"<< endl;
      return 1;
   }
   try {
      Poly p_in1(argv[2], ios::in);
      Poly p_in2(argv[3], ios::in);
      Poly p_out(argv[1], ios::out | ios::trunc, p_in1.type());
      
      const bool no_labels= !strcmp(argv[argc-1],"-nol");
      
      // reading permutation and facets
      int f1=0, f2=0;
      std::list<int> P;
      bool permutation = false;
 
      if ( argc>6 && !strcmp(argv[6],"-p") ) {  // f1 and f2 specified
	 f1 = atoi(argv[4]);
	 f2 = atoi(argv[5]);
	 
	 permutation = true;
	 if (no_labels)
	    P = topaz::read_int_args_as_list(argc-1, argv, 7);
	 else
	    P = topaz::read_int_args_as_list(argc, argv, 7);
      }

      if ( argc>5 && !strcmp(argv[5],"-p") ) {    // only f1 specified
	 f1 = atoi(argv[4]);
	 
	 permutation = true;
	 if (no_labels)
	    P = topaz::read_int_args_as_list(argc-1, argv, 6);
	 else
	    P = topaz::read_int_args_as_list(argc, argv, 6);
      }
      
      if ( argc>4 && !strcmp(argv[4],"-p") ) {    // read permutaion only
	 permutation = true;
	 if (no_labels)
	    P = topaz::read_int_args_as_list(argc-1, argv, 5);
	 else 
	    P = topaz::read_int_args_as_list(argc, argv, 5);
      }

      if (!permutation) {
	 f1= argc>4 ? atoi(argv[4]) : 0;
	 f2= argc>5 ? atoi(argv[5]) : 0;
      }
        
      std::ostringstream comment;
      comment << "Connected sum of " << argv[2] << ", using facet " << f1
	      << ",\nand " << argv[3] << ", using facet " << f2 << ".";
      if (!P.empty())
	 wrap(comment) << "\nThe vertices of facet " << f2 << " of "
		       << argv[3] << " are permuted " << P << ".";

      topaz::connected_sum(p_out, p_in1, p_in2, f1, f2, P, no_labels, comment.str());
   }
   catch (const std::exception& e) {
      cerr << e.what() << endl;
      return 1;
   }
   return 0;
}


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