/* Copyright (c) 1997-2010
   Ewgenij Gawrilow, Michael Joswig (Technische Universitaet Darmstadt, Germany)
   http://www.polymake.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.
--------------------------------------------------------------------------------
   $Project: polymake $$Id: cell_from_subdivision.cc 10057 2011-03-11 17:29:30Z herr $
*/

#include "polymake/client.h"
#include "polymake/Array.h"
#include "polymake/Rational.h"
#include "polymake/Matrix.h"
#include "polymake/IncidenceMatrix.h"
#include "polymake/Graph.h"

namespace polymake { namespace polytope {

perl::Object full_dim_cell(perl::Object p_in, const Set<int>& cell_verts, perl::OptionSet options)
{
  perl::Object p_out("Polytope<Rational>");

  if (p_in.exists("CONE_DIM")) {
    const int dim=p_in.CallPolymakeMethod("DIM");
    p_out.take("CONE_DIM") << dim+1;
  }
  const Matrix<Rational> V=p_in.give("VERTICES");
  p_out.take("VERTICES") << V.minor(cell_verts,All);    
  if (p_in.exists("AFFINE_HULL")) {
    const Matrix<Rational> AH=p_in.give("AFFINE_HULL");
    p_out.take("AFFINE_HULL") << AH;
  }

  if (options["relabel"]) {
    const int n_vertices = V.rows();
    Array<std::string> labels(n_vertices);
    read_labels(p_in, "VERTEX_LABELS", labels);
    Array<std::string> labels_out(select(labels,cell_verts));
    p_out.take("VERTEX_LABELS") << labels_out;
  }
  
  return p_out;
}


perl::Object cell_from_subdivision(perl::Object p_in, int cell_number, perl::OptionSet options)
{
  const Array< Set<int> > subdivision = p_in.give("POLYTOPAL_SUBDIVISION");
  if (cell_number < 0 || cell_number >= subdivision.size())
    throw std::runtime_error("cell number out of range");
  
  perl::Object p_out = full_dim_cell(p_in, subdivision[cell_number], options);
  p_out.set_description() << "cell " << cell_number << " of subdivision of " << p_in.name() << endl;
  return p_out;
}

perl::Object cells_from_subdivision(perl::Object p_in, const Set<int>& cells, perl::OptionSet options)
{
  const Array< Set<int> > subdivision = p_in.give("POLYTOPAL_SUBDIVISION");
  Set<int> cell_verts;
  for (Entire< Set<int> >::const_iterator i=entire(cells); !i.at_end(); ++i) {
    int cell_number = *i;
    if (cell_number < 0 || cell_number >= subdivision.size())
      throw std::runtime_error("cell number out of range");
    cell_verts+=subdivision[cell_number];
  }
  perl::Object p_out = full_dim_cell(p_in, cell_verts, options);
  p_out.set_description() << "cells " << cells << " of subdivision of " << p_in.name() << endl;
  return p_out;
} 


UserFunction4perl("# @category Producing a new polyhedron from others"
                  "# Extract the given //cell// of the subdivision of a polyhedron and write it as a new polyhedron."
                  "# @param Polytope P"
                  "# @param Int cell"
                  "# @option Bool relabel copy the vertex labels from the original polytope"
                  "# @return Polytope",
                  &cell_from_subdivision,"cell_from_subdivision(Polytope $ { relabel => 0})");

UserFunction4perl("# @category Producing a new polyhedron from others"
                  "# Extract the given //cells// of the subdivision of a polyhedron and write their union"
                  "# as a new polyhedron."
                  "# @param Polytope P"
                  "# @param Set<Int> cells"
                  "# @option Bool relabel copy the vertex labels from the original polytope"
                  "# @return Polytope",
                  &cells_from_subdivision,"cells_from_subdivision(Polytope $ { relabel => 0})");
} }

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