#ifndef POLYNOMIAL_H_INCLUDED
#define POLYNOMIAL_H_INCLUDED

class Polynomial;
class PolynomialSet;
//class PolynomialSetList;

#include <map>
#include "term.h"
#include "termorder.h"

struct TermMapCompare
{
  inline bool operator()(const Monomial &s1, const Monomial &s2) const
  {
    return LexicographicTermOrder()(s1.exponent,s2.exponent);
  }
};

typedef map<Monomial,FieldElement,TermMapCompare> TermMap;

class Polynomial
{
  Term marked;
  int sugar;
 public:
  TermMap terms;
  Polynomial(const Term &t);
  Polynomial();
  void computeInitialSugar();
  int getSugar()const;
  void madd(const Term &m, const Polynomial &p);
  void operator+=(const Polynomial &p);
  void operator-=(const Polynomial &p);
  friend Polynomial operator+(const Polynomial &p, const Polynomial &q);
  friend Polynomial operator-(const Polynomial &p, const Polynomial &q);
  void operator*=(const Term &p);
  void operator*=(const Monomial &m);
  void operator*=(FieldElement const &c);
  friend Polynomial operator*(const Polynomial &p, Term const &t);
  friend Polynomial operator*(const Polynomial &p, Monomial const &m);
  friend Polynomial operator*(const Polynomial &p, FieldElement const &c);
  int getNumberOfVariables()const;
  void changeNumberOfVariables(int n);
  void mark(class TermOrder const &termOrder);
  void mark(Monomial const &monomial);
  void scaleMarkedCoefficientToOne();
  bool isMonomial() const;
  const Term &getMarked()const{return marked;}
  bool isZero()const;
  int numberOfTerms()const;//linear time in worst case!
  IntegerVector exponentsSum()const;
  int totalDegree()const;
  int64 degree(IntegerVector const &w)const;
  Polynomial homogenization(int variable=-1, int degree=-1, IntegerVector const *w=0)const;
  Polynomial deHomogenization()const;
  int numberOfVariablesInRing()const;//by looking at just one monomial
  bool checkMarking(TermOrder const &termOrder)const;
  void saturate(int variableNum=-1);//default is to saturate with respect to all variables
  bool isMarked()const;
  bool isValid(int numberOfVarialbes=-1)const; //debug testing
};


class PolynomialCompare
{
 public:
  bool operator()(const Polynomial &a, const Polynomial &b)const;
};


class PolynomialCompareMarkedTerms
{
  TermOrder const &termOrder;
 public:
  PolynomialCompareMarkedTerms(TermOrder const &termOrder_);
  bool operator()(const Polynomial &a, const Polynomial &b)const;
};


class PolynomialCompareMarkedTermsReverse
{
  TermOrder const &termOrder;
 public:
  PolynomialCompareMarkedTermsReverse(TermOrder const &termOrder_);
  bool operator()(const Polynomial &a, const Polynomial &b)const;
};


class PolynomialSet : public list<Polynomial>
{
 public:
  void changeNumberOfVariables(int n=-1);
  int numberOfVariablesInRing()const;//by looking at just one monomial
  void scaleMarkedCoefficientsToOne();
  void markAndScale(TermOrder const &termOrder);
  bool checkMarkings(TermOrder const &termOrder)const;
  void unionPolynomial(const Polynomial &p);
  void unionSet(const PolynomialSet &s);
  int totalDegree()const;
  IntegerVector exponentsSum()const;
  void sort_();
  friend bool operator==(PolynomialSet const &a, PolynomialSet const &b); //remember to call sort_ before calling this procedure
  PolynomialSet markedTermIdeal()const;
  void computeInitialSugar();
  bool isMarked()const;
  PolynomialSet deHomogenization()const;
  bool isValid()const; //debug testing
};

typedef list<PolynomialSet> PolynomialSetList;
/*class PolynomialSetList : public list<PolynomialSet>
{
};*/

#endif
