/* Copyright (c) 2018
   Charles Jordan (Hokkaido University, Sapporo, Japan),
   Michael Joswig, Lars Kastner (Technische Universitaet Berlin, Germany)

   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 3, 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/Integer.h>
#include "helpers.hh"
#include <string>

template<>
std::string scalar2string<int>(const int i){
   return std::to_string(i);
}

template<>
std::string scalar2string<pm::Integer>(const pm::Integer i){
   char * tmp;
   tmp = mpz_get_str(NULL, 10, i.get_rep());
   std::string result(tmp);
   void (*freefunc)(void *, size_t);
   mp_get_memory_functions (NULL, NULL, &freefunc);
   freefunc(tmp, strlen(tmp) + 1);
   return result;
}

// Determine the support of a triangulation, i.e. which vertices it uses.
pm::Set<int> support(const TriangNode& t){
   pm::Set<int> result;
   for(TriangNode::const_iterator triangle = t.begin();
         triangle != t.end();
         ++triangle){
      for(basis_type::const_iterator entry = (*triangle).begin();
            entry != (*triangle).end();
            ++entry){
         result += *entry;
      }
   }
   return result;
}

// Method for determining whether a triangulation is fine, i.e. uses all
// lattice points.
bool isFine(const TriangNode& t){
   int n = t.no();
   pm::Set<int> s=support(t);
   // std::cout << "N: " << n << " s: " << s.size() << " t: " << t << std::endl;
   return n == s.size();
}

// Compute inverse permutation
Symmetry inverse(const Symmetry& g){
   // FIXME
   // Is this right? Can it be done better?
   Symmetry result(g);
   // std::cout << "Maxindex: " << g.maxindex() << std::endl;
   for(int i=0; i<g.maxindex(); i++){
      result[g[i]] = i;
   }
   return result;
}

// Check whether the signature 'sig1' refines the signature 'sig2', i.e. for
// every set of 'sig1' there is a set in 'sig2' containing it.
bool refines(const signature_vector_type& sig1, const signature_vector_type& sig2){
   for(int i=0; i<sig1.dim(); i++){
      if(sig2[i] != sig2[sig1[i]]){
         return false;
      }
   }
   return true;
}

// Get signature of a permutation, i.e. point orbits.
const signature_vector_type signature(const Symmetry& g) {
   signature_vector_type result(g.n());
   pm::Set<int> all(pm::range<int>(0,g.n()-1));
   while(all.size() > 0){
      int current = all.front();
      all -= current;
      result[current] = current;
      int next = g[current];
      while(next != current){
         result[next] = current;
         all -= next;
         next = g[next];
      }
   }
   return result;
}
