/* 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: intersection.cc 10061 2011-03-16 12:46:53Z herr $
*/

#include "polymake/client.h"
#include "polymake/ListMatrix.h"
#include "polymake/Matrix.h"
#include "polymake/Vector.h"
#include "polymake/Array.h"

namespace polymake { namespace polytope {

template <typename Scalar>
perl::Object intersection(const Array<perl::Object>& pp_in)
{
   Entire< Array<perl::Object> >::const_iterator p_in=entire(pp_in);
   const int dim=p_in->CallPolymakeMethod("AMBIENT_DIM");
        
        
   //dimension and polytope check
   bool containsPolytope=false;
   bool containsConePoly=false;
   //to avoid adding too many 1,0,...,0 inequalities 
   while (! p_in.at_end()) {
      //check dimension mismatch
      const int dim2=p_in->CallPolymakeMethod("AMBIENT_DIM");
      if (dim != dim2) throw std::runtime_error("dimension mismatch");
      //check whether contains at least one Polytope
      if(!containsPolytope){
         if (p_in->isa("Polytope")){
            containsPolytope=true;
         }
      }        
      ++p_in;
   }

   Entire< Array<perl::Object> >::const_iterator p_in2=entire(pp_in);
        
   perl::ObjectType t=(containsPolytope)?(perl::ObjectType::construct<Scalar>("Polytope")):(perl::ObjectType::construct<Scalar>("Cone"));
   perl::Object p_out(t);
        
   std::string descr_names;
        

   ListMatrix< Vector<Scalar> > Inequalities(0,containsPolytope?dim+1:dim), Equations(0,containsPolytope?dim+1:dim);
        
   while (! p_in2.at_end()) {
      try { 
         if(Inequalities.rows()!=0||Equations.rows()!=0)
            descr_names+=", ";
         Matrix<Scalar> F=p_in2->give("FACETS | INEQUALITIES"),
            AH=p_in2->lookup("LINEAR_SPAN | EQUATIONS");
         if(containsPolytope&&F.cols()==dim){
            F=(zero_vector<Scalar>(F.rows()))|F; 
            AH=(zero_vector<Scalar>(AH.rows()))|AH;
            containsConePoly=true;
         } 
         Inequalities /= F;
         Equations /= AH;
      }
      catch (perl::undefined) {
         Matrix<Scalar> AH=p_in2->give("LINEAR_SPAN | EQUATIONS");
         if(containsPolytope&&AH.cols()==dim){
            AH=(zero_vector<Scalar>(AH.rows()))|AH;
            containsConePoly=true;
         }  
         Equations /= AH;
      }          
            
      descr_names+=p_in2->name();
      ++p_in2;
   }
        
   if(containsConePoly) {
      Inequalities/=unit_vector<Scalar>(dim+1,0);
      p_out.set_description() << "Intersection of cones and polytopes " << descr_names << endl;
      p_out.take("CONE_AMBIENT_DIM") << dim+1;
   } else { // only Cones or Polytopes
      if(!containsPolytope){
         p_out.set_description() << "Intersection of cones " << descr_names << endl;
         p_out.take("CONE_AMBIENT_DIM") << dim;
      } else {
         p_out.set_description() << "Intersection of polytopes " << descr_names << endl;
         p_out.take("CONE_AMBIENT_DIM") << dim+1;
      }
   }
        
        
   p_out.take("INEQUALITIES") << Inequalities;
   if (Equations.rows()) p_out.take("EQUATIONS") << Equations;
        
   return p_out;
}
    
UserFunctionTemplate4perl("# @category Producing a new polyhedron from others"
                          "# Construct a new polyhedron or cone as the intersection of given polyhedra and/or cones."
                          "# Works only if all [[AMBIENT_DIM]] values are equal."
                          "# If the input contains both cones and polytopes, the output will be a polytope."
                          "# (In this case the condition on [[AMBIENT_DIM]] means that the [[CONE_AMBIENT_DIM]]"
                          "# of the cones has to match the [[POLYTOPE_AMBIENT_DIM]] of the polytopes.)"
                          "# @param Cone C ... polyhedra and cones to be intersected"
                          "# @return Cone",
                          "intersection<Scalar>(Cone<Scalar> +)");
} }

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