#ifndef __POLYNOMIAL_H__
#define __POLYNOMIAL_H__
#include <synaps/upol.h>
#include <synaps/upol/gcd.h>
#include <synaps/usolve/Algebraic.h>
#include <synaps/usolve/algebraic/sign_fct.h>
#include <synaps/usolve/bezier/SlvBzStd.h>
//#include <synaps/usolve/Sturm.h>
//#include <synaps/arithm/Infinity.h>
#include <stack>
#include "rational-function.h"
template<class T> class SynapsTraits;
template<class T>
class UPolynomial
{
	public:
		typedef						typename SynapsTraits<T>::Polynomial				Polynomial;
		typedef						RationalFunction<Polynomial>						RationalFunction;
		typedef						typename SynapsTraits<T>::Solver					Solver;
		typedef						typename SynapsTraits<T>::RootType					RootType;
		typedef						std::stack<RootType>								RootStack;
		static void					solve(const RationalFunction& rf, RootStack& stack);
		static RootType				root(const T& r)									{ return SynapsTraits<T>::root(r); }
		static int					sign_at(const RationalFunction& rf, const RootType& r);
		static RootType				between(const RootType& r1, const RootType& r2)		{ return SynapsTraits<T>::between(r1,r2); }
};
template<class T>
struct SynapsTraits				///< Suitable for double
{
		typedef						T													CoefficientType;
		typedef						SYNAPS::UPolDse<CoefficientType>					Polynomial;
		typedef						SYNAPS::SlvBzStd<CoefficientType>					Solver;
		typedef						T													RootType;
		static RootType				root(CoefficientType r)								{ return r; }
		static unsigned int			multiplicity(RootType r)							{ return 1; }
		static int					sign_at(const Polynomial& p, RootType r)			{ return SYNAPS::UPOLDAR::sign_at(p, r); }
		static RootType				between(RootType r1, RootType r2)					{ return (r1 + r2)/2; }
};
template<>
struct SynapsTraits<ZZ>
{
		typedef						ZZ													CoefficientType;
		typedef						SYNAPS::UPolDse<CoefficientType>					Polynomial;
		typedef						SYNAPS::Algebraic<CoefficientType>					Solver;
		typedef						Solver::root_t										RootType;
		static RootType				root(const CoefficientType& r)						{ CoefficientType p[2] = {-r, 1}; return SYNAPS::solve(Polynomial(2, p), Solver(), 0);}
		static unsigned int			multiplicity(const RootType& r)						{ return r.multiplicity(); }
		static int					sign_at(const Polynomial& p, 
											const RootType& r)							{ return SYNAPS::ALGEBRAIC::sign_at(p, r); }
		//static RootType				between(const RootType& r1, const RootType& r2) 	{ RootType r = r1; r += r2; r /= root(2); return r; }
};
#include "polynomial.hpp"
#endif