#include <iostream>
#include "parser.h"
#include "printer.h"
#include "polynomial.h"
#include "buchberger.h"
#include "reversesearch.h"
#include "termorder.h"
#include "genericwalk.h"
#include "gfanapplication.h"
#include "timer.h"
#include "tropical2.h"
#include "log.h"
#include "field_rationals.h"
#include "saturation.h"

class CandidatesForTropicalBasisApplication : public GFanApplication
{
  IntegerOption optionNumberOfParameters;
  SimpleOption optionDropFirstEntry;
  SimpleOption optionMinX;
public:
  bool includeInDefaultInstallation()
  {
    return false;
  }
  const char *helpText()
  {
    return "This program takes a list of polynomials and a list of weight vectors. The output is the set of \n";
  }
  CandidatesForTropicalBasisApplication():
    optionNumberOfParameters("--nparams","Specify number of variables to regard as parameters.\n"),
	optionDropFirstEntry("--drop","Ignore first column of the matrix of weight vectors."),
	optionMinX("--minx","Switch to min-convention.")
  {
    registerOptions();
  }

  const char *name()
  {
    return "_candidatesfortropicalbasis";
  }

  bool doesPolyExclude(Polynomial const &p, IntegerVector const &w)
  {
	  Polynomial g=initialForm(p,w);

	  if(g.isZero())return false;
	  g.saturate();
	  if(g.numberOfVariablesInUseConsecutive()<=optionNumberOfParameters.getValue())
		  return true;
	  return false;
  }

  int main()
  {
    PolynomialSet g=FileParser(Stdin).parsePolynomialSetWithRing();
    IntegerVectorList wlist=FileParser(Stdin).parseIntegerVectorList();


    PolynomialSet out(g.getRing());

    for(auto w:wlist)
    {
    	if(optionMinX.getValue())
    		w=-w;

        if(optionDropFirstEntry.getValue())
        	w=w.withIthCoordinateRemoved(0);

        w=concatenation(IntegerVector(g.numberOfVariablesInRing()-w.size()),w);

        WeightTermOrder T(w);

		g.markAndScale(T);

static		int skip=30;
		skip--;
		if(1)
		{
			if(skip<0)
			{
			pout<<w<<"\n";
			//w=w.subvector(6,w.size());/!!!

			PolynomialSet a=initialForms(g,w);
			//AsciiPrinter(stdout)<<a<<"\n";
			pout<<"ContainsMonomialGenerator:"<<a.containsMonomialGenerator();
			auto s=nonHomogeneousSaturation(a);
			AsciiPrinter(stdout)<<s<<"\n";
			}
		}
		else
		{

		bool alreadyExcluded=false;
		for(auto &f:out)
			if(doesPolyExclude(f,w))
			{
				alreadyExcluded=true;
				break;
			}

		if(!alreadyExcluded)
		{
			PolynomialSet potentialCandidates=g;
			int I=0;
			for(PolynomialSet::const_iterator i=g.begin();i!=g.end();i++,I++)
			{
				int J=0;
				for(PolynomialSet::const_iterator j=g.begin();j!=i;j++,J++)
				{
					Polynomial s=sPolynomial(*i,*j);
					if(!s.isZero())
						potentialCandidates.push_back(s);
				}
			}
			int termsInCandidate=0;
			Polynomial candidate(g.getRing().zero());
			for(auto &h:potentialCandidates)
				if(doesPolyExclude(h,w))
				{
					if(termsInCandidate==0 || initialForm(h,w).numberOfTerms()<termsInCandidate)
					{
						candidate=h;
						termsInCandidate=candidate.numberOfTerms();
					}
				}
			if(!candidate.isZero())
				out.push_back(candidate);
			else
				debug<<"No excluding polynomial found for vector\n"<<w<<"\n";
		}
		}
    }
    AsciiPrinter(Stdout).printPolynomialRing(out.getRing());
    AsciiPrinter(Stdout).printPolynomialSet(out);

    return 0;
  }
};

static CandidatesForTropicalBasisApplication theApplication;

