/* 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/Matrix.h"
#include "polymake/IncidenceMatrix.h"
#include "polymake/Set.h"
#include "polymake/topaz/sum_triangulation_tools.h"
#include "polymake/PowerSet.h"
#include "polymake/hash_set"

namespace polymake { namespace topaz {

// this function takes a facet F and glues it around the boundary of
// the ball defined by the WEB. It creates a new simplicial complex
// which contains all the facets indicated by WEB. 
void glue_facet(const Set<int>& _F, 
                const Array<int>& F_vertex_indices, 
                const Array<Set<int> >& facets, 
                const Array<int>& facets_vertex_indices, 
                const Set<int>& web, 
                int shift, 
                bool shift_facet,
                std::vector<Set<int> >& result)
{
   // computing the boundary ridges
   hash_set< Set< int > > boundary;

   for (Entire< const Set<int>& >::const_iterator sfit = entire(web); !sfit.at_end(); ++sfit){
      for (Entire< Subsets_less_1<const Set<int>& > >::const_iterator rit = entire(all_subsets_less_1(facets[*sfit])); !rit.at_end(); ++rit) {
         if(boundary.exists(*rit)){
            boundary -= *rit;
         }else{
            boundary +=*rit;
         }
      }
   }

   // taking care of index shifting for unused points
   Array<int> vertex_indices = facets_vertex_indices;

   // take into account the vertex indices of F
   Set<int> F(permuted_inv(_F,F_vertex_indices));
   
   // shift the indices of F or boundary facet
   if (shift_facet) {
      F = attach_operation(F, operations::fix2<int,operations::add>(operations::fix2<int,operations::add>(shift)));
   } else {
      // we shift the vertex indices of the boundary facet via the
      // vertex permutation so that we don't have to do it later
      vertex_indices = attach_operation(vertex_indices, operations::fix2<int,operations::add>(operations::fix2<int,operations::add>(shift)));
   }

   // glue everything together
   for (Entire<hash_set<Set<int> > >::const_iterator bfit = entire(boundary); !bfit.at_end(); ++bfit){
      result.push_back(F + permuted_inv(*bfit, vertex_indices));
   }    
}


template<typename Scalar>  
perl::Object sum_triangulation(perl::Object p_in, 
                               perl::Object q_in, 
                               const IncidenceMatrix<> webOfStars_in,
                               perl::OptionSet options)
{
   return sum_triangulation_impl<Scalar>(p_in,q_in,webOfStars_in, options);
}

UserFunctionTemplate4perl("# @category Producing a new simplicial complex from others\n"
                          "# Produce a specific sum-triangulation of two given triangulations.\n"
                          "# and a WebOfStars.  There are P-sum-triangulations and Q-sum-triangulations."
                          "# If the image of the star of the origin of P is empty then we have a"
                          "# Q-sum-triangulation; otherwise it is a P-sum-triangulation."
                          "# For details see Assarf, Joswig & Pfeifle:"
                          "# Webs of stars or how to triangulate sums of polytopes, to appear"
                          "# @param GeometricSimplicialComplex P first complex"
                          "# @param GeometricSimplicialComplex Q second complex"
                          "# @param IncidenceMatrix WebOfStars Every row corresponds to a full dimensional simplex in P and every column to a full dimensional simplex in Q."
                          "# @option Bool origin_first decides if the origin should be the first point in the resulting complex. Default=0"
                          "# @return GeometricSimplicialComplex",
                          "sum_triangulation<Scalar>(GeometricSimplicialComplex<type_upgrade<Scalar>> GeometricSimplicialComplex<type_upgrade<Scalar>>; IncidenceMatrix=new IncidenceMatrix() { origin_first => 0 })"); 

} }

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