/* Copyright (c) 1997-2018
	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/Vector.h"
#include "polymake/Matrix.h"
#include "polymake/Rational.h"
#include "polymake/Map.h"
#include "polymake/Array.h"
#include "polymake/Set.h"
#include "polymake/IncidenceMatrix.h"

namespace polymake { namespace tropical {

   Array<Rational> cycle_edge_lengths(perl::Object cycle) {
      const Matrix<Rational>& vertices = cycle.give("VERTICES");
      const Set<int>& far_vertices = cycle.give("FAR_VERTICES");
      const Map< std::pair<int,int>, Vector<Integer> >& lattice_normals = cycle.give("LATTICE_NORMALS");
      const IncidenceMatrix<>& maximal_polytopes = cycle.give("MAXIMAL_POLYTOPES");
      const IncidenceMatrix<>& codim_one_incidence = cycle.give("MAXIMAL_AT_CODIM_ONE");
      const auto& maximal_incidence = T(codim_one_incidence);

      Array<Rational> result( maximal_polytopes.rows() );
      auto result_it = entire(result);
      auto incidence_it = entire(rows(maximal_incidence));
      int mp_index = 0;
      for(auto mp = entire(rows(maximal_polytopes)); !mp.at_end(); 
            ++mp, ++mp_index, ++result_it, ++incidence_it) {
         if( ! ((*mp) * far_vertices).empty()) {
            *result_it = std::numeric_limits<Rational>::infinity(); continue;
         }
         const int adj_codim = *(incidence_it->begin());
         Vector<Integer> lnormal = lattice_normals[ std::make_pair(adj_codim, mp_index)];
         const Matrix<Rational> ends = vertices.minor( *mp, All);
         const Vector<Rational> diff = ends.row(0) - ends.row(1);
         auto lnormal_it = entire(lnormal);
         for(auto diff_it = entire(diff); !diff_it.at_end(); ++diff_it, ++lnormal_it) {
            if(*diff_it != 0) {
               *result_it = abs(*diff_it / *lnormal_it); break;
            }
         }
      }
      return result;
   }

   Function4perl(&cycle_edge_lengths, "cycle_edge_lengths(Cycle)");

}}
