/* Copyright (c) 1997-2015
   Ewgenij Gawrilow, Michael Joswig (Technische Universitaet Berlin, Germany)
   http://www.polymake.org

   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.
--------------------------------------------------------------------------------
*/

#include "polymake/client.h"
#include "polymake/topaz/connected_sum.h"

namespace polymake { namespace topaz {

perl::Object connected_sum_complex(perl::Object p_in1, perl::Object p_in2, const int f1, const int f2,perl::OptionSet options)
{
   const bool no_labels=options["no_labels"];
   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());
   }


   // set permutation: connected_sum interprets empty permutation as trivial
   hash_map<int, int> Perm;

   perl::Object p_out("SimplicialComplex");

   // testing P
   Array<int> P;
   if (options["permutation"]>>P) {

      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());
      }
      
      //      Perm.resize((C1[f1].size()));
      Set<int>::const_iterator v= C1[f1].begin();
      for (Entire< Array<int> >::const_iterator p=entire(P);
           !p.at_end(); ++p, ++v)
         Perm[*v] = *p;
      p_out.set_description() << "Connected sum of " << p_in1.name() << ", using facet " << f1
                              << ",\nand " << p_in2.name() << ", using facet " << f2 << "." << endl
                              << "The vertices of facet " << f2 << " of " << p_in2.name() << " are permuted " << P << "."<<endl;
   }   
   else
      p_out.set_description() << "Connected sum of " << p_in1.name() << ", using facet " << f1
                              << ",\nand " << p_in2.name() << ", using facet " << f2 << "." << endl;
   
   p_out.take("FACETS") << as_array(connected_sum(C1, C2, f1, f2, L1, L2, Perm));

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

UserFunction4perl("# @category Producing a new simplicial complex from others\n"
                  "# Compute the __connected sum__ of two complexes.\n"
                  "# "
                  "# Parameters //f_1 and //f_2// specify which facet of the first and second complex correspondingly are glued together.\n"
                  "# Default is the 0-th facet of both.\n"
                  "# "
                  "# The vertices in the selected facets are identified with each other according to their order in the facet\n"
                  "# (that is, in icreasing index order).  The option //permutation// allows to get an alternative identification. It should specify a\n"
                  "# permutation of the vertices of the second facet.\n"
                  "# "
                  "# The vertices of the new complex get the original labels with ''_1'' or ''_2'' appended, according to the input complex\n"
                  "#  they came from.  If you set the //no_labels// flag, the label generation will be omitted.\n"
                  "# @param SimplicialComplex complex1"
                  "# @param SimplicialComplex complex2"
                  "# @param Int f1 default: 0"
                  "# @param Int f2 default: 0"
                  "# @option Array<Int> permutation"
                  "# @option Bool no_lables"
                  "# @return SimplicialComplex",
                  &connected_sum_complex,"connected_sum(SimplicialComplex SimplicialComplex; $=0,$=0, { permutation => undef, no_labels => 0 })");
} }

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