#include "CommandlineOptions.hh"
#include "ComputeTriangs.hh"
#include "PointConfiguration.hh"
#include "Symmetry.hh"
#include "Chirotope.hh"
#include "mptopcom_typedefs.hh"
#include "SymmetryBlackBox.hh"
#include "helpers.hh"

int main(const int argc, const char** argv) {
   CommandlineOptions::init(argc, argv);
   
   PointConfiguration points;
   if(!points.read(std::cin)){
      std::cerr << "Error while reading point configuration." << std::endl;
      return 1;
   }
   
   SymmetryGroup group(points.no());
   if(!group.read(std::cin)){
      std::cerr << "Error while reading symmetry group." << std::endl;
      return 1;
   }
   
   SimplicialComplex seed;
   if(!seed.read(std::cin)){
      std::cerr << "No triangulation provided." << std::endl;
      return 1;
   }
   
   gkz_type gkz(points);
   TriangNode t(0, points.no(), points.rank(), seed), result;
   gkz_vector_type result_gkz(gkz.evaluate(t));
   GroupDecomposer gd(group, gkz);
   Symmetry perm(array2symmetry(gd.get_identity()));
   
   bool sg = CommandlineOptions::small_group();
   
   if(sg) {
      // If the group is small, it is cheaper to just iterate over all
      // of it.
      result = t;
      TriangNode tmp;
      gkz_vector_type tmp_gkz;
      triang_vector_type result_tvec(gkz.triangulationAsVector(t)), tmp_tvec;
      for(SymmetryGroup::const_iterator sym_iter = group.begin();
                  sym_iter != group.end();
                  ++sym_iter){
         Symmetry g(*sym_iter);
         tmp = g(t);
         tmp_gkz = gkz.evaluate(tmp);
         int comp = lex_compare(tmp_gkz, result_gkz);
         if(comp == 1){
            result = tmp;
            result_gkz = tmp_gkz;
            result_tvec = gkz.triangulationAsVector(tmp);
            perm = Symmetry(g);
         } else if (comp == 0){
            tmp_tvec = gkz.triangulationAsVector(tmp);
            if(result_tvec > tmp_tvec){
               result = tmp;
               result_gkz = tmp_gkz;
               result_tvec = tmp_tvec;
               perm = Symmetry(g);
            }
         }
      }
   } else {
      TriangulationOptimizer td(t, gkz.evaluate(t), gd, gkz);
      result = td.get_optimal();
      result_gkz = td.get_optimal_gkz();
      perm = td.get_permutation();
   }


   std::cout << result;
   std::cout << " - gkz: " << pmVector2string(result_gkz);
   std::cout << " - perm: " << perm;
   std::cout << std::endl;
   
   return 0;
}
