#include <iostream>
#include <ctype.h>
#include <assert.h>
#include <set>
#include <unordered_map>

#include "Global.hh"
#include "Field.hh"
#include "Symmetry.hh"
#include "PointConfiguration.hh"
#include "Permutation.hh"
#include "IntegerSet.hh"

int main(const int argc, const char** argv) {
  using namespace topcom;

  if (argc < 2) {
    MessageStreams::forced() << "usage: " << argv[0] << " <dimension>" << std::endl;
    return 1;
  }

  size_type no = atol(argv[1]);
  
  Permutation sorted(Permutation(no + 1, 1).complement());
  Vector seed(sorted);
  PointConfiguration Permutahedron;
  Permutahedron.augment(seed);

  // generate S_n:
  // travers through all two cycles to generate the entire symmetric group on rows:
  symmetry_collectordata rowperms;
  Permutation perm(no, 2);
  do {
    rowperms.insert(Symmetry(perm, true));
  } while (perm.lexnext());
  SymmetryGroup rowsyms(no, rowperms, true);

  // sort symmetries in order to obtain a reproducible result:
  std::set<Symmetry> sorted_symmetries;
  std::copy(rowsyms.begin(), rowsyms.end(), std::inserter<std::set<Symmetry> >(sorted_symmetries, sorted_symmetries.begin()));

  // generate points from all S_n permutations:
  for (std::set<Symmetry>::const_iterator symiter = sorted_symmetries.begin();
       symiter != sorted_symmetries.end();
       ++symiter) {
    Permutahedron.augment(symiter->inverse().map(seed)); //
  }

  // symmetries are induced by symmetries on rows:
  symmetry_collectordata rowperm_generators(rowsyms.rowperm_symmetry_generators(Permutahedron));
  SymmetryGroup symmetries(Permutahedron.no(), rowperm_generators);

  // as an example, generate the cyclic subgroup of S_n:
  Permutation full_cycle(no, no);
  symmetry_collectordata required_rowperms;
  required_rowperms.insert(Symmetry(full_cycle, true));
  SymmetryGroup required_rowsyms(no, required_rowperms, true);
  symmetry_collectordata required_rowperm_generators(required_rowsyms.rowperm_symmetry_generators(Permutahedron));
  SymmetryGroup required_symmetries(Permutahedron.no(), required_rowperm_generators);
  
  // print points:
  MessageStreams::result() << Permutahedron << std::endl;
  
  // print symmetry generators for S_n sorted in order to
  // obtain a reproducable output:
  symmetries.write_sorted_generators(MessageStreams::result());
  MessageStreams::result() << std::endl;

  // print an example for required symmetries sorted:
  required_symmetries.write_sorted_generators(MessageStreams::result());
  MessageStreams::result() << std::endl;
  return 0;
}

// eof permutahedron.cc
