#include "vektor.h"
#include "printer.h"
#include "parser.h"
#include "gfanapplication.h"
#include "minkowskisum.h"
#include "newtonpolytope.h"
#include "buchberger.h"
#include "wallideal.h"
#include "lp.h"
#include "tropical.h"
#include "division.h"
#include "bergman.h"
#include "tropical2.h"
#include "dimension.h"
#include "timer.h"

class TropicalApplication : public GFanApplication
{
  FieldOption theFieldOption;
  SimpleOption optionMultipleSets;
  SimpleOption optionRay;
  SimpleOption optionTraverse;
  SimpleOption optionPerformanceTimer;
  SimpleOption optionSymmetry;
  SimpleOption optionGuess;
  SimpleOption optionIncidencePrinting;
  SimpleOption optionInitialIdealPrinting;
public:
  bool includeInDefaultInstallation()
  {
    return false;
  }
  const char *helpText()
  {
    return "topical.\n";
  }
  TropicalApplication():
    optionPerformanceTimer("-T","Enable performance timer"),
    optionMultipleSets("-m","undocumented"),
    optionRay("--ray","undocumented"),
    optionGuess("--guess","undocumented"),
    optionTraverse("--traverse","undocumented"),
    optionSymmetry("--symmetry","undocumented"),
    optionIncidencePrinting("--incidence","Print incidence information. This will also extract the full fan from its orbits!"),
    optionInitialIdealPrinting("--initialideals","Print the initial ideals during incidence printing ONLY with --incidence")
  {
    registerOptions();
  }
  char *name()
  {
    return "_tropical";
  }
  int main()
  {
    PolynomialSetList tropical;

    lpSetSolver("cddgmp");
    FileParser P(Stdin);

    if(optionGuess.getValue())
      {
	PolynomialSet g=P.parsePolynomialSet();
	buchberger(&g,StandardGradedLexicographicTermOrder());


	PolynomialSet fullBasis;
	PolynomialSet g2=guessInitialIdealWithoutMonomial(g,&fullBasis,false);

	AsciiPrinter(Stdout).printPolynomialSet(g2);
	AsciiPrinter(Stdout).printPolynomialSet(fullBasis);

	

	fprintf(Stderr,"Input:  Krull dimension %i Dimension of homogeneity space %i\n",krullDimension(g),dimensionOfHomogeneitySpace(g));
	fprintf(Stderr,"Output: Krull dimension %i Dimension of homogeneity space %i\n",krullDimension(g2),dimensionOfHomogeneitySpace(g2));


	return 0;
      }


    if(optionRay.getValue())
      {
	AsciiPrinter p(Stdout);
	bergmanRay(P.parsePolynomialSet()).print(p);

	return 0;
      }

    if(optionTraverse.getValue())
      {
	AsciiPrinter p(Stdout);
	PolynomialSet coneGroebnerBasis=P.parsePolynomialSet();
	PolynomialSet idealGroebnerBasis=P.parsePolynomialSet();
	coneGroebnerBasis.changeNumberOfVariables(idealGroebnerBasis.numberOfVariablesInRing());

	SymmetryGroup s(idealGroebnerBasis.numberOfVariablesInRing());
	if(optionSymmetry.getValue())
	  {
	    IntegerVectorList generators=P.parseIntegerVectorList();
	    for(IntegerVectorList::iterator i=generators.begin();i!=generators.end();i++)
	      {
		assert(areIdealsEqual(idealGroebnerBasis,SymmetryGroup::permutePolynomialSet(idealGroebnerBasis,*i)));
	      }
	    
	    s.computeClosure(generators);
	    s.print(Stderr);
	  }

	BergmanFan f=bergman(coneGroebnerBasis,idealGroebnerBasis,&s);
	f.print(p);

	if(optionIncidencePrinting.getValue())
	  {
	    PolyhedralFan p1=f.toPolyhedralFan();
	    
	    p1.removeAllLowerDimensional();
	    
	    AsciiPrinter Q(Stdout);
	    
	    p1.printWithIndices(&Q,&s);
	  }
	if(optionInitialIdealPrinting.getValue())
	  {
	    //	    AsciiPrinter p(Stderr);
	    PolyhedralFan p1=f.toPolyhedralFan();
	    int n=p1.getAmbientDimension();
	    IncidenceList a=p1.getIncidenceList(&s);
	    IntegerVectorList rays=p1.getRaysInPrintingOrder(&s);
	    p.printString("Rays:\n");
	    p.printVectorList(rays);
	    vector<IntegerVector> rays2(rays.size());
	    int K=0;
	    for(IntegerVectorList::const_iterator k=rays.begin();k!=rays.end();k++)
	      rays2[K++]=*k;

	    for(IncidenceList::const_iterator j=a.begin();j!=a.end();j++)
	      {
		p.printInteger(j->first);
		for(IntegerVectorList::const_iterator i=j->second.begin();i!=j->second.end();i++)
		  {
		    p.printVector(*i);
		    IntegerVector v(n);
		    for(int t=0;t<i->size();t++)
		      {
			v+=rays2[(*i)[t]];
		      }
		    p.printVector(v);
		    PolynomialSet g2=idealGroebnerBasis;
		    buchberger(&g2,WeightReverseLexicographicTermOrder(v));
		    g2=initialForms(g2,v);
		    g2=saturatedIdeal(g2);
		    p.printPolynomialSet(g2);
		    
		  }
	      }
	  }



	if(optionPerformanceTimer.getValue())Timer::printList();
	return 0;
      }

    PolynomialSetList input;

    if(optionMultipleSets.getValue())
      input=P.parsePolynomialSetList();
    else
      input.push_back(P.parsePolynomialSet());

    for(PolynomialSetList::const_iterator g=input.begin();g!=input.end();g++)
      {

	PolynomialSetList s=fullColoredIdeals(*g,false);
	
	static int num;
	fprintf(Stderr,"Monomial Intial Ideal num: %i\n",num++);

	//  AsciiPrinter(Stdout).printPolynomialSetList(s);
	
	//  fprintf(Stdout,"contains no monomials:\n");
	for(PolynomialSetList::const_iterator i=s.begin();i!=s.end();i++)
	  {
	    fprintf(Stderr,"Testing ideal:\n");
	    AsciiPrinter(Stderr).printPolynomialSet(*i);
	    if(!containsMonomial(*i))
	      {		
		//  AsciiPrinter(Stdout).printPolynomialSet(*i);
		
		PolynomialSet g=*i;
		
		buchberger(&g,StandardGradedLexicographicTermOrder());
		
		bool inList=false;
		for(PolynomialSetList::const_iterator j=tropical.begin();j!=tropical.end();j++)
		  {
		    if(areIdealsEqual(*j,g))
		      {
			inList=true;
			break;
		      }
		  }
		if(!inList)tropical.push_back(g);
	      }
	  }
      }
    fprintf(Stderr,"No duplicates:\n");
    AsciiPrinter(Stdout).printPolynomialSetList(tropical);


    for(PolynomialSetList::const_iterator i=tropical.begin();i!=tropical.end();i++)
      {
	int coDim=rankOfMatrix(wallInequalities(*i));
	int d=i->numberOfVariablesInRing()-coDim;
	if(d<0)
	  {
	    fprintf(Stderr,"Error computing dimension of cone:");
	    AsciiPrinter(Stderr).printPolynomialSet(*i);
	    AsciiPrinter(Stderr).printVectorList(wallInequalities(*i));
	    fprintf(Stderr,"coDim= %i, numberOfVariables= %i\n",coDim,i->numberOfVariablesInRing());
	  }
	fprintf(Stderr,"%i\n",d);
      }

    return 0;
  }
};

static TropicalApplication theApplication;
