#include "vektor.h"
#include "printer.h"
#include "parser.h"
#include "gfanapplication.h"
#include "log.h"
#include "linalg.h"
#include "symmetrictraversal.h"
#include "traverser_stableintersection.h"


class ActApplication : public GFanApplication
{
//  SimpleOption optionOrbit;
  IntegerOption optionShift;
  SimpleOption optionVector;
  SimpleOption optionVectorList;
  SimpleOption optionPolynomialsInSet;
public:
  bool includeInDefaultInstallation()
  {
    return false;
  }
  const char *helpText()
  {
    return "This program takes in permutation and lets it act on an object.\n";
  }
  ActApplication():
//    optionOrbit("--orbit","Computes the orbit of the object. In this case the input are generators for a permutation group."),
	optionShift("--shift","Sometimes the object has more coordinates than the permutation. In that case the number of object coordinates to be ignored can be specified with this option."),
	optionVector("--vectorobject","Select object type to be a vector."),
	optionVectorList("--vectorlistobject",""),
	optionPolynomialsInSet("--polynomialsinset","Takes a polynomial ring and a set of polynomials. Acts on each polynomial and outputs the set of all obtained polynomials and a ring.")
	{
    registerOptions();
	}
  const char *name()
  {
    return "_act";
  }
  int main()
  {
	  /*
	   * {
(0,5,6,7,8,1,2,3,4,9,10,11,12,13,14),
(5,6,7,8,0,9,10,11,1,12,13,2,14,3,4)}
(12,13,14,15,16,23,24,25,26,34,35,36,45,46,56)
	   */
	  FileParser P(Stdin);
	  IntegerVectorList generators=P.parseIntegerVectorList();
	  assert(generators.size());
	  int n=generators.front().size();
	  SymmetryGroup s(n);
	  s.computeClosure(generators);
	  s.createTrie();
	  log1 cerr<<"TRIE size:"<<s.elements.size()<<"\n";

	  if(optionVector.getValue())
	  {
		  IntegerVector v=P.parseIntegerVector();
		  IntegerVectorList r;
	  	  for(auto &sigma:s.elements)
	  	  {
	  		  r.push_back(SymmetryGroup::compose(sigma,v));
	  	  }
	  	  pout<<r;
	  }
	else
		  if(optionVectorList.getValue())
		  {
			  auto L=P.parseIntegerVectorList();
			  IntegerVectorList r;
		  	  for(auto &sigma:s.elements)
		  	  {
		  		  for(auto &v:L)
		  			  r.push_back(SymmetryGroup::compose(sigma,v));
		  	  }
		  	  pout<<r;
		  }
		else
			if(optionPolynomialsInSet.getValue())
			{
				PolynomialSet A=P.parsePolynomialSetWithRing();
				assert(A.size());
				PolynomialSet B(A.getRing());
				for(auto &sigma:s.elements)
					{
					  auto C=SymmetryGroup::permutePolynomialSet(A,sigma);
					  for(auto &p:C)B.push_back(p);
					  B.removeDuplicates();
					}
				pout.printPolynomialRing(B.getRing());
				pout.printPolynomialSet(B);
			}
			else
	{
		cerr<<"No object type specified.";
		assert(0);
	}
    return 0;
  }
};

static ActApplication theApplication;
