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

#include "Field.hh"
#include "Vector.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;
  }
  parameter_type dim(atol(argv[1]));

  PointConfiguration rootpoly;
  for (parameter_type i = 0; i < dim; ++i) {
    for (parameter_type j = i + 1; j < dim; ++j) {
      Vector pos_col(dim);
      pos_col[i] = FieldConstants::ONE;
      pos_col[j] = FieldConstants::MINUSONE;
      rootpoly.augment(pos_col);
      Vector neg_col(dim);
      neg_col[i] = FieldConstants::MINUSONE;
      neg_col[j] = FieldConstants::ONE;
      rootpoly.augment(neg_col);
    }
  }
  rootpoly.homogenize();

  MessageStreams::result() << rootpoly << std::endl;

  symmetry_collectordata rowperms;

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

  Symmetry reflection(rootpoly.no());
  for (parameter_type i = 0; i < reflection.n() / 2; ++i) {
    reflection.at(2 * i) = 2 * i + 1;
    reflection.at(2 * i + 1) = 2 * i;
  }

  symmetry_generators.insert(reflection);
  SymmetryGroup symmetries(rootpoly.no(), symmetry_generators, false);

  // print symmetry generators sorted in order to
  // obtain a reproducable output:
  symmetries.write_sorted_generators(MessageStreams::result());
  MessageStreams::result() << std::endl;

  // print empty complex as a dummy seed triangulation:
  MessageStreams::result() << SimplicialComplex() << std::endl;

  // generate required symmetries containing the reflection:
  SymmetryGroup required_symmetries(rootpoly.no());
  required_symmetries.extend(reflection);

  // print symmetry generators sorted in order to
  // obtain a reproducable output:
  required_symmetries.write_sorted_generators(MessageStreams::result());
  MessageStreams::result() << std::endl;
  return 0;
}

// eof rootpoly.cc
